diff options
author | kaloz <kaloz@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2010-07-21 11:20:53 +0000 |
---|---|---|
committer | kaloz <kaloz@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2010-07-21 11:20:53 +0000 |
commit | 642064ae9a94b47054ea7fb39804776ae11fbc4e (patch) | |
tree | ce5d36d1490a49f1a75c8b8aae051f7c1e077ac8 /target/linux/cns3xxx/patches-2.6.31/205-cns3xxx_net_device_support.patch | |
parent | 9b743eb09d74b1807a1101f8537c06f618835126 (diff) |
add support for the Gateworks Laguna family (Cavium Networks Econa CNS3xxx)
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@22323 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/cns3xxx/patches-2.6.31/205-cns3xxx_net_device_support.patch')
-rw-r--r-- | target/linux/cns3xxx/patches-2.6.31/205-cns3xxx_net_device_support.patch | 11802 |
1 files changed, 11802 insertions, 0 deletions
diff --git a/target/linux/cns3xxx/patches-2.6.31/205-cns3xxx_net_device_support.patch b/target/linux/cns3xxx/patches-2.6.31/205-cns3xxx_net_device_support.patch new file mode 100644 index 000000000..945edec6b --- /dev/null +++ b/target/linux/cns3xxx/patches-2.6.31/205-cns3xxx_net_device_support.patch @@ -0,0 +1,11802 @@ +--- /dev/null ++++ b/drivers/net/cns3xxx/cns3xxx_config.h +@@ -0,0 +1,136 @@ ++/******************************************************************************* ++ * ++ * Copyright (c) 2009 Cavium Networks ++ * ++ * 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. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ ********************************************************************************/ ++ ++#include <linux/version.h> ++ ++#ifndef CNS3XXX_CONFIG_H ++#define CNS3XXX_CONFIG_H ++ ++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,27) ++#define LINUX2627 1 ++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) ++#define LINUX2631 1 ++#endif ++ ++ ++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) ++#define CNS3XXX_VLAN_8021Q ++#endif ++ ++#ifdef CNS3XXX_VLAN_8021Q ++//#define CNS3XXX_NIC_MODE_8021Q // use NIC mode to support 8021Q ++ ++#endif ++ ++#define CONFIG_CNS3XXX_JUMBO_FRAME ++ ++#ifdef CONFIG_CNS3XXX_JUMBO_FRAME ++#define MAX_PACKET_LEN 9600 ++#else ++#define MAX_PACKET_LEN 1536 ++#endif ++ ++//#define CONFIG_SWITCH_BIG_ENDIAN ++ ++//#define CONFIG_FPGA_FORCE ++ ++//#define CNS3XXX_GIGA_MODE ++ ++#define CNS3XXX_SET_ARL_TABLE ++#define CNS3XXX_AGE_ENABLE ++#define CNS3XXX_LEARN_ENABLE ++#define CNS3XXX_CPU_PORT_FC ++#define CNS3XXX_CPU_MIB_COUNTER ++#define CNS3XXX_MAC0_MIB_COUNTER ++#define CNS3XXX_MAC1_MIB_COUNTER ++//#define CNS3XXX_MAC2_MIB_COUNTER ++//#define QOS_TEST ++//#define ACCEPT_CRC_BAD_PKT ++//#define CONFIG_FAST_BRIDGE ++//#define CONFIG_HOLP_TEST ++ ++ ++#define CONFIG_CNS3XXX_NAPI ++#ifdef CONFIG_CNS3XXX_NAPI ++#define CNS3XXX_NAPI_WEIGHT 64 ++#endif ++//#define CONFIG_NIC_MODE ++//#define CNS3XXX_TX_HW_CHECKSUM ++//#define CNS3XXX_RX_HW_CHECKSUM ++//#define CNS3XXX_STATUS_ISR ++//#define CNS3XXX_TEST_ONE_LEG_VLAN ++//#define CNS3XXX_TX_DSCP_PROC ++ ++ ++#define CNS3XXX_FSQF_RING0_ISR ++//#define CNS3XXX_TSTC_RING0_ISR ++//#define CNS3XXX_TSTC_RING1_ISR ++ ++//#define CNS3XXX_COMPARE_PACKET ++//#define CONFIG_FPGA_10 ++//#define CNS3XXX_CONFIG_SIM_MODE ++ ++#define CNS3XXX_8021Q_HW_TX ++ ++ ++#ifndef CONFIG_CNS3XXX_SPPE ++#define IVL // if no define, use SVL ++#endif ++//#define CNS3XXX_4N // if don't define it, use 4N+2 ++ ++//#define NCNB_TEST ++//#define CNS3XXX_TEST_D_CACHE ++#define CNS3XXX_FREE_TX_IN_RX_PATH ++ ++ ++//#define DEBUG_RX ++//#define DEBUG_TX ++//#define DEBUG_PRIO_IPDSCR ++#define DEBUG_RX_PROC ++#define DEBUG_TX_PROC ++//#define DEBUG_PHY_PROC ++#define CNS3XXX_PVID_PROC ++#define CNS3XXX_SARL_PROC ++ ++ ++//#define DOUBLE_RING_TEST ++ ++//#define CNS3XXX_DOUBLE_RX_RING ++//#define CNS3XXX_DOUBLE_TX_RING ++#define CNS3XXX_USE_MASK ++ ++#define CNS3XXX_CONFIG_CHANGE_TX_RING ++ ++#ifdef CNS3XXX_DOUBLE_RX_RING ++#define CNS3XXX_FSQF_RING1_ISR ++#endif ++ ++//#define CNS3XXX_DELAYED_INTERRUPT ++ ++#ifdef CNS3XXX_DELAYED_INTERRUPT ++#define MAX_PEND_INT_CNT 0x06 ++#define MAX_PEND_TIME 0x20 ++#endif ++ ++//#define CNS3XXX_ENABLE_RINT1 ++#endif +--- /dev/null ++++ b/drivers/net/cns3xxx/cns3xxx_ethtool.c +@@ -0,0 +1,436 @@ ++/******************************************************************************* ++ * ++ * ++ * Copyright (c) 2009 Cavium Networks ++ * ++ * 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. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ ********************************************************************************/ ++ ++//#include <linux/module.h> ++#include <linux/types.h> ++#include <linux/ethtool.h> ++#include <linux/netdevice.h> ++#include "cns3xxx_symbol.h" ++#include "cns3xxx.h" ++#include "cns3xxx_tool.h" ++ ++// ethtool support reference e100.c and e1000_ethtool.c . ++static void cns3xxx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) ++{ ++ strcpy(info->driver, "cns3xxx"); ++ strcpy(info->version, DRV_VERSION); ++ strcpy(info->fw_version, "N/A"); ++ strcpy(info->bus_info, "N/A"); ++} ++ ++static void cns3xxx_get_ringparam(struct net_device *netdev, ++ struct ethtool_ringparam *ring) ++{ ++ CNS3XXXPrivate *priv = netdev_priv(netdev); ++ ++ ring->rx_max_pending = priv->rx_ring->max_ring_size; ++ ring->tx_max_pending = priv->tx_ring->max_ring_size; ++ ring->rx_pending = priv->rx_ring->ring_size; ++ ring->tx_pending = priv->tx_ring->ring_size; ++#if 0 ++ struct nic *nic = netdev_priv(netdev); ++ struct param_range *rfds = &nic->params.rfds; ++ struct param_range *cbs = &nic->params.cbs; ++ ++ ring->rx_max_pending = rfds->max; ++ ring->tx_max_pending = cbs->max; ++ ring->rx_mini_max_pending = 0; ++ ring->rx_jumbo_max_pending = 0; ++ ring->rx_pending = rfds->count; ++ ring->tx_pending = cbs->count; ++ ring->rx_mini_pending = 0; ++ ring->rx_jumbo_pending = 0; ++#endif ++} ++ ++ ++ ++static int cns3xxx_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) ++{ ++ int cns3xxx_up(void); ++ int cns3xxx_down(void); ++ int cns3xxx_close(struct net_device *dev); ++ int cns3xxx_open(struct net_device *dev); ++ extern struct net_device *net_dev_array[]; ++ ++ CNS3XXXPrivate *priv = netdev_priv(netdev); ++ ++ int i=0; ++ ++#if 0 ++ struct nic *nic = netdev_priv(netdev); ++ struct param_range *rfds = &nic->params.rfds; ++ struct param_range *cbs = &nic->params.cbs; ++ ++ if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) ++ return -EINVAL; ++ ++ if(netif_running(netdev)) ++ e100_down(nic); ++ rfds->count = max(ring->rx_pending, rfds->min); ++ rfds->count = min(rfds->count, rfds->max); ++ cbs->count = max(ring->tx_pending, cbs->min); ++ cbs->count = min(cbs->count, cbs->max); ++ DPRINTK(DRV, INFO, "Ring Param settings: rx: %d, tx %d\n", ++ rfds->count, cbs->count); ++ if(netif_running(netdev)) ++ e100_up(nic); ++ ++#endif ++ //ring->rx_max_pending = RX_DESC_SIZE; ++ //ring->tx_max_pending = TX_DESC_SIZE; ++ ++#if 0 ++ printk("ring->rx_max_pending: %d\n", ring->rx_max_pending); ++ printk("ring->tx_max_pending: %d\n", ring->tx_max_pending); ++ printk("ring->rx_pending: %d\n", ring->rx_pending); ++ printk("ring->tx_pending: %d\n", ring->tx_pending); ++#endif ++ ++ for (i=0 ; i < NETDEV_SIZE ; ++i) { ++ if(net_dev_array[i] && netif_running(net_dev_array[i])) { ++ //printk("close net_dev_array[%d]: %s\n", i, net_dev_array[i]); ++ cns3xxx_close(net_dev_array[i]); ++ } ++ } ++ ++ //cns3xxx_down(); ++ ++ priv->rx_ring->ring_size = min(ring->rx_pending, priv->rx_ring->max_ring_size); ++ priv->tx_ring->ring_size = min(ring->rx_pending, priv->tx_ring->max_ring_size); ++ ++ for (i=0 ; i < NETDEV_SIZE ; ++i) { ++ if(net_dev_array[i] && netif_running(net_dev_array[i])) { ++ //printk("open net_dev_array[%d]: %s\n", i, net_dev_array[i]); ++ cns3xxx_open(net_dev_array[i]); ++ } ++ } ++ //cns3xxx_up(); ++ ++ return 0; ++} ++ ++static uint32_t cns3xxx_get_tx_csum(struct net_device *netdev) ++{ ++ //return (netdev->features & NETIF_F_HW_CSUM) != 0; ++ return (netdev->features & NETIF_F_IP_CSUM) != 0; ++} ++ ++static int cns3xxx_set_tx_csum(struct net_device *netdev, uint32_t data) ++{ ++ if (data) ++ netdev->features |= NETIF_F_IP_CSUM; ++ else ++ netdev->features &= ~NETIF_F_IP_CSUM; ++ return 0; ++} ++ ++static uint32_t cns3xxx_get_rx_csum(struct net_device *netdev) ++{ ++ //struct e1000_adapter *adapter = netdev_priv(netdev); ++ //return adapter->rx_csum; ++ return 1; ++} ++ ++static int cns3xxx_set_rx_csum(struct net_device *netdev, uint32_t data) ++{ ++ return 0; ++} ++ ++u32 cns3xxx_get_sg(struct net_device *dev) ++{ ++#ifdef NETIF_F_SG ++ return (dev->features & NETIF_F_SG) != 0; ++#else ++ return 0; ++#endif ++} ++ ++int cns3xxx_set_sg(struct net_device *dev, u32 data) ++{ ++#ifdef NETIF_F_SG ++ if (data) ++ dev->features |= NETIF_F_SG; ++ else ++ dev->features &= ~NETIF_F_SG; ++#endif ++ ++ return 0; ++} ++ ++static void cns3xxx_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) ++{ ++ u32 mac_port_config = 0; ++ CNS3XXXPrivate *priv = netdev_priv(netdev); ++ ++ switch (priv->net_device_priv->which_port) ++ { ++ case MAC_PORT0: ++ { ++ mac_port_config = MAC0_CFG_REG; ++ break; ++ } ++ case MAC_PORT1: ++ { ++ mac_port_config = MAC1_CFG_REG; ++ break; ++ } ++ case MAC_PORT2: ++ { ++ mac_port_config = MAC2_CFG_REG; ++ break; ++ } ++ } ++ ++ ++ pause->autoneg = ( ((mac_port_config >> 7) & 1) ? AUTONEG_ENABLE : AUTONEG_DISABLE); ++ pause->tx_pause = (mac_port_config >> 6) & 1; ++ pause->rx_pause = (mac_port_config >> 5) & 1; ++} ++ ++static int cns3xxx_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) ++{ ++ u32 mac_port_config = 0; ++ CNS3XXXPrivate *priv = netdev_priv(netdev); ++ ++ switch (priv->net_device_priv->which_port) ++ { ++ case MAC_PORT0: ++ { ++ mac_port_config = MAC0_CFG_REG; ++ break; ++ } ++ case MAC_PORT1: ++ { ++ mac_port_config = MAC1_CFG_REG; ++ break; ++ } ++ case MAC_PORT2: ++ { ++ mac_port_config = MAC2_CFG_REG; ++ break; ++ } ++ } ++ ++ ++ mac_port_config &= ~(0x1 << 7); // clean AN ++ mac_port_config &= ~(0x1 << 11); // clean rx flow control ++ mac_port_config &= ~(0x1 << 12); // clean tx flow control ++ ++ mac_port_config |= ( (pause->autoneg << 7) | (pause->rx_pause << 11) | (pause->tx_pause << 12) ); ++ ++ ++ switch (priv->net_device_priv->which_port) ++ { ++ case MAC_PORT0: ++ { ++ MAC0_CFG_REG = mac_port_config; ++ break; ++ } ++ case MAC_PORT1: ++ { ++ MAC1_CFG_REG = mac_port_config; ++ break; ++ } ++ case MAC_PORT2: ++ { ++ MAC2_CFG_REG = mac_port_config; ++ break; ++ } ++ } ++ return 0; ++} ++ ++u32 cns3xxx_get_link(struct net_device *netdev) ++{ ++ u32 mac_port_config = 0; ++ CNS3XXXPrivate *priv = netdev_priv(netdev); ++ ++ switch (priv->net_device_priv->which_port) ++ { ++ case MAC_PORT0: ++ { ++ mac_port_config = MAC0_CFG_REG; ++ break; ++ } ++ case MAC_PORT1: ++ { ++ mac_port_config = MAC1_CFG_REG; ++ break; ++ } ++ case MAC_PORT2: ++ { ++ mac_port_config = MAC2_CFG_REG; ++ break; ++ } ++ } ++ ++ return (mac_port_config & 1 ) ? 1 : 0; ++ //return netif_carrier_ok(dev) ? 1 : 0; ++} ++ ++ ++static int cns3xxx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ++{ ++ u8 value; ++ u32 mac_port_config = 0; ++ CNS3XXXPrivate *priv = netdev_priv(netdev); ++ ++ ++ if (priv->net_device_priv->nic_setting == 0) { // connect to switch chip ++ ++ GET_MAC_PORT_CFG(priv->net_device_priv->which_port, mac_port_config) ++ ++ ecmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full| SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_Pause); ++ ++ ecmd->duplex = ((mac_port_config >> 4) & 0x1) ? DUPLEX_FULL : DUPLEX_HALF ; ++ ++ value = ((mac_port_config >> 2) & 0x3); ++ switch (value) ++ { ++ case 0: ++ ecmd->speed = SPEED_10; ++ break; ++ case 1: ++ ecmd->speed = SPEED_100; ++ break; ++ case 2: ++ ecmd->speed = SPEED_1000; ++ break; ++ } ++ ++ ecmd->autoneg = ((mac_port_config >> 7) & 1) ? AUTONEG_ENABLE : AUTONEG_DISABLE; ++ ++ ++ ++ } else { // connect to PHY chip ++ ++ } ++ ++ return 0; ++} ++ ++// set speed and duplex ++int cns3xxx_set_spd_dplx(struct net_device *netdev, u16 spddplx) ++{ ++ u32 mac_port_config = 0; ++ CNS3XXXPrivate *priv = netdev_priv(netdev); ++ ++ GET_MAC_PORT_CFG(priv->net_device_priv->which_port, mac_port_config) ++ ++ //printk("mac_port_config: %x\n", mac_port_config); ++ ++ mac_port_config &= ~(0x3 << 8); // clear speed ++ mac_port_config &= ~(0x1 << 10); // clear duplex ++ mac_port_config &= ~(0x1 << 7); // disable AN ++ ++ switch (spddplx) { ++ case AUTONEG_ENABLE: ++ mac_port_config |= (0x1 << 7); // enable AN ++ break; ++ case SPEED_10 + DUPLEX_HALF: ++ printk("10, halt\n"); ++ mac_port_config |= (0 << 8); // set speed ++ mac_port_config |= (0 << 10); // set duplex ++ //printk("xxx mac_port_config: %x\n", mac_port_config); ++ break; ++ case SPEED_10 + DUPLEX_FULL: ++ mac_port_config |= (0 << 8); // set speed ++ mac_port_config |= (1 << 10); // set duplex ++ break; ++ case SPEED_100 + DUPLEX_HALF: ++ mac_port_config |= (1 << 8); // set speed ++ mac_port_config |= (0 << 10); // set duplex ++ break; ++ case SPEED_100 + DUPLEX_FULL: ++ mac_port_config |= (1 << 8); // set speed ++ mac_port_config |= (1 << 10); // set duplex ++ break; ++ case SPEED_1000 + DUPLEX_HALF: ++ mac_port_config |= (2 << 8); // set speed ++ mac_port_config |= (0 << 10); // set duplex ++ break; ++ case SPEED_1000 + DUPLEX_FULL: ++ mac_port_config |= (2 << 8); // set speed ++ mac_port_config |= (1 << 10); // set duplex ++ break; ++ default: ++ //printk("Unsupported Speed/Duplex configuration\n"); ++ return -EINVAL; ++ } ++ ++ SET_MAC_PORT_CFG(priv->net_device_priv->which_port, mac_port_config) ++ ++ return 0; ++} ++ ++static int cns3xxx_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ++{ ++ u8 value = 0; ++ CNS3XXXPrivate *priv = netdev_priv(netdev); ++ ++ if (priv->net_device_priv->nic_setting == 0) { // connect to switch chip ++ if (ecmd->autoneg == AUTONEG_ENABLE) { ++ printk("autoneg\n"); ++ if ((value=cns3xxx_set_spd_dplx(netdev, AUTONEG_ENABLE)) != 0) { ++ return -EINVAL; ++ } ++ } else { ++ printk("no autoneg\n"); ++ if ((value=cns3xxx_set_spd_dplx(netdev, ecmd->speed + ecmd->duplex)) != 0) { ++ return -EINVAL; ++ } ++ ++ ++ } ++ ++ } else { // connect to PHY chip ++ ++ } ++ ++ // down then up ++ return 0; ++} ++ ++static const struct ethtool_ops cns3xxx_ethtool_ops = { ++ .get_drvinfo = cns3xxx_get_drvinfo, ++ .get_ringparam = cns3xxx_get_ringparam, ++ .set_ringparam = cns3xxx_set_ringparam, ++ .get_rx_csum = cns3xxx_get_rx_csum, ++ .set_rx_csum = cns3xxx_set_rx_csum, ++ .get_tx_csum = cns3xxx_get_tx_csum, ++ .set_tx_csum = cns3xxx_set_tx_csum, ++ .get_sg = cns3xxx_get_sg, ++ .set_sg = cns3xxx_set_sg, ++ .get_pauseparam = cns3xxx_get_pauseparam, ++ .set_pauseparam = cns3xxx_set_pauseparam, ++ .get_link = cns3xxx_get_link, ++ .get_settings = cns3xxx_get_settings, ++ .set_settings = cns3xxx_set_settings, ++}; ++ ++void cns3xxx_set_ethtool_ops(struct net_device *netdev) ++{ ++ SET_ETHTOOL_OPS(netdev, &cns3xxx_ethtool_ops); ++} +--- /dev/null ++++ b/drivers/net/cns3xxx/cns3xxx.h +@@ -0,0 +1,452 @@ ++/******************************************************************************* ++ * ++ * Copyright (c) 2009 Cavium Networks ++ * ++ * 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. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ ********************************************************************************/ ++ ++#ifndef CNS3XXX_H ++#define CNS3XXX_H ++ ++#include "cns3xxx_symbol.h" ++#include "cns3xxx_config.h" ++#include <linux/cns3xxx/switch_api.h> ++ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/kernel.h> ++#include <linux/bootmem.h> ++#include <linux/sched.h> ++#include <linux/types.h> ++#include <linux/fcntl.h> ++#include <linux/interrupt.h> ++#include <linux/ptrace.h> ++#include <linux/ioport.h> ++#include <linux/in.h> ++#include <linux/slab.h> ++#include <linux/init.h> ++#include <linux/proc_fs.h> ++#include <linux/reboot.h> ++#include <asm/bitops.h> ++#include <asm/irq.h> ++#include <asm/io.h> ++//#include <asm/hardware.h> ++#include <linux/pci.h> ++#include <linux/errno.h> ++#include <linux/delay.h> ++#include <linux/netdevice.h> ++#include <linux/etherdevice.h> ++#include <linux/skbuff.h> ++#include <linux/ip.h> ++#include <linux/if_ether.h> ++#include <linux/icmp.h> ++#include <linux/udp.h> ++#include <linux/tcp.h> ++#include <linux/if_arp.h> ++#include <net/arp.h> ++ ++ ++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) ++#include <linux/if_vlan.h> ++#endif ++ ++//#define VERSION "1.0" ++ ++ ++typedef struct ++{ ++ int32_t sdp; // segment data pointer ++ ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++ u32 cown:1; ++ u32 eor:1; ++ u32 fsd:1; ++ u32 lsd:1; ++ u32 interrupt:1; ++ u32 fr:1; ++ u32 fp:1; // force priority ++ u32 pri:3; ++ u32 rsv_1:3; // reserve ++ u32 ico:1; ++ u32 uco:1; ++ u32 tco:1; ++ u32 sdl:16; // segment data length ++ ++#else ++ u32 sdl:16; // segment data length ++ u32 tco:1; ++ u32 uco:1; ++ u32 ico:1; ++ u32 rsv_1:3; // reserve ++ u32 pri:3; ++ u32 fp:1; // force priority ++ u32 fr:1; ++ u32 interrupt:1; ++ u32 lsd:1; ++ u32 fsd:1; ++ u32 eor:1; ++ u32 cown:1; ++#endif ++ ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++ u32 rsv_3:5; ++ u32 fewan:1; ++ u32 ewan:1; ++ u32 mark:3; ++ u32 pmap:5; ++ u32 rsv_2:9; ++ u32 dels:1; ++ u32 inss:1; ++ u32 sid:4; ++ u32 stv:1; ++ u32 ctv:1; ++#else ++ u32 ctv:1; ++ u32 stv:1; ++ u32 sid:4; ++ u32 inss:1; ++ u32 dels:1; ++ u32 rsv_2:9; ++ u32 pmap:5; ++ u32 mark:3; ++ u32 ewan:1; ++ u32 fewan:1; ++ u32 rsv_3:5; ++#endif ++ ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++ u32 s_pri:3; ++ u32 s_dei:1; ++ u32 s_vid:12; ++ u32 c_pri:3; ++ u32 c_cfs:1; ++ u32 c_vid:12; ++#else ++ u32 c_vid:12; ++ u32 c_cfs:1; ++ u32 c_pri:3; ++ u32 s_vid:12; ++ u32 s_dei:1; ++ u32 s_pri:3; ++#endif ++ ++ u8 alignment[16]; // for alignment 32 byte ++ ++} __attribute__((packed)) TXDesc; ++ ++typedef struct ++{ ++ u32 sdp; ++ ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++ u32 cown:1; ++ u32 eor:1; ++ u32 fsd:1; ++ u32 lsd:1; ++ u32 hr :6; ++ u32 prot:4; ++ u32 ipf:1; ++ u32 l4f:1; ++ u32 sdl:16; ++#else ++ u32 sdl:16; ++ u32 l4f:1; ++ u32 ipf:1; ++ u32 prot:4; ++ u32 hr :6; ++ u32 lsd:1; ++ u32 fsd:1; ++ u32 eor:1; ++ u32 cown:1; ++#endif ++ ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++ u32 rsv_3:11; ++ u32 ip_offset:5; ++ u32 rsv_2:1; ++ u32 tc:2; ++ u32 un_eth:1; ++ u32 crc_err:1; ++ u32 sp:3; ++ u32 rsv_1:2; ++ u32 e_wan:1; ++ u32 exdv:1; ++ u32 iwan:1; ++ u32 unv:1; ++ u32 stv:1; ++ u32 ctv:1; ++#else ++ u32 ctv:1; ++ u32 stv:1; ++ u32 unv:1; ++ u32 iwan:1; ++ u32 exdv:1; ++ u32 e_wan:1; ++ u32 rsv_1:2; ++ u32 sp:3; ++ u32 crc_err:1; ++ u32 un_eth:1; ++ u32 tc:2; ++ u32 rsv_2:1; ++ u32 ip_offset:5; ++ u32 rsv_3:11; ++#endif ++ ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++ u32 s_pri:3; ++ u32 s_dei:1; ++ u32 s_vid:12; ++ u32 c_pri:3; ++ u32 c_cfs:1; ++ u32 c_vid:12; ++#else ++ u32 c_vid:12; ++ u32 c_cfs:1; ++ u32 c_pri:3; ++ u32 s_vid:12; ++ u32 s_dei:1; ++ u32 s_pri:3; ++#endif ++ ++ u8 alignment[16]; // for alignment 32 byte ++ ++} __attribute__((packed)) RXDesc; ++ ++typedef struct { ++ TXDesc *tx_desc; ++ struct sk_buff *skb; // for free skb ++ u32 pri; ++ unsigned long j; ++ unsigned long tx_index; ++}TXBuffer; ++ ++typedef struct { ++ RXDesc *rx_desc; ++ struct sk_buff *skb; // rx path need to fill some skb field, ex: length ... ++#ifdef NCNB_TEST ++ u32 ncnb_index; ++#endif ++}RXBuffer; ++ ++ ++typedef struct { ++ TXBuffer *head; ++ TXDesc *tx_desc_head_vir_addr; ++ dma_addr_t tx_desc_head_phy_addr; ++ u32 cur_index; // for put send packet ++ spinlock_t tx_lock; ++ u32 non_free_tx_skb; ++ u32 free_tx_skb_index; ++ u32 ring_size; ++ u32 max_ring_size; ++}TXRing; ++ ++ ++typedef struct { ++ RXBuffer *head; ++ RXDesc *rx_desc_head_vir_addr; ++ dma_addr_t rx_desc_head_phy_addr; ++ u32 cur_index; ++ u32 ring_size; ++ u32 max_ring_size; ++}RXRing; ++ ++#if 0 ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ TXRing *tx_ring; ++ RXRing *rx_ring; ++}CNS3XXXRingStatus; ++#endif ++ ++ ++#define RX_RING0(priv) (priv->rx_ring[0]) ++#define TX_RING0(priv) (priv->tx_ring[0]) ++ ++ ++static inline u32 get_rx_ring_size(const RXRing *ring) ++{ ++ //printk("rx ring->ring_size: %d\n", ring->ring_size); ++ return ring->ring_size; ++} ++ ++static inline u32 get_tx_ring_size(TXRing *ring) ++{ ++ //printk("tx ring->ring_size: %d\n", ring->ring_size); ++ return ring->ring_size; ++} ++ ++static inline RXBuffer *get_rx_ring_head(const RXRing *rx_ring) ++{ ++ return rx_ring->head; ++} ++ ++static inline TXBuffer *get_tx_ring_head(TXRing *tx_ring) ++{ ++ return tx_ring->head; ++} ++ ++static inline RXBuffer *get_cur_rx_buffer(RXRing *rx_ring) ++{ ++ return rx_ring->head + rx_ring->cur_index; ++} ++ ++static inline TXBuffer *get_cur_tx_buffer(TXRing *tx_ring) ++{ ++ return tx_ring->head + tx_ring->cur_index; ++} ++ ++static inline u32 get_rx_head_phy_addr(RXRing *rx_ring) ++{ ++ return rx_ring->rx_desc_head_phy_addr; ++} ++ ++static inline u32 get_tx_ring_head_phy_addr(TXRing *tx_ring) ++{ ++ return tx_ring->tx_desc_head_phy_addr; ++} ++ ++ ++static inline u32 get_rx_cur_index(RXRing *rx_ring) ++{ ++ return rx_ring->cur_index; ++} ++ ++static inline u32 get_tx_cur_index(TXRing *tx_ring) ++{ ++ return tx_ring->cur_index; ++} ++ ++static inline u32 get_tx_cur_phy_addr(u8 ring_num) ++{ ++ if (ring_num == 0) ++ return TS_DESC_PTR0_REG; ++ if (ring_num == 1) ++ return TS_DESC_PTR1_REG; ++ return 0; // fail ++} ++ ++static inline void rx_index_next(RXRing *ring) ++{ ++ ring->cur_index = ((ring->cur_index + 1) % ring->ring_size); ++} ++static inline void tx_index_next(TXRing *ring) ++{ ++ ring->cur_index = ((ring->cur_index + 1) % ring->ring_size); ++} ++ ++ ++ ++struct CNS3XXXPrivate_; ++ ++typedef int (*RXFuncPtr)(struct sk_buff *skb, RXDesc*tx_desc_ptr, const struct CNS3XXXPrivate_* ); ++typedef int (*TXFuncPtr)(TXDesc*tx_desc_ptr, const struct CNS3XXXPrivate_*, struct sk_buff *); ++typedef void (*OpenPtr)(void); ++typedef void (*ClosePtr)(void); ++ ++ ++// for ethtool set operate ++typedef struct{ ++ ++}NICSetting; ++ ++typedef struct{ ++ int pmap; // for port base, force route ++ int is_wan; // mean the net device is WAN side. ++ //u16 gid; ++ u16 s_tag; ++ //u8 mac_type; // VLAN base, or port base; ++ u16 vlan_tag; ++ ++ // do port base mode and vlan base mode work ++ RXFuncPtr rx_func; ++ TXFuncPtr tx_func; ++ OpenPtr open; ++ ClosePtr close; ++ u8 which_port; ++ //NICSetting *nic_setting; ++ u8 *mac; // point to a mac address array ++ VLANTableEntry *vlan_table_entry; ++ ARLTableEntry *arl_table_entry; ++ NICSetting *nic_setting; ++ const char *name; // 16 bytes, reference include/linux/netdevice.h IFNAMSIZ ++}NetDevicePriv; ++ ++typedef struct ++{ ++ u8 num_rx_queues; ++ u8 num_tx_queues; ++ TXRing *tx_ring; ++ RXRing *rx_ring; ++}RingInfo; ++ ++ ++/* store this information for the driver.. */ ++typedef struct CNS3XXXPrivate_ ++{ ++ u8 num_rx_queues; ++ u8 num_tx_queues; ++ TXRing *tx_ring; ++ RXRing *rx_ring; ++ struct net_device_stats stats; ++ spinlock_t lock; ++ int pmap; ++ int is_wan; // mean the net device is WAN side. ++ u16 gid; ++ u8 mac_type; // VLAN base, or port base; ++ u16 vlan_tag; ++ struct napi_struct napi; ++ struct work_struct reset_task; ++ ++ u8 which_port; ++ //NICSetting *nic_setting; ++ char name[IFNAMSIZ]; // 16 bytes, reference include/linux/netdevice.h IFNAMSIZ ++ ++ ++ NetDevicePriv *net_device_priv; ++ u8 ring_index; ++ ++ u32 rx_s_vid[4096]; // record receive s vid (0x9100 ...) ++ u32 rx_c_vid[4096]; // record receive c vid (0x8100 ...) ++#ifdef CONFIG_CNS3XXX_NAPI ++ volatile unsigned long is_qf; // determine rx ring queue full state ++#endif ++ ++#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) ++ struct vlan_group *vlgrp; ++#endif ++}CNS3XXXPrivate; ++ ++ ++ ++ ++int rx_port_base(struct sk_buff *skb, RXDesc *rx_desc_ptr, const struct CNS3XXXPrivate_ *priv); ++ ++int rx_vlan_base(struct sk_buff *skb, RXDesc *rx_desc_ptr, const struct CNS3XXXPrivate_ *priv); ++ ++int tx_port_base(TXDesc *tx_desc_ptr, const struct CNS3XXXPrivate_ *priv, struct sk_buff *skb); ++ ++ ++int tx_vlan_base(TXDesc *tx_desc_ptr, const struct CNS3XXXPrivate_ *priv, struct sk_buff *skb); ++#if defined (CONFIG_CNS3XXX_SPPE) ++int fp_port_base(TXDesc *tx_desc_ptr, const struct CNS3XXXPrivate_ *priv, struct sk_buff *skb); ++#endif ++#endif ++ +--- /dev/null ++++ b/drivers/net/cns3xxx/cns3xxx_main.c +@@ -0,0 +1,3949 @@ ++/******************************************************************************* ++ * ++ * Copyright (c) 2009 Cavium Networks ++ * ++ * 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. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ ********************************************************************************/ ++ ++#include <linux/module.h> ++#include <mach/board.h> ++#include <linux/platform_device.h> ++#include "cns3xxx.h" ++#include "cns3xxx_tool.h" ++#include "cns3xxx_config.h" ++ ++#if defined (CONFIG_CNS3XXX_SPPE) ++#include <linux/cns3xxx/sppe.h> ++#define PACKET_REASON_TO_CPU (0x2C) ++#endif ++ ++#define RX_SDP_ALIGN 64 ++ ++#ifdef CONFIG_FPGA ++#include "fpga.h" ++#endif ++ ++#ifdef CONFIG_VB ++#include "vb.h" ++#endif ++ ++#define CPU_CACHE_BYTES 64 ++#define CPU_CACHE_ALIGN(X) (((X) + (CPU_CACHE_BYTES-1)) & ~(CPU_CACHE_BYTES-1)) ++ ++ ++#define QUEUE_WEIGHT_SET(port, ctl) \ ++{ \ ++ MAC##port##_PRI_CTRL_REG &= ~(0x3ffff); \ ++ MAC##port##_PRI_CTRL_REG |= (ctl.sch_mode << 16); \ ++ MAC##port##_PRI_CTRL_REG |= (ctl.q0_w); \ ++ MAC##port##_PRI_CTRL_REG |= (ctl.q1_w << 4); \ ++ MAC##port##_PRI_CTRL_REG |= (ctl.q2_w << 8); \ ++ MAC##port##_PRI_CTRL_REG |= (ctl.q3_w << 12); \ ++} ++ ++#define QUEUE_WEIGHT_GET(port, ctl) \ ++{ \ ++ ctl.sch_mode = ((MAC##port##_PRI_CTRL_REG >> 16 ) & 0x3); \ ++ ctl.q0_w = ((MAC##port##_PRI_CTRL_REG >> 0 ) & 0x7); \ ++ ctl.q1_w = ((MAC##port##_PRI_CTRL_REG >> 4 ) & 0x7); \ ++ ctl.q2_w = ((MAC##port##_PRI_CTRL_REG >> 8 ) & 0x7); \ ++ ctl.q3_w = ((MAC##port##_PRI_CTRL_REG >> 12 ) & 0x7); \ ++} ++ ++int cns3xxx_send_packet(struct sk_buff *skb, struct net_device *netdev); ++static int install_isr_rc = 0; ++static int rc_setup_rx_tx = 0; // rc means reference counting. ++static struct net_device *intr_netdev; ++struct net_device *net_dev_array[NETDEV_SIZE]; ++spinlock_t tx_lock; ++spinlock_t rx_lock; ++u8 fast_bridge_en=1; ++u8 show_rx_proc=0; ++u8 show_tx_proc=0; ++ ++int init_port=7; // bit map 7 means port 0, 1 and 2, default is 7. ++//module_param(init_port, u8, S_IRUGO); ++module_param(init_port, int, 0); ++ ++u8 ring_index=0; // 0 or 1 ++ ++#ifdef CNS3XXX_DELAYED_INTERRUPT ++static u32 max_pend_int_cnt=MAX_PEND_INT_CNT, max_pend_time=MAX_PEND_TIME; ++#endif ++ ++#ifdef CONFIG_CNS3XXX_NAPI ++struct net_device *napi_dev; ++ #ifdef CNS3XXX_DOUBLE_RX_RING ++ struct net_device *r1_napi_dev; // ring1 napi dev ++ #endif ++#endif ++ ++const u32 MAX_RX_DESC_SIZE = 512; ++const u32 MAX_TX_DESC_SIZE = 512; ++const u32 RX_DESC_SIZE = 128; ++//const u32 RX_DESC_SIZE = 5; ++const u32 TX_DESC_SIZE = 120; ++ ++//RXRing *rx_ring; ++//TXRing *tx_ring; ++ ++// only for debug (proc) ++RingInfo g_ring_info; ++ ++int MSG_LEVEL = NORMAL_MSG; ++ ++#ifdef CNS3XXX_STATUS_ISR ++const char *cns3xxx_gsw_status_tbl[] = { ++ "\nMAC0_Q_FULL\n", ++ "\nMAC1_Q_FULL\n", ++ "\nCPU_Q_FULL\n", ++ "\nHNAT_Q_FULL\n", ++ "\nMAC2_Q_FULL\n", ++ "\nMAC0_Q_EXT_FULL\n", ++ "\nGLOBAL_Q_FULL\n", ++ "\nBUFFER_FULL\n", ++ "\nMIB_COUNTER_TH\n", ++ "\n", // 9 ++ "\nMAC0_INTRUDER\n", ++ "\nMAC1_INTRUDER\n", ++ "\nCPU_INTRUDER\n", ++ "\nMAC2_INTRUDER\n", ++ "\nMAC0_STATUS_CHG\n", ++ "\nMAC1_STATUS_CHG\n", ++ "\nMAC2_STATUS_CHG\n", ++ "\nMAC0_NO_LINK_DROP\n", ++ "\nMAC1_NO_LINK_DROP\n", ++ "\nMAC2_NO_LINK_DROP\n", ++ "\nMAC0_RX_ERROR_DROP\n", ++ "\nMAC1_RX_ERROR_DROP\n", ++ "\nMAC2_RX_ERROR_DROP\n", ++ "\nMAC0_NO_DESTINATION_DROP\n", ++ "\nMAC1_NO_DESTINATION_DROP\n", ++ "\nMAC2_NO_DESTINATION_DROP\n", ++ "\nMAC0_RMC_PAUSE_DROP\n", ++ "\nMAC1_RMC_PAUSE_DROP\n", ++ "\nMAC2_RMC_PAUSE_DROP\n", ++ "\nMAC0_LOCAL_DROP\n", ++ "\nMAC1_LOCAL_DROP\n", ++ "\nMAC2_LOCAL_DROP\n", ++}; ++#endif ++ ++#define MIN_PACKET_LEN 14 ++ ++void cns3xxx_write_pri_mask(u8 pri_mask); ++ ++static int cns3xxx_notify_reboot(struct notifier_block *nb, unsigned long event, void *ptr); ++ ++static struct notifier_block cns3xxx_notifier_reboot = { ++ .notifier_call = cns3xxx_notify_reboot, ++ .next = NULL, ++ .priority = 0 ++}; ++ ++#if defined(CNS3XXX_VLAN_8021Q) ++void cns3xxx_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid); ++void cns3xxx_vlan_rx_register(struct net_device *dev, struct vlan_group *grp); ++#endif ++ ++void take_off_vlan_header(struct sk_buff *skb) ++{ ++ // take off VLAN header ++ memmove(skb->data + 4, skb->data, 12); ++#if 0 ++ //skb_ptr->data += 4; ++ skb_reserve(skb, 4); ++#else ++ skb->data += 4; ++#endif ++ skb->len -= 4; // minus 4 byte vlan tag ++} ++ ++int rx_port_base(struct sk_buff *skb, RXDesc *rx_desc_ptr, const struct CNS3XXXPrivate_ *priv) ++{ ++ if (skb->data[12] == 0x81 && skb->data[13] == 0x00) // VLAN header ++ { ++ take_off_vlan_header(skb); ++ print_packet(skb->data, skb->len); ++ } ++ return 0; ++} ++ ++int rx_vlan_base(struct sk_buff *skb, RXDesc *rx_desc_ptr, const struct CNS3XXXPrivate_ *priv) ++{ ++ return 0; ++} ++ ++int tx_port_base(TXDesc *tx_desc_ptr, const struct CNS3XXXPrivate_ *priv, struct sk_buff *skb) ++{ ++#if defined(CNS3XXX_VLAN_8021Q) && defined (CNS3XXX_8021Q_HW_TX) ++ if (skb && priv->vlgrp != NULL && vlan_tx_tag_present(skb)) ++ { ++ tx_desc_ptr->c_vid = cpu_to_le16(vlan_tx_tag_get(skb)); ++ tx_desc_ptr->ctv=1; ++ tx_desc_ptr->fr = 0; ++ ++ } ++ else ++#endif ++ { ++ tx_desc_ptr->ctv = 0; ++ tx_desc_ptr->pmap = priv->net_device_priv->pmap; ++ tx_desc_ptr->fr = 1; ++ } ++ ++ return 0; ++} ++ ++ ++int tx_vlan_base(TXDesc *tx_desc_ptr, const struct CNS3XXXPrivate_ *priv, struct sk_buff *skb) ++{ ++#if defined(CNS3XXX_VLAN_8021Q) ++ ++ if (skb && priv->vlgrp != NULL && vlan_tx_tag_present(skb)) { ++ tx_desc_ptr->c_vid = cpu_to_le16(vlan_tx_tag_get(skb)); ++ } ++#else ++ tx_desc_ptr->c_vid = priv->net_device_priv->vlan_tag; ++ ++#endif ++ tx_desc_ptr->ctv=1; ++ tx_desc_ptr->fr = 0; ++ ++ return 0; ++} ++ ++#if defined (CONFIG_CNS3XXX_SPPE) ++int fp_port_base(TXDesc *tx_desc_ptr, const struct CNS3XXXPrivate_ *priv, struct sk_buff *skb) ++{ ++#if 1 ++ tx_desc_ptr->fr = 1; ++ tx_desc_ptr->pmap = 0x8; ++#else ++ tx_desc_ptr->fr = 0; ++ tx_desc_ptr->ctv = 1; ++ tx_desc_ptr->c_vid = 80; ++#endif ++ return 0; ++} ++#endif ++ ++static inline struct sk_buff *cns3xxx_alloc_skb(void) ++{ ++ struct sk_buff *skb; ++ u32 align_64; ++ ++ skb = dev_alloc_skb(MAX_PACKET_LEN + 2 + RX_SDP_ALIGN); ++ ++ if (unlikely(!skb)) { ++ return NULL; ++ } ++ pci_dma_sync_single_for_device(NULL, virt_to_phys(skb->data), MAX_PACKET_LEN+2+RX_SDP_ALIGN, PCI_DMA_FROMDEVICE); ++ ++ align_64=CPU_CACHE_ALIGN((u32)skb->data); ++ skb_reserve(skb, align_64-(u32)skb->data); /* 16 bytes alignment */ ++ ++#ifndef CNS3XXX_4N ++ skb_reserve(skb, NET_IP_ALIGN); /* 16 bytes alignment */ ++#endif ++ ++ ++ ++ return skb; ++} ++ ++static int free_rx_skb(RXRing *rx_ring) ++{ ++ int i=0; ++ RXBuffer *rx_buffer = rx_ring->head; ++ //RXDesc *rx_desc = rx_ring.rx_desc_head_vir_addr; ++ ++ for (i=0 ; i < get_rx_ring_size(rx_ring) ; ++i) { ++ if (rx_buffer->rx_desc->cown==0 && rx_buffer->skb) { ++ dev_kfree_skb(rx_buffer->skb); ++ rx_buffer->skb=0; ++ } ++ } ++ return 0; ++} ++ ++int cns3xxx_setup_all_rx_resources(RXRing *rx_ring, u8 ring_num) ++{ ++ int i=0; ++ RXBuffer *rx_buffer = 0; ++ RXDesc *rx_desc = 0; ++ ++#ifdef NCNB_TEST ++ ncnb_buf = dma_alloc_coherent(NULL, 2*1024* get_rx_ring_size(rx_ring), &ncnb_buf_phy, GFP_KERNEL); ++ printk("NCB_BUF: %08X PHY: %08X \n", ncnb_buf, ncnb_buf_phy); ++ ++#endif ++ ++ // alloc RXDesc array ++ rx_ring->rx_desc_head_vir_addr = dma_alloc_coherent(NULL, sizeof(RXDesc) * (get_rx_ring_size(rx_ring)), &rx_ring->rx_desc_head_phy_addr, GFP_KERNEL); ++ if (!rx_ring->rx_desc_head_vir_addr) { ++ return -ENOMEM; ++ } ++ ++ memset(rx_ring->rx_desc_head_vir_addr, 0, sizeof(RXDesc) * get_rx_ring_size(rx_ring)); ++ ++ // alloc RXBuffer array ++ rx_ring->head = kmalloc(sizeof(RXBuffer) * get_rx_ring_size(rx_ring), GFP_KERNEL); ++ ++ if (!rx_ring->head) { ++ return -ENOMEM; ++ } ++ ++ rx_buffer = rx_ring->head; ++ for (i=0 ; i < get_rx_ring_size(rx_ring) ; ++i) { ++ rx_buffer->skb=0; ++ ++rx_buffer; ++ } ++ ++ rx_buffer = rx_ring->head; ++ rx_desc = rx_ring->rx_desc_head_vir_addr; ++ for (i=0 ; i < get_rx_ring_size(rx_ring) ; ++i, ++rx_buffer, ++rx_desc) { ++ rx_buffer->rx_desc = rx_desc; ++ rx_buffer->skb = cns3xxx_alloc_skb(); ++ ++ if (!rx_buffer->skb) { ++ ++ free_rx_skb(rx_ring); ++ kfree(rx_ring->head); ++ dma_free_coherent(NULL, sizeof(RXDesc) * get_rx_ring_size(rx_ring), rx_ring->rx_desc_head_vir_addr, rx_ring->rx_desc_head_phy_addr); ++ return -ENOMEM; ++ } ++ ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++ { ++ RXDesc tmp_rx_desc; ++ ++ memset(&tmp_rx_desc, 0, sizeof(RXDesc)); ++ tmp_rx_desc.sdp = (u32)virt_to_phys(rx_buffer->skb->data); ++ tmp_rx_desc.sdl = MAX_PACKET_LEN; ++ if (i == (get_rx_ring_size(rx_ring)-1) ){ ++ tmp_rx_desc.eor = 1; ++ } ++ tmp_rx_desc.fsd = 1; ++ tmp_rx_desc.lsd = 1; ++ swap_rx_desc(&tmp_rx_desc, rx_buffer->rx_desc); ++ } ++ ++#else ++ rx_buffer->rx_desc->sdp = (u32)virt_to_phys(rx_buffer->skb->data); ++ rx_buffer->rx_desc->sdl = MAX_PACKET_LEN; ++ if (i == (get_rx_ring_size(rx_ring)-1) ){ ++ rx_buffer->rx_desc->eor = 1; ++ } ++ rx_buffer->rx_desc->fsd = 1; ++ rx_buffer->rx_desc->lsd = 1; ++#endif ++ ++ } ++ rx_ring->cur_index = 0 ; ++ ++ if (ring_num == 0){ ++ FS_DESC_PTR0_REG = rx_ring->rx_desc_head_phy_addr; ++ FS_DESC_BASE_ADDR0_REG = rx_ring->rx_desc_head_phy_addr; ++ ++ } else if (ring_num == 1){ ++ FS_DESC_PTR1_REG = rx_ring->rx_desc_head_phy_addr; ++ FS_DESC_BASE_ADDR1_REG = rx_ring->rx_desc_head_phy_addr; ++ } ++ ++ return CAVM_OK; ++} ++ ++static int cns3xxx_setup_all_tx_resources(TXRing *tx_ring, u8 ring_num) ++{ ++ int i=0; ++ TXBuffer *tx_buffer = 0; ++ TXDesc *tx_desc = 0; ++ ++ ++ spin_lock_init(&(tx_ring->tx_lock)); ++ ++ tx_ring->tx_desc_head_vir_addr = dma_alloc_coherent(NULL, sizeof(TXDesc) * get_tx_ring_size(tx_ring), &tx_ring->tx_desc_head_phy_addr, GFP_KERNEL); ++ if (!tx_ring->tx_desc_head_vir_addr) { ++ return -ENOMEM; ++ } ++ ++ memset(tx_ring->tx_desc_head_vir_addr, 0, sizeof(TXDesc) * get_tx_ring_size(tx_ring)); ++ tx_ring->head = kmalloc(sizeof(TXBuffer) * get_tx_ring_size(tx_ring), GFP_KERNEL); ++ ++ tx_buffer = tx_ring->head; ++ tx_desc = tx_ring->tx_desc_head_vir_addr; ++ for (i=0 ; i < get_tx_ring_size(tx_ring) ; ++i, ++tx_buffer, ++tx_desc) { ++ tx_buffer->tx_desc = tx_desc; ++ ++ tx_buffer->tx_desc->cown = 1; ++ tx_buffer->skb = 0; ++ if (i == (get_tx_ring_size(tx_ring)-1) ){ ++ tx_buffer->tx_desc->eor = 1; ++ } ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++ swap_tx_desc(tx_buffer->tx_desc, tx_buffer->tx_desc); ++#endif ++ ++ } ++ ++ tx_ring->cur_index = 0 ; ++ ++ if (ring_num == 0){ ++ TS_DESC_PTR0_REG = tx_ring->tx_desc_head_phy_addr; ++ TS_DESC_BASE_ADDR0_REG = tx_ring->tx_desc_head_phy_addr; ++ } else if (ring_num == 1){ ++ TS_DESC_PTR1_REG = tx_ring->tx_desc_head_phy_addr; ++ TS_DESC_BASE_ADDR1_REG = tx_ring->tx_desc_head_phy_addr; ++ } ++ return CAVM_OK; ++} ++ ++int cns3xxx_free_all_rx_resources(RXRing *rx_ring) ++{ ++ free_rx_skb(rx_ring); ++ kfree(rx_ring->head); ++ dma_free_coherent(NULL, sizeof(RXDesc) * get_rx_ring_size(rx_ring), rx_ring->rx_desc_head_vir_addr, rx_ring->rx_desc_head_phy_addr); ++ return 0; ++} ++ ++static int free_tx_skb(TXRing *tx_ring) ++{ ++ int i=0; ++ TXBuffer *tx_buffer = tx_ring->head; ++ ++ for (i=0 ; i < get_tx_ring_size(tx_ring) ; ++i) { ++ if (tx_buffer->skb) { ++ dev_kfree_skb(tx_buffer->skb); ++ tx_buffer->skb = 0; ++ } ++ } ++ return 0; ++} ++ ++int cns3xxx_free_all_tx_resources(TXRing *tx_ring) ++{ ++ free_tx_skb(tx_ring); ++ kfree(tx_ring->head); ++ dma_free_coherent(NULL, sizeof(TXDesc) * get_tx_ring_size(tx_ring), tx_ring->tx_desc_head_vir_addr, tx_ring->tx_desc_head_phy_addr); ++ return 0; ++} ++ ++static int cns3xxx_free_rx_tx_res(CNS3XXXPrivate *priv) ++{ ++ int i=0; ++ ++ --rc_setup_rx_tx; ++ if (rc_setup_rx_tx == 0) { ++ enable_port(3, 0); // disable cpu port ++ ++ // stop RX/TX ring0 dma ++ enable_rx_dma(0, 0); ++ enable_tx_dma(0, 0); ++ ++ for (i=0 ; i < priv->num_rx_queues ; ++i) { ++ cns3xxx_free_all_rx_resources(priv->rx_ring+i); ++ memset(priv->rx_ring + i, 0, sizeof(RXRing)); ++ } ++ ++ for (i=0 ; i < priv->num_tx_queues ; ++i) { ++ cns3xxx_free_all_tx_resources(priv->tx_ring+i); ++ memset(priv->tx_ring + i, 0, sizeof(TXRing)); ++ } ++ ++ } ++ return 0; ++} ++ ++ ++static int cns3xxx_setup_rx_tx_res(CNS3XXXPrivate *priv) ++{ ++ int i=0; ++ ++ if (rc_setup_rx_tx == 0) { ++ clear_fs_dma_state(1); ++ FS_DESC_PTR0_REG = 0; ++ FS_DESC_BASE_ADDR0_REG = 0; ++ FS_DESC_PTR1_REG = 0; ++ FS_DESC_BASE_ADDR1_REG = 0; ++ TS_DESC_PTR0_REG = 0; ++ TS_DESC_BASE_ADDR0_REG = 0; ++ TS_DESC_PTR1_REG = 0; ++ TS_DESC_BASE_ADDR1_REG = 0; ++ ++ for (i=0 ; i < priv->num_tx_queues ; ++i) { ++ spin_lock_init(&((priv->tx_ring+i)->tx_lock)); ++ (priv->tx_ring+i)->max_ring_size = MAX_TX_DESC_SIZE; ++ (priv->tx_ring+i)->ring_size = TX_DESC_SIZE; ++ if (cns3xxx_setup_all_tx_resources(priv->tx_ring+i, i) != CAVM_OK) ++ return CAVM_ERR; ++ } ++ ++ for (i=0 ; i < priv->num_rx_queues ; ++i) { ++ (priv->rx_ring+i)->max_ring_size = MAX_RX_DESC_SIZE; ++ (priv->rx_ring+i)->ring_size = RX_DESC_SIZE; ++ if (cns3xxx_setup_all_rx_resources(priv->rx_ring+i, i) != CAVM_OK) ++ return CAVM_ERR; ++ ++ } ++ clear_fs_dma_state(0); ++ } ++ ++rc_setup_rx_tx; ++ return CAVM_OK; ++} ++ ++int free_tx_desc_skb(TXRing *tx_ring, u8 ring_num) ++{ ++#if 1 ++ int i=0; ++ //u32 tssd_current=0; ++ TXBuffer *tx_buffer = 0; ++ u32 tx_ring_size = get_tx_ring_size(tx_ring); ++ // check curent hw index previous tx descriptor ++ u32 cur_index = cns3xxx_get_tx_hw_index(ring_num) - 1; ++ ++ tx_buffer = get_tx_buffer_by_index(tx_ring, cur_index); ++ ++ ++ //while (1) ++ for (i=0 ; i < tx_ring_size ; ++i) { ++ if (tx_buffer->tx_desc->cown == 1 && tx_buffer->skb) { ++ dev_kfree_skb_any(tx_buffer->skb); ++ tx_buffer->skb=0; ++ //tx_buffer->tx_desc->cown == 1; ++ } else { ++ break; ++ } ++ // --tx_desc_pair_ptr ++ --cur_index; ++ tx_buffer = get_tx_buffer_by_index(tx_ring, cur_index); ++ ++ } ++#endif ++ return 0; ++} ++ ++void do_arl_lookup(void) ++{ ++} ++ ++inline void assign_netdev(RXBuffer volatile *rx_buffer) ++{ ++ RXDesc * rx_desc=0; ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++ RXDesc tmp_rx_desc; ++ rx_desc = &tmp_rx_desc; ++ swap_rx_desc(rx_buffer->rx_desc, rx_desc); ++#else ++ rx_desc = rx_buffer->rx_desc; ++#endif ++ ++ ++#if defined(CONFIG_CNS3XXX_PORT_BASE) || defined(CNS3XXX_VLAN_8021Q) ++ // sp: ++ // 0 - mac port 0 ++ // 1 - mac port 1 ++ // 4 - mac port 2 ++ ++ switch (rx_desc->sp) ++ { ++ case 0: ++ { ++ rx_buffer->skb->dev = PORT0_NETDEV; ++ break; ++ } ++ case 1: ++ { ++ rx_buffer->skb->dev = PORT1_NETDEV; ++ break; ++ } ++ case 4: ++ { ++ rx_buffer->skb->dev = PORT2_NETDEV; ++ break; ++ } ++ ++ } ++#endif ++ ++#ifdef CONFIG_CNS3XXX_VLAN_BASE ++{ ++ u16 vlan_tag; ++ ++ vlan_tag = rx_desc->c_vid; ++ rx_buffer->skb->dev = net_dev_array[vlan_tag]; ++ ++} ++#endif ++ ++} ++ ++#if defined(CNS3XXX_VLAN_8021Q) ++static int cns3xxx_vlan_rx(CNS3XXXPrivate *priv, struct sk_buff *skb, u16 vlan_tag) ++{ ++ return vlan_hwaccel_receive_skb(skb, priv->vlgrp, vlan_tag); ++} ++#endif ++ ++// old_priv has ring index information, current version only uses the information. ++static int cns3xxx_get_rfd_buff(RXBuffer volatile *rx_buffer, CNS3XXXPrivate *old_priv) ++{ ++ CNS3XXXPrivate *priv=0; ++ //RXDesc volatile *rxdesc_ptr = rx_buffer->rx_desc; ++ struct sk_buff *skb; ++ //unsigned char *data; ++ u32 len; ++ RXDesc *rx_desc; ++ ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++ ++ RXDesc tmp_rx_desc; ++ ++ rx_desc = &tmp_rx_desc; ++ swap_rx_desc(rx_buffer->rx_desc, rx_desc); ++ ++#else ++ rx_desc = rx_buffer->rx_desc; ++#endif ++ ++ //rxdesc_ptr = rxring.vir_addr + index; ++ skb = rx_buffer->skb; ++ len = rx_desc->sdl; ++ ++ ++#ifdef DEBUG_RX ++ if (MSG_LEVEL == DUMP_RX_PKT_INFO) { ++ print_packet(skb->data, len); ++ } ++ ++#endif ++ ++ pci_dma_sync_single_for_device(NULL, virt_to_phys(skb->data), len, PCI_DMA_FROMDEVICE); ++#if defined (CONFIG_CNS3XXX_SPPE) ++ if (PACKET_REASON_TO_CPU == rx_buffer->rx_desc->hr) { ++ if (sppe_pci_fp_ready) { ++ SPPE_PARAM param; ++ int pci_dev_index; ++ struct iphdr *iph; ++ ++ skb_put(skb, len); ++ iph = (struct iphdr *)(skb->data + sizeof(struct ethhdr)); ++ ++ memset(¶m, 0, sizeof(SPPE_PARAM)); ++ param.cmd = SPPE_CMD_ARP; ++ param.op = SPPE_OP_GET; ++ param.data.sppe_arp.ip[0] = iph->daddr; ++ if (SPPE_RESULT_SUCCESS != sppe_func_hook(¶m)) { ++ goto NOT_IN_PCI_FP; ++ } else { ++ pci_dev_index = param.data.sppe_arp.unused_1; ++ } ++ param.cmd = SPPE_CMD_PCI_FP_DEV; ++ param.op = SPPE_OP_GET; ++ param.data.sppe_pci_fp_dev.dev = NULL; ++ param.data.sppe_pci_fp_dev.index = pci_dev_index; ++ if (SPPE_RESULT_SUCCESS != sppe_pci_fp_hook(¶m)) { ++ goto NOT_IN_PCI_FP; ++ } else { ++ skb->dev = param.data.sppe_pci_fp_dev.dev; ++ } ++ #if 1 ++ dev_queue_xmit(skb); ++ #else ++ skb->dev->hard_start_xmit(skb, skb->dev); ++ #endif ++ ++ return 0; ++ } ++ } ++NOT_IN_PCI_FP: ++#endif ++ ++#ifdef CNS3XXX_NON_NIC_MODE_8021Q ++ if (cns3xxx_is_untag_packet(rx_desc) == 1) ++ take_off_vlan_header(skb); ++#endif ++ ++#ifdef CONFIG_CNS3XXX_PORT_BASE ++ assign_netdev(rx_buffer); ++ ++ if (rx_buffer->skb->dev) // if skb->dev is 0, means VLAN base ++ goto determine_dev_ok; ++ ++#endif /* CONFIG_CNS3XXX_PORT_BASE */ ++ ++ ++#ifdef CONFIG_CNS3XXX_VLAN_BASE ++ ++#ifdef CONFIG_HAVE_VLAN_TAG ++ ++#if defined(CNS3XXX_VLAN_8021Q) ++ // some funcion need netdev like eth_type_trans(), so need to assign it. ++ skb->dev = intr_netdev; ++ // 8021Q module will determine right netdev by vlan tag. ++#else // defined(CNS3XXX_VLAN_8021Q) ++ { ++ assign_netdev(rx_buffer); ++ ++ take_off_vlan_header(skb); ++ if (MSG_LEVEL == 5) ++ print_packet(skb->data, 32); ++ ++ if ( rx_buffer->skb->dev == 0){ ++ goto freepacket; ++ } ++ } ++ ++#endif // CNS3XXX_VLAN_8021Q ++ ++#else /* CONFIG_HAVE_VLAN_TAG */ ++ ++#ifdef CNS3XXX_RX_DESC_VLAN_INFO ++// get VLAN information by RX descriptor field ++ ++#endif ++ ++#endif // CONFIG_HAVE_VLAN_TAG ++ ++#endif // CONFIG_CNS3XXX_VLAN_BASE ++ ++ ++#ifdef CONFIG_CNS3XXX_PORT_BASE ++determine_dev_ok: ++#endif ++ ++ skb_put(skb, len); ++ ++ if (skb->dev) { ++ priv = netdev_priv(skb->dev); ++ } ++ else{ ++ DEBUG_MSG(WARNING_MSG, "skb_ptr->dev==NULL\n"); ++ goto freepacket; ++ } ++ ++#ifdef CNS3XXX_RX_HW_CHECKSUM ++ switch (rx_desc->prot) ++ { ++ case 1 : ++ case 2 : ++ case 5 : ++ case 6 : ++ { ++ if ( rx_desc->l4f == 0) { // tcp/udp checksum is correct ++ skb->ip_summed = CHECKSUM_UNNECESSARY; ++ } else { ++ skb->ip_summed = CHECKSUM_NONE; ++ } ++ break; ++ } ++ default: ++ { ++ skb->ip_summed = CHECKSUM_NONE; ++ break; ++ } ++ } ++#else ++ skb->ip_summed = CHECKSUM_NONE; ++#endif // CNS3XXX_RX_HW_CHECKSUM ++ ++ ++ // this line must, if no, packet will not send to network layer ++#ifdef CONFIG_FAST_BRIDGE ++ if (fast_bridge_en == 0) ++#endif ++ skb->protocol = eth_type_trans(skb, skb->dev); ++ ++ skb->dev->last_rx = jiffies; ++ priv->stats.rx_packets++; ++ priv->stats.rx_bytes += len; ++ ++#ifdef CONFIG_FAST_BRIDGE ++ if (fast_bridge_en == 1) { ++ ++ skb->ip_summed = CHECKSUM_NONE; ++ if ( skb->dev == PORT0_NETDEV) { ++ skb->dev = PORT1_NETDEV; ++ } else if ( skb->dev == PORT1_NETDEV) { ++ skb->dev = PORT0_NETDEV; ++ } ++ //skb->dev->hard_start_xmit(skb, skb->dev); ++ cns3xxx_send_packet(skb, skb->dev); ++ } else { ++#endif // #ifdef CONFIG_FAST_BRIDGE ++ ++ ++//#if defined(CNS3XXX_VLAN_8021Q) ++#if 0 ++ if (priv->vlgrp != NULL) ++ { ++ //cns3xxx_vlan_rx(priv, skb, rx_buffer->rx_desc->c_vid); ++ cns3xxx_vlan_rx(priv, skb, rx_buffer->rx_desc->c_vid); ++ //cns3xxx_vlan_rx(priv, skb, swab16(le32_to_cpu(rx_buffer->rx_desc->c_vid)) ); ++ } ++ else ++#else ++ #ifdef CONFIG_CNS3XXX_NAPI ++ netif_receive_skb(skb); ++ #else ++ netif_rx(skb); ++ #endif ++#endif ++ ++#ifdef CONFIG_FAST_BRIDGE ++ } ++#endif ++ ++ //vlan_hwaccel_receive_skb(skb, priv->vlgrp, 1); ++ ++ return 0; ++ ++freepacket: ++ //DEBUG_MSG(NORMAL_MSG, "freepacket\n"); ++ dev_kfree_skb_any(skb); ++ return 0; ++} ++ ++// index from 1 ++inline u32 get_rx_hw_index(CNS3XXXPrivate *priv) ++{ ++ return ((FS_DESC_PTR0_REG - get_rx_head_phy_addr(&RX_RING0(priv))) / sizeof(RXDesc) ); ++} ++ ++inline int get_rx_hw_index_by_reg(u8 ring_num) ++{ ++ if (ring_num == 0 ) { ++ return ((FS_DESC_PTR0_REG - FS_DESC_BASE_ADDR0_REG) / sizeof(RXDesc) ); ++ } else if (ring_num == 1 ) { ++ return ((FS_DESC_PTR1_REG - FS_DESC_BASE_ADDR1_REG) / sizeof(RXDesc) ); ++ } ++ ++ return CAVM_FAIL; ++} ++ ++void dump_rxring(void) ++{ ++ int j=0; ++ RXBuffer *rx_buffer = 0; ++ ++ rx_buffer = get_rx_ring_head(g_ring_info.rx_ring+0); ++ for (j=0 ; j < get_rx_ring_size(g_ring_info.rx_ring+0); ++j, ++rx_buffer) { ++ printk("[%d] ## rx_buffer->rx_desc->cown: %d\n", j, rx_buffer->rx_desc->cown); ++ } ++} ++ ++#ifdef CONFIG_CNS3XXX_NAPI ++void cns3xxx_receive_packet(CNS3XXXPrivate *priv, int mode, int *work_done, int work_to_do) ++#else ++void cns3xxx_receive_packet(CNS3XXXPrivate *priv, int mode) ++#endif ++{ ++ int fssd_index; ++ //int fssd_current; ++ RXBuffer volatile *rx_buffer = 0; ++ RXDesc volatile *rx_desc=0; ++ struct sk_buff *skb; ++#ifndef CONFIG_CNS3XXX_NAPI ++ int fsqf = 0; // Queue Full Mode =0 ++#endif ++ int i, rxcount = 0; ++ u8 queue_index = priv->ring_index; ++ ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++ RXDesc tmp_rx_desc; ++#endif ++ ++ rx_buffer = get_cur_rx_buffer(&(priv->rx_ring[queue_index])); ++ ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++ rx_desc = &tmp_rx_desc; ++ swap_rx_desc(rx_buffer->rx_desc, rx_desc); ++#else ++ rx_desc = rx_buffer->rx_desc; ++#endif ++ ++ fssd_index = get_rx_hw_index_by_reg(queue_index); ++ ++ if (fssd_index > get_rx_cur_index(&priv->rx_ring[queue_index]) ) { ++ rxcount = fssd_index - get_rx_cur_index(&priv->rx_ring[queue_index]); ++ } else if (fssd_index < get_rx_cur_index(&priv->rx_ring[queue_index])) { ++ rxcount = (get_rx_ring_size(&priv->rx_ring[queue_index]) - get_rx_cur_index(&priv->rx_ring[queue_index]) ) + fssd_index; ++ } else { // fssd_index == rxring.cur_index ++ if (rx_desc->cown == 0) { // if rx_desc->cown is 1, we can receive the RX descriptor. ++ enable_rx_dma(0, 1); ++ goto receive_packet_exit; ++ } else { ++ // Queue Full ++#ifndef CONFIG_CNS3XXX_NAPI ++ fsqf = 1; ++#endif ++ rxcount = get_rx_ring_size(&priv->rx_ring[queue_index]); ++ } ++ } ++#ifndef CONFIG_CNS3XXX_NAPI ++ if (mode == 1) { ++ fsqf = 1; ++ rxcount = get_rx_ring_size(&priv->rx_ring[queue_index]); ++ } ++#endif ++ ++#ifdef CNS3XXX_FREE_TX_IN_RX_PATH ++ free_tx_desc_skb(priv->tx_ring + 0, 0); ++#ifdef CNS3XXX_DOUBLE_TX_RING ++ free_tx_desc_skb(priv->tx_ring + 1, 1); ++#endif ++#endif ++ ++ for (i = 0; i < rxcount; i++) { ++ ++ if (rx_desc->cown != 0) { // start to get packet ++ // Alloc New skb_buff ++ skb = cns3xxx_alloc_skb(); ++ // Check skb_buff ++ if (skb) { ++ cns3xxx_get_rfd_buff(rx_buffer, priv); ++ rx_buffer->skb = skb; ++#ifndef NCNB_TEST ++ rx_desc->sdp = (u32)virt_to_phys(skb->data); ++#endif ++ rx_desc->sdl = MAX_PACKET_LEN; ++ rx_desc->fsd = 1; ++ rx_desc->lsd = 1; ++ rx_desc->cown = 0; // set cbit to 0 ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++ swap_rx_desc(rx_desc, rx_buffer->rx_desc); ++#endif ++ ++#ifdef CONFIG_CNS3XXX_NAPI ++ ++(*work_done); ++ if (*work_done >= work_to_do) { ++ ++ rx_index_next(&priv->rx_ring[queue_index]); // rx_ring.cur_index points to next ++ rx_buffer = get_cur_rx_buffer(&priv->rx_ring[queue_index]); ++ rx_desc = rx_buffer->rx_desc; ++ break; ++ } ++#endif ++ ++ } else { ++ // I will add dev->lp.stats->rx_dropped, it will effect the performance ++ //PDEBUG("%s: Alloc sk_buff fail, reuse the buffer\n", __FUNCTION__); ++ rx_desc->cown = 0; // set cbit to 0 ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++ swap_rx_desc(rx_desc, rx_buffer->rx_desc); ++#endif ++ ++ return; ++ } ++ } else { // cown is 0, no packets ++ //*work_done = 0; ++ return; ++ } ++ ++ ++ rx_index_next(&priv->rx_ring[queue_index]); // rx_ring.cur_index points to next ++ rx_buffer = get_cur_rx_buffer(&priv->rx_ring[queue_index]); ++ rx_desc = rx_buffer->rx_desc; ++ ++ } // end for (i = 0; i < rxcount; i++) ++ ++ ++#ifndef CONFIG_CNS3XXX_NAPI ++ if (fsqf) { ++ priv->rx_ring[queue_index].cur_index = fssd_index; ++ mb(); ++ enable_rx_dma(0, 1); ++ } ++#endif ++ ++ ++ //spin_unlock(&rx_lock); ++receive_packet_exit: ++ return; ++} ++ ++irqreturn_t cns3xxx_fsrc_ring0_isr(int irq, void *dev_id) ++{ ++ struct net_device *netdev = dev_id; ++ CNS3XXXPrivate *priv = netdev_priv(netdev); ++ ++ priv->ring_index=0; ++ ++#ifdef CONFIG_CNS3XXX_NAPI ++{ ++ CNS3XXXPrivate *priv = netdev_priv(napi_dev); ++ priv->ring_index=0; ++ ++#ifdef CNS3XXX_USE_MASK ++ cns3xxx_write_pri_mask(0xb0); ++#else ++ cns3xxx_disable_irq(FSRC_RING0_INTERRUPT_ID); ++#endif ++ ++ //if (likely(netif_rx_schedule_prep(napi_dev, &priv->napi))) { ++ if (likely(napi_schedule_prep(&priv->napi))) { ++ //__netif_rx_schedule(napi_dev, &priv->napi); ++ __napi_schedule(&priv->napi); ++ } else { ++#ifdef CNS3XXX_USE_MASK ++ cns3xxx_write_pri_mask(0xf0); ++#else ++ cns3xxx_enable_irq(FSRC_RING0_INTERRUPT_ID); ++#endif ++ } ++} ++#else // !CONFIG_CNS3XXX_NAPI ++ ++#ifdef CNS3XXX_USE_MASK ++ cns3xxx_write_pri_mask(0xb0); ++#else ++ cns3xxx_disable_irq(FSRC_RING0_INTERRUPT_ID); ++ cns3xxx_disable_irq(FSQF_RING0_INTERRUPT_ID); ++#endif ++ ++ cns3xxx_receive_packet(priv, 0); // Receive Once ++ ++#ifdef CNS3XXX_USE_MASK ++ cns3xxx_write_pri_mask(0xf0); ++#else ++ cns3xxx_enable_irq(FSRC_RING0_INTERRUPT_ID); ++ cns3xxx_enable_irq(FSQF_RING0_INTERRUPT_ID); ++#endif ++ enable_rx_dma(0, 1); ++#endif ++ ++ return IRQ_HANDLED; ++} ++ ++ ++#if defined(CNS3XXX_DOUBLE_RX_RING) ++irqreturn_t cns3xxx_fsrc_ring1_isr(int irq, void *dev_id) ++{ ++ struct net_device *netdev = dev_id; ++ CNS3XXXPrivate *priv = netdev_priv(netdev); ++ priv->ring_index=1; ++ ++ ++#if defined(CONFIG_CNS3XXX_NAPI) && defined(CNS3XXX_DOUBLE_RX_RING) ++{ ++ CNS3XXXPrivate *priv = netdev_priv(r1_napi_dev); ++ priv->ring_index=1; ++ ++ cns3xxx_disable_irq(FSRC_RING1_INTERRUPT_ID); ++ ++ if (likely(napi_schedule_prep(&priv->napi))) { ++ __napi_schedule(&priv->napi); ++ } else { ++ cns3xxx_enable_irq(FSRC_RING1_INTERRUPT_ID); ++ } ++} ++#else ++ ++ cns3xxx_disable_irq(CNS3XXX_FSRC_RING1_INTERRUPT_ID); ++ cns3xxx_disable_irq(CNS3XXX_FSQF_RING1_INTERRUPT_ID); ++ cns3xxx_receive_packet(priv, 0); // Receive Once ++ enable_rx_dma(1, 1); ++ ++ cns3xxx_enable_irq(CNS3XXX_FSRC_RING1_INTERRUPT_ID); ++ cns3xxx_enable_irq(CNS3XXX_FSQF_RING1_INTERRUPT_ID); ++#endif ++ ++ return IRQ_HANDLED; ++} ++#endif ++ ++int cns3xxx_check_enough_tx_descriptor(TXRing *tx_ring, int need_free_tx_desc) ++{ ++#if 1 ++ int i=0; ++ TXDesc *tx_desc=0; ++ u32 cur_index = get_tx_cur_index(tx_ring); ++ TXBuffer *tx_buffer = get_tx_buffer_by_index(tx_ring, cur_index); ++ ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++ TXDesc tmp_tx_desc; ++ tx_desc = &tmp_tx_desc; ++ swap_tx_desc(tx_buffer->tx_desc, tx_desc); ++#else ++ tx_desc = tx_buffer->tx_desc; ++#endif ++ ++ ++ for (i=0 ; i < need_free_tx_desc ; ++i) { ++ if ( tx_desc->cown == 0 ) { ++ return 0; // no free TX descriptor ++ } ++ tx_buffer = get_tx_buffer_by_index(tx_ring, ++cur_index); ++ } ++#endif ++ return 1; ++} ++ ++// if return CAVM_ERR, means pad is fail, the packet cannot send by switch. ++ ++int fill_a_skb_to_tx_desc(TXBuffer * tx_buffer, u8 *data, int len, struct sk_buff *skb, const struct CNS3XXXPrivate_ *priv, int sg, int fsd, int lsd) ++{ ++ //TXDesc *tx_desc_ptr = tx_buffer->tx_desc; ++ static int tt=0; ++ ++ TXDesc *tx_desc_ptr = 0; ++#ifdef CONFIG_SWTICH_BIG_ENDIAN ++ TXDesc tmp_tx_desc; ++ tx_desc_ptr = &tmp_tx_desc; ++ swap_tx_desc(tx_buffer->tx_desc, tx_desc_ptr); ++#else ++ tx_desc_ptr = tx_buffer->tx_desc; ++#endif ++ ++ ++ ++ if (tx_buffer->skb) { ++ dev_kfree_skb_any(tx_buffer->skb); ++ tx_buffer->skb = 0 ; ++ } else { ++ //++tx_ring.non_free_tx_skb; ++ } ++ ++ tx_buffer->skb = skb; /* for free skb */ ++ tx_desc_ptr->sdp = virt_to_phys(data); ++ tx_buffer->j = tt; ++ tx_buffer->tx_index = cns3xxx_get_tx_hw_index(0); ++ ++tt; ++ ++#if 0 ++ { ++ static u16 previous_sn_num=10; ++ u16 sn_num=0; ++ u16 e_type=0; ++ ++ memcpy(&e_type, skb->data + 12, 2); ++ e_type = be16_to_cpu(e_type); ++ ++ if (e_type == 0x0800) { ++ memcpy(&sn_num, skb->data + 0x28, 2); ++ sn_num = be16_to_cpu(sn_num); ++ ++ if ( previous_sn_num == sn_num) ++ printk("dup\n"); ++ ++ previous_sn_num = sn_num; ++ } ++ ++ } ++#endif ++ ++ ++#ifdef CNS3XXX_TX_HW_CHECKSUM ++ tx_desc_ptr->ico = 1; ++ tx_desc_ptr->uco = 1; ++ tx_desc_ptr->tco = 1; ++#else ++ tx_desc_ptr->ico = 0; ++ tx_desc_ptr->uco = 0; ++ tx_desc_ptr->tco = 0; ++#endif ++ // Wake interrupt ++#ifdef CNS3XXX_TSTC_RING0_ISR ++ tx_desc_ptr->interrupt = 1; ++#else ++ tx_desc_ptr->interrupt = 0; ++#endif ++ ++ /* fill 0 to MIN_PACKET_LEN size */ ++ // can change MIN_PACKET_LEN to 14 ++ if (sg==0 && len < MIN_PACKET_LEN) { ++ if (skb_padto(skb, MIN_PACKET_LEN)) ++ return CAVM_ERR; ++ ++ //memset(skb->data + len, 0, MIN_PACKET_LEN - len); ++ //skb->len = MIN_PACKET_LEN; ++ tx_desc_ptr->sdl = MIN_PACKET_LEN; ++ } else { ++ tx_desc_ptr->sdl = len; ++ } ++ ++ dma_cache_maint(data, tx_desc_ptr->sdl, PCI_DMA_TODEVICE); ++ ++ /* VLAN base or port base function to set TX descriptor */ ++ /* reference: tx_//port_base(), tx_vlan_base() */ ++ priv->net_device_priv->tx_func(tx_desc_ptr, priv, skb); ++ tx_desc_ptr->fsd = fsd; ++ tx_desc_ptr->lsd = lsd; ++ ++ /* NOT SG packet */ ++ if( fsd == 1 && lsd == 1) ++ tx_desc_ptr->cown = 0; ++ ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++ swap_tx_desc(tx_desc_ptr, tx_buffer->tx_desc); ++#endif ++ ++ return CAVM_OK; ++} ++ ++int cns3xxx_send_packet(struct sk_buff *skb, struct net_device *netdev) ++{ ++ ++ CNS3XXXPrivate *priv = netdev_priv(netdev); ++ TXBuffer *tx_buffer = 0; ++ unsigned long flags; ++ int nr_frags =skb_shinfo(skb)->nr_frags; ++ ++ TXDesc *tx_desc[10]; // FIXME: ensure to maximum sg size ++ int tx_desc_count=0; ++ int i=0; ++ ++#ifdef DEBUG_TX ++ if (MSG_LEVEL == DUMP_TX_PKT_INFO) { ++ print_packet(tx_buffer->skb->data, tx_buffer->tx_desc->sdl); ++ //dump_tx_desc(tx_buffer->tx_desc); ++ } ++#endif ++ ++ spin_lock_irqsave(&tx_lock, flags); ++ ++ if (cns3xxx_check_enough_tx_descriptor(priv->tx_ring + ring_index, (nr_frags==0 ) ? 1 : nr_frags) == 0) { ++ // no enough tx descriptor ++ spin_unlock_irqrestore(&tx_lock, flags); ++ // re-queue the skb ++ return NETDEV_TX_BUSY; ++ } ++ ++ tx_buffer = get_cur_tx_buffer(priv->tx_ring + ring_index); ++ ++ if (nr_frags == 0) { // non scatter/gather I/O ++ ++ fill_a_skb_to_tx_desc(tx_buffer, skb->data, skb->len, skb, priv, 0, 1, 1); ++ ++ tx_index_next(priv->tx_ring + ring_index); ++ ++ } else { // scatter/gather I/O ++ struct skb_frag_struct *frag = 0; ++ ++ ++ fill_a_skb_to_tx_desc(tx_buffer, skb->data, skb->len - skb->data_len, 0, priv, 1, 1, 0); ++ tx_desc[tx_desc_count++] = tx_buffer->tx_desc; ++ tx_index_next(priv->tx_ring + ring_index); ++ tx_buffer = get_cur_tx_buffer(priv->tx_ring + ring_index); ++ ++ for (i=0 ; i < nr_frags-1 ; ++i) { ++ frag = &skb_shinfo(skb)->frags[i]; ++ ++ fill_a_skb_to_tx_desc(tx_buffer, page_address(frag->page) + frag->page_offset, frag->size, 0, priv, 1, 0, 0); ++ tx_desc[tx_desc_count++] = tx_buffer->tx_desc; ++ ++ tx_index_next(priv->tx_ring + ring_index); ++ tx_buffer = get_cur_tx_buffer(priv->tx_ring + ring_index); ++ } ++ frag = &skb_shinfo(skb)->frags[nr_frags-1]; ++ ++ // last fragment ++ fill_a_skb_to_tx_desc(tx_buffer, page_address(frag->page) + frag->page_offset, frag->size, skb, priv, 1, 0, 1); ++ tx_desc[tx_desc_count++] = tx_buffer->tx_desc; ++ ++ tx_index_next(priv->tx_ring + ring_index); ++ tx_buffer = get_cur_tx_buffer(priv->tx_ring + ring_index); ++ } ++ ++ ++ if( nr_frags != 0) { ++ ++ for (i = 0; i < tx_desc_count ; i++ ) ++ tx_desc[i]->cown = 0 ; ++ } ++ ++ mb(); ++ enable_tx_dma(ring_index, 1); ++ ++ priv->stats.tx_packets++; ++ priv->stats.tx_bytes += skb->len; ++ netdev->trans_start = jiffies; ++ ++ spin_unlock_irqrestore(&tx_lock, flags); ++ return NETDEV_TX_OK; ++} ++ ++ ++#ifdef CNS3XXX_FSQF_RING0_ISR ++irqreturn_t cns3xxx_fsqf_ring0_isr(int irq, void *dev_id) ++{ ++#ifndef CONFIG_CNS3XXX_NAPI ++ struct net_device *netdev = dev_id; ++ CNS3XXXPrivate *priv = netdev_priv(netdev); ++#endif ++ ++#ifdef CONFIG_CNS3XXX_NAPI ++{ ++ CNS3XXXPrivate *priv = netdev_priv(napi_dev); ++ // because in normal state, fsql only invoke once and set_bit is atomic function. ++ // so I don't mask it. ++ set_bit(0, &priv->is_qf); ++} ++#else ++#ifdef CNS3XXX_USE_MASK ++ cns3xxx_write_pri_mask(0xb0); ++#else ++ cns3xxx_disable_irq(FSRC_RING0_INTERRUPT_ID); ++ cns3xxx_disable_irq(FSQF_RING0_INTERRUPT_ID); ++#endif ++ ++ ++ cns3xxx_receive_packet(priv, 1); // Receive at Queue Full Mode ++ ++#ifdef CNS3XXX_USE_MASK ++ cns3xxx_write_pri_mask(0xf0); ++#else ++ cns3xxx_enable_irq(FSRC_RING0_INTERRUPT_ID); ++ cns3xxx_enable_irq(FSQF_RING0_INTERRUPT_ID); ++#endif ++ ++ enable_rx_dma(0, 1); ++#endif // CONFIG_CNS3XXX_NAPI ++ ++ return IRQ_HANDLED; ++} ++#endif ++ ++ ++#if defined(CNS3XXX_DOUBLE_RX_RING) ++#ifdef CNS3XXX_FSQF_RING1_ISR ++irqreturn_t cns3xxx_fsqf_ring1_isr(int irq, void *dev_id) ++{ ++ struct net_device *netdev = dev_id; ++ CNS3XXXPrivate *priv = netdev_priv(netdev); ++ //INTC_CLEAR_EDGE_TRIGGER_INTERRUPT(INTC_GSW_FSQF_BIT_INDEX); ++ ++#ifdef CONFIG_CNS3XXX_NAPI ++{ ++ CNS3XXXPrivate *priv = netdev_priv(r1_napi_dev); ++ // because in normal state, fsqf only invoke once and set_bit is atomic function. ++ // so don't mask it. ++ set_bit(0, &priv->is_qf); ++} ++#else ++ cns3xxx_disable_irq(FSRC_RING1_INTERRUPT_ID); ++ cns3xxx_disable_irq(FSQF_RING1_INTERRUPT_ID); ++ ++ cns3xxx_receive_packet(priv, 1); // Receive at Queue Full Mode ++ enable_rx_dma(1, 1); ++ ++ cns3xxx_enable_irq(FSRC_RING1_INTERRUPT_ID); ++ cns3xxx_enable_irq(FSQF_RING1_INTERRUPT_ID); ++#endif ++ return IRQ_HANDLED; ++} ++#endif ++#endif //#if defined(CNS3XXX_DOUBLE_RX_RING) ++ ++ ++#ifdef CNS3XXX_STATUS_ISR ++irqreturn_t cns3xxx_status_isr(int irq, void *dev_id) ++{ ++ u32 int_status = INTR_STAT_REG; ++ u32 i=0; ++ ++ cns3xxx_disable_irq(STATUS_INTERRUPT_ID); ++ for (i = 0; i < 32; i++) { ++ if (int_status & (1 << i)) { ++ PRINT_INFO(cns3xxx_gsw_status_tbl[i]); ++ } ++ } ++ INTR_STAT_REG = 0xffffffff; // write 1 for clear. ++ cns3xxx_enable_irq(STATUS_INTERRUPT_ID); ++ return IRQ_HANDLED; ++} ++#endif ++ ++ ++#ifdef CNS3XXX_TSTC_RING0_ISR ++irqreturn_t cns3xxx_tstc_ring0_isr(int irq, void *dev_id) ++{ ++ return IRQ_HANDLED; ++} ++#endif ++ ++ ++static int cns3xxx_install_isr(struct net_device *dev) ++{ ++ int retval; ++ CNS3XXXPrivate *priv = netdev_priv(dev); ++ ++ if (install_isr_rc == 0) { ++ ++ retval = request_irq(FSRC_RING0_INTERRUPT_ID, cns3xxx_fsrc_ring0_isr, IRQF_SHARED, "FSRC_RING0", intr_netdev); ++ ++ if (retval) { ++ return 1; ++ } ++ ++#ifdef CNS3XXX_FSQF_RING0_ISR ++ retval = request_irq(FSQF_RING0_INTERRUPT_ID, cns3xxx_fsqf_ring0_isr, IRQF_SHARED, "FSQF_RING0", intr_netdev); ++ ++ if (retval) { ++ PRINT_INFO("%s: unable to get IRQ %d (irqval=%d).\n", "FSQF_RING0", FSQF_RING0_INTERRUPT_ID, retval); ++ return 2; ++ } ++#endif ++ ++#ifdef CNS3XXX_TSTC_RING0_ISR ++ retval = request_irq(TSTC_RING0_INTERRUPT_ID, cns3xxx_tstc_ring0_isr, IRQF_SHARED, "TSTC_RING0", intr_netdev); ++ ++ if (retval) { ++ PRINT_INFO("%s: unable to get IRQ %d (irqval=%d).\n", "TSTC_RING0", FSQF_RING0_INTERRUPT_ID, retval); ++ return 3; ++ } ++ ++#endif ++ ++ ++ if (priv->num_rx_queues == 2) { ++#if defined(CNS3XXX_DOUBLE_RX_RING) ++ retval = request_irq(FSRC_RING1_INTERRUPT_ID, cns3xxx_fsrc_ring1_isr, IRQF_SHARED, "FSRC_RING1", intr_netdev); ++ ++ if (retval) { ++ return 1; ++ } ++ ++#ifdef CNS3XXX_FSQF_RING1_ISR ++ retval = request_irq(FSQF_RING1_INTERRUPT_ID, cns3xxx_fsqf_ring1_isr, IRQF_SHARED, "FSQF_RING1", intr_netdev); ++ ++ if (retval) { ++ PRINT_INFO("%s: unable to get IRQ %d (irqval=%d).\n", "FSQF_RING1", FSQF_RING1_INTERRUPT_ID, retval); ++ return 2; ++ } ++#endif ++ ++#endif ++ } ++ ++#ifdef CNS3XXX_STATUS_ISR ++ retval = request_irq(STATUS_INTERRUPT_ID, cns3xxx_status_isr, IRQF_SHARED, "GSW_STATUS", intr_netdev); ++ ++ if (retval) { ++ PRINT_INFO("%s: unable to get IRQ %d (irqval=%d).\n", "GSW STATUS INT", STATUS_INTERRUPT_ID, retval); ++ return 3; ++ } ++ INTR_MASK_REG = 0; ++#endif ++ ++ ++ ++ ++ ++ ++#ifdef CONFIG_CNS3XXX_NAPI ++{ ++ CNS3XXXPrivate *sp = netdev_priv(napi_dev); ++ napi_enable(&sp->napi); ++ netif_start_queue(napi_dev); ++ ++#ifdef CNS3XXX_DOUBLE_RX_RING ++ sp = netdev_priv(r1_napi_dev); ++ napi_enable(&sp->napi); ++ netif_start_queue(r1_napi_dev); ++#endif ++} ++#endif ++ // enable cpu port ++ enable_port(3, 1); ++ ++ } // end if (install_isr_rc == 0) ++ ++ ++install_isr_rc; ++ ++ return 0; ++} ++ ++ ++int cns3xxx_open(struct net_device *dev) ++{ ++ CNS3XXXPrivate *priv = netdev_priv(dev); ++ //static int init_state=0; ++ ++ if (cns3xxx_setup_rx_tx_res(priv) != CAVM_OK) { ++ return -1; ++ } ++ ++ netif_start_queue(dev); ++ priv->net_device_priv->open(); ++ ++ cns3xxx_install_isr(dev); ++ ++ enable_rx_dma(0, 1); ++ ++ if (priv->num_rx_queues == 2) ++ enable_rx_dma(1, 1); ++ ++ netif_carrier_on(dev); ++ ++ return 0; ++} ++ ++static int cns3xxx_uninstall_isr(struct net_device *dev) ++{ ++ CNS3XXXPrivate *priv = netdev_priv(dev); ++ --install_isr_rc; ++ if (install_isr_rc == 0) { ++ enable_port(3, 0); ++ free_irq(FSRC_RING0_INTERRUPT_ID, intr_netdev); ++#ifdef CNS3XXX_STATUS_ISR ++ free_irq(STATUS_INTERRUPT_ID, intr_netdev); ++#endif ++ ++#ifdef CNS3XXX_FSQF_RING0_ISR ++ free_irq(FSQF_RING0_INTERRUPT_ID, intr_netdev); ++#endif ++ ++#ifdef CNS3XXX_TSTC_RING0_ISR ++ free_irq(TSTC_RING0_INTERRUPT_ID, intr_netdev); ++#endif ++ ++ if (priv->num_rx_queues == 2) { ++ free_irq(FSRC_RING1_INTERRUPT_ID, intr_netdev); ++ ++#ifdef CNS3XXX_FSQF_RING1_ISR ++ free_irq(FSQF_RING1_INTERRUPT_ID, intr_netdev); ++#endif ++ } ++ ++ ++ ++#ifdef CONFIG_CNS3XXX_NAPI ++{ ++ CNS3XXXPrivate *sp = netdev_priv(napi_dev); ++ ++ napi_disable(&sp->napi); ++ netif_stop_queue(napi_dev); ++#ifdef CNS3XXX_DOUBLE_RX_RING ++ sp = netdev_priv(r1_napi_dev); ++ ++ napi_disable(&sp->napi); ++ netif_stop_queue(r1_napi_dev); ++#endif ++} ++#endif ++ ++ ++ } ++ ++ return 0; ++} ++ ++int cns3xxx_close(struct net_device *dev) ++{ ++ CNS3XXXPrivate *priv = netdev_priv(dev); ++ ++ enable_rx_dma(0, 0); ++ enable_tx_dma(0, 0); ++ ++ if (priv->num_rx_queues == 2) ++ enable_tx_dma(1, 0); ++ ++ if (priv->num_tx_queues == 2) ++ enable_rx_dma(1, 0); ++ ++ netif_stop_queue(dev); ++ ++ priv->net_device_priv->close(); ++ cns3xxx_uninstall_isr(dev); ++ cns3xxx_free_rx_tx_res(priv); ++ netif_carrier_off(dev); ++ return 0; ++} ++ ++ ++ ++//#define MAC_PORT(p) MAC##p##_CFG_REG ++ ++void broadcast_storm_cfg(u8 port, u8 boradcast, u8 multicast, u8 unknown) ++{ ++ switch (port) ++ { ++ case 0: ++ { ++ (boradcast == 1) ? (MAC0_CFG_REG |= (1 << 30)) : (MAC0_CFG_REG &= (~(1 << 30))) ; ++ (multicast == 1) ? (MAC0_CFG_REG |= (1 << 29)) : (MAC0_CFG_REG &= (~(1 << 29))) ; ++ (unknown == 1) ? (MAC0_CFG_REG |= (1 << 28)) : (MAC0_CFG_REG &= (~(1 << 28))) ; ++ break; ++ } ++ case 1: ++ { ++ (boradcast == 1) ? (MAC1_CFG_REG |= (1 << 30)) : (MAC1_CFG_REG &= (~(1 << 30))) ; ++ (multicast == 1) ? (MAC1_CFG_REG |= (1 << 29)) : (MAC1_CFG_REG &= (~(1 << 29))) ; ++ (unknown == 1) ? (MAC1_CFG_REG |= (1 << 28)) : (MAC1_CFG_REG &= (~(1 << 28))) ; ++ break; ++ } ++ case 2: ++ { ++ (boradcast == 1) ? (MAC2_CFG_REG |= (1 << 30)) : (MAC2_CFG_REG &= (~(1 << 30))) ; ++ (multicast == 1) ? (MAC2_CFG_REG |= (1 << 29)) : (MAC2_CFG_REG &= (~(1 << 29))) ; ++ (unknown == 1) ? (MAC2_CFG_REG |= (1 << 28)) : (MAC2_CFG_REG &= (~(1 << 28))) ; ++ break; ++ } ++ } ++} ++ ++void broadcast_storm_rate(u8 rate) ++{ ++ TC_CTRL_REG &= (~(0xf << 24)); ++ TC_CTRL_REG |= (rate << 24); ++} ++ ++// port: 0, 1, 2 ; port0, port1 and port2 ++// config general mac port configuration ++void cns3xxx_general_mac_cfg(u8 port) ++{ ++ u32 cfg=0; ++ ++ switch (port) ++ { ++ case 0: ++ { ++ cfg = MAC0_CFG_REG; ++ break; ++ } ++ case 1: ++ { ++ cfg = MAC1_CFG_REG; ++ break; ++ } ++ case 2: ++ { ++ cfg = MAC2_CFG_REG; ++ break; ++ } ++ } ++ ++ ++ // txc_check_en: 1 ++ cfg |= (1 << 13); ++ ++ // bp_en: 1 ++ cfg |= (1 << 17); ++ ++#ifdef CNS3XXX_LEARN_ENABLE ++ // learn_dis: 0 ++ cfg &= (~(1 << 19)); ++#else ++ // learn disable ++ cfg |= (1 << 19); ++#endif ++ ++ // blocking_state: 0 ++ cfg &= (~(1 << 20)); ++ ++ // block_mode: 0 ++ cfg &= (~(1 << 21)); ++ ++#ifdef CNS3XXX_AGE_ENABLE ++ // age_en: 1 ++ cfg |= (1 << 22); ++ ++#else ++ // age disable ++ cfg &= (~(1 << 22)); ++#endif ++ ++ // SA_secured: 0 ++ cfg &= (~(1 << 23)); ++ ++ switch (port) ++ { ++ case 0: ++ { ++ MAC0_CFG_REG = cfg; ++ break; ++ } ++ case 1: ++ { ++ MAC1_CFG_REG = cfg; ++ break; ++ } ++ case 2: ++ { ++ MAC2_CFG_REG = cfg; ++ break; ++ } ++ } ++ ++} ++ ++void cns3xxx_configu_cpu_port(void) ++{ ++ // Set CPU port to general configuration ++ ++#ifdef CNS3XXX_LEARN_ENABLE ++ CPU_CFG_REG &= (~(1 << 19)); ++#else ++ // learn_dis: 1 ++ CPU_CFG_REG |= (1 << 19); ++#endif ++ ++#ifdef CNS3XXX_AGE_ENABLE ++ // age_en: 1 ++ CPU_CFG_REG |= (1 << 22); ++#else ++ // age disable ++ CPU_CFG_REG &= (~(1 << 22)); ++#endif ++ ++ // SA_secured: 0 ++ CPU_CFG_REG &= (~(1 << 23)); ++ ++ // go to hnat:1 ++ CPU_CFG_REG |= (1 << 29); ++ ++ //offset 4N +2 ++ CPU_CFG_REG &= (~(1 << 30)); ++#ifdef CNS3XXX_4N ++ CPU_CFG_REG |= (1 << 30); ++#endif ++ ++ // cpu flow control disable ++ CPU_CFG_REG &= (~(1 << 31)); ++#ifdef CNS3XXX_CPU_PORT_FC ++ // cpu flow control enable ++ CPU_CFG_REG |= (1 << 31); ++#endif ++ ++} ++ ++static void __init cns3xxx_gsw_hw_init(void) ++{ ++ //u32 mac_port_config; ++ int i; ++ //u32 cfg_reg = 0; ++ u32 reg_config = 0; ++ ++#ifdef CONFIG_SILICON ++ ++ //GPIOB_PIN_EN_REG |= (1 << 14); //enable GMII2_CRS ++ //GPIOB_PIN_EN_REG |= (1 << 15); //enable GMII2_COL ++ GPIOB_PIN_EN_REG |= (1 << 20); //enable MDC ++ GPIOB_PIN_EN_REG |= (1 << 21); //enable MDIO ++ ++ cns3xxx_gsw_power_enable(); ++ cns3xxx_gsw_software_reset(); ++#endif ++ ++#ifdef CNS3XXX_CONFIG_SIM_MODE ++ SLK_SKEW_CTRL_REG |= (1 << 31); ++#endif ++ ++ ++#if 1 ++ while (((SRAM_TEST_REG >> 20) & 1) == 0); ++#endif ++ ++ clear_fs_dma_state(1); ++ ++ ++ // disable port mac0, mac1, mac2, cpu port ++ enable_port(0, 0); ++ enable_port(1, 0); ++ enable_port(2, 0); ++ enable_port(3, 0); ++ ++ // disable RX0/TX0 RX1/TX1 DMA ++ enable_tx_dma(0, 0); ++ enable_tx_dma(1, 0); ++ enable_rx_dma(0, 0); ++ enable_rx_dma(1, 0); ++ ++ INTR_STAT_REG = 0xffffffff; // write 1 for clear. ++ ++#ifdef CNS3XXX_DELAYED_INTERRUPT ++ DELAY_INTR_CFG_REG = (1 << 16) | (max_pend_int_cnt << 8) | (max_pend_time); ++#endif ++ ++ reg_config = PHY_AUTO_ADDR_REG; ++ reg_config &= ~(3 << 30); ++#ifdef CONFIG_CNS3XXX_JUMBO_FRAME ++ reg_config |= (3 << 30); // maximum frame length: 9600 bytes ++#else ++ reg_config |= (2 << 30); // maximum frame length: 1536 bytes ++#endif ++ ++ PHY_AUTO_ADDR_REG = reg_config; ++ ++ ++ // Set general value for MAC_GLOB_CFG_REG ++ // age_time: 2 ^(1-1) * 300 sec ++ MAC_GLOB_CFG_REG &= (~0xf); ++ MAC_GLOB_CFG_REG |= 1; ++ ++ ++ // bkoff_mode: 111 follow standard ++ MAC_GLOB_CFG_REG &= (~(0x7 << 9)); ++ MAC_GLOB_CFG_REG |= (0x7 << 9); ++ ++ // jam_no: 1010: ++ MAC_GLOB_CFG_REG &= (~(0xf << 12)); ++ MAC_GLOB_CFG_REG |= (0xa << 12); ++ ++ // bp_mode: 10: ++ MAC_GLOB_CFG_REG &= (~(0x3 << 16)); ++ MAC_GLOB_CFG_REG |= (0x2 << 16); ++ ++ // res_mc_flt: 0 ++ MAC_GLOB_CFG_REG &= (~(0x1 << 28)); ++ ++ // col_mode: 11 ++ MAC_GLOB_CFG_REG &= (~(0x3 << 18)); ++ MAC_GLOB_CFG_REG |= (0x3 << 18); ++ ++ // crc_stripping: 1 ++ MAC_GLOB_CFG_REG |= (0x1 << 20); ++ ++ ++ // ACCEPT_CRC_BAD_PKT : 0 ++ MAC_GLOB_CFG_REG &= (~(0x1 << 21)); ++ ++#ifdef ACCEPT_CRC_BAD_PKT ++ MAC_GLOB_CFG_REG |= (0x1 << 21); ++#endif ++ ++ // SVL ++ MAC_GLOB_CFG_REG &= (~(0x1 << 7)); ++ ++#ifdef IVL ++ // IVL: 1 (IVL), 0 (SVL) ++ MAC_GLOB_CFG_REG |= (0x1 << 7); ++#endif ++ ++ ++ // HNAT_en: 0 ++ MAC_GLOB_CFG_REG &= (~(0x1 << 26)); ++ ++ // Firewall_mode: 0 ++ MAC_GLOB_CFG_REG &= (~(0x1 << 27)); ++ ++ ++ ++ cns3xxx_general_mac_cfg(0); ++ cns3xxx_general_mac_cfg(1); ++ cns3xxx_general_mac_cfg(2); ++ cns3xxx_configu_cpu_port(); ++ ++ // write vlan table ++ // set cpu port vlan table ++ cns3xxx_vlan_table_add(&cpu_vlan_table_entry); ++ for (i=0 ; i < sizeof(vlan_table_entry)/sizeof(VLANTableEntry) ; ++i) ++ cns3xxx_vlan_table_add(&vlan_table_entry[i]); ++ ++ cns3xxx_set_pvid(0, PORT0_PVID); ++ cns3xxx_set_pvid(1, PORT1_PVID); ++ cns3xxx_set_pvid(2, PORT2_PVID); ++ cns3xxx_set_pvid(3, CPU_PVID); ++ ++#ifdef CNS3XXX_SET_ARL_TABLE ++ // set arl table ++ cns3xxx_arl_table_flush(); ++#endif ++} ++ ++static int cns3xxx_set_mac_addr(struct net_device *dev, void *p) ++{ ++ //struct sockaddr *sock_addr = addr; ++ CNS3XXXPrivate *priv = netdev_priv(dev); ++ ++ struct sockaddr *addr= p; ++ ++ ++ spin_lock_irq(&priv->lock); ++ ++ ++ if (!is_valid_ether_addr(addr->sa_data)) ++ return -EADDRNOTAVAIL; ++ ++ // 1. delete old arl mac entry ++ // 2. add new arl mac entry ++ // 3. copy new mac to netdev field ++ ++ if (priv->net_device_priv->arl_table_entry) { ++ cns3xxx_arl_table_invalid(priv->net_device_priv->arl_table_entry); ++ memcpy(priv->net_device_priv->arl_table_entry->mac, addr->sa_data, dev->addr_len); ++ //print_arl_table_entry(priv->net_device_priv->arl_table_entry); ++ cns3xxx_arl_table_add(priv->net_device_priv->arl_table_entry); ++ } ++ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); ++ ++ spin_unlock_irq(&priv->lock); ++ return 0; ++} ++ ++ ++int set_fc_rls(struct ifreq *ifr) ++{ ++ CNS3XXXSARLEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ FC_GLOB_THRS_REG &= (~(0x1ff << 16)); ++ FC_GLOB_THRS_REG |= (ctl.val << 16); ++ return CAVM_OK; ++} ++ ++int get_fc_rls(struct ifreq *ifr) ++{ ++ CNS3XXXSARLEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ ++ ctl.val = ((FC_GLOB_THRS_REG >> 16) & 0x1ff); ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ return CAVM_OK; ++} ++ ++int set_fc_set(struct ifreq *ifr) ++{ ++ CNS3XXXSARLEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ FC_GLOB_THRS_REG &= (~0x1ff); ++ FC_GLOB_THRS_REG |= ctl.val; ++ return CAVM_OK; ++} ++ ++int get_fc_set(struct ifreq *ifr) ++{ ++ CNS3XXXSARLEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ ++ ctl.val = ((FC_GLOB_THRS_REG) & 0x1ff); ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ return CAVM_OK; ++} ++ ++ ++int set_sarl_rls(struct ifreq *ifr) ++{ ++ CNS3XXXSARLEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ SARL_CTRL_REG &= (~(0x1ff << 12)); ++ SARL_CTRL_REG |= (ctl.val << 12); ++ return CAVM_OK; ++} ++ ++int get_sarl_rls(struct ifreq *ifr) ++{ ++ CNS3XXXSARLEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ ++ ctl.val = ((SARL_CTRL_REG >> 12) & 0x1ff); ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ return CAVM_OK; ++} ++ ++int set_sarl_enable(struct ifreq *ifr) ++{ ++ CNS3XXXSARLEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ SARL_CTRL_REG &= (~(0x1 << 31)); ++ SARL_CTRL_REG |= (ctl.val << 31); ++ return CAVM_OK; ++} ++ ++int get_sarl_enable(struct ifreq *ifr) ++{ ++ CNS3XXXSARLEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ ctl.val = ((SARL_CTRL_REG >> 31 ) & 0x1); ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ return CAVM_OK; ++} ++int set_sarl_set(struct ifreq *ifr) ++{ ++ CNS3XXXSARLEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ SARL_CTRL_REG &= (~0x1ff); ++ SARL_CTRL_REG |= ctl.val; ++ return CAVM_OK; ++} ++ ++int get_sarl_set(struct ifreq *ifr) ++{ ++ CNS3XXXSARLEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ ++ ctl.val = ((SARL_CTRL_REG) & 0x1ff); ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ return CAVM_OK; ++} ++ ++int set_sarl_oq(struct ifreq *ifr) ++{ ++ CNS3XXXSARLEntry ctl; ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ ++ switch (ctl.gyr) ++ { ++ case 0: // green ++ { ++ SARL_OQ_GTH_REG &= (~(0xff << ctl.tc*8)); ++ SARL_OQ_GTH_REG |= (ctl.val << ctl.tc*8); ++ break; ++ } ++ case 1: // yellow ++ { ++ SARL_OQ_YTH_REG &= (~(0xff << ctl.tc*8)); ++ SARL_OQ_YTH_REG |= (ctl.val << ctl.tc*8); ++ break; ++ } ++ case 2: // red ++ { ++ SARL_OQ_RTH_REG &= (~(0xff << ctl.tc*8)); ++ SARL_OQ_RTH_REG |= (ctl.val << ctl.tc*8); ++ break; ++ } ++ } ++ return CAVM_OK; ++} ++ ++int get_sarl_oq(struct ifreq *ifr) ++{ ++ CNS3XXXSARLEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ ++ switch (ctl.gyr) ++ { ++ case 0: // green ++ { ++ ctl.val = ((SARL_OQ_GTH_REG >> ctl.tc*8) & 0xff); ++ break; ++ } ++ case 1: // yellow ++ { ++ ctl.val = ((SARL_OQ_YTH_REG >> ctl.tc*8) & 0xff); ++ break; ++ } ++ case 2: // red ++ { ++ ctl.val = ((SARL_OQ_RTH_REG >> ctl.tc*8) & 0xff); ++ break; ++ } ++ } ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXSARLEntry)) ) ++ return -EFAULT; ++ return CAVM_OK; ++} ++ ++int set_queue_weight(struct ifreq *ifr) ++{ ++ CNS3XXXQueueWeightEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXQueueWeightEntry)) ) ++ return -EFAULT; ++ switch (ctl.which_port) ++ { ++ case 0: ++ { ++ QUEUE_WEIGHT_SET(0, ctl) ++ return 0; ++ } ++ case 1: ++ { ++ QUEUE_WEIGHT_SET(1, ctl) ++ return 0; ++ } ++ case 2: ++ { ++ QUEUE_WEIGHT_SET(2, ctl) ++ return 0; ++ } ++ case 3: // cpu port ++ { ++ CPU_PRI_CTRL_REG &= ~(0x3ffff); ++ CPU_PRI_CTRL_REG |= (ctl.sch_mode << 16); ++ CPU_PRI_CTRL_REG |= (ctl.q0_w); ++ CPU_PRI_CTRL_REG |= (ctl.q1_w << 4); ++ CPU_PRI_CTRL_REG |= (ctl.q2_w << 8); ++ CPU_PRI_CTRL_REG |= (ctl.q3_w << 12); ++ return 0; ++ } ++ case 4: // PPE port ++ { ++ HNAT_PRI_CTRL_REG &= ~(0x3ffff); ++ HNAT_PRI_CTRL_REG |= (ctl.sch_mode << 16); ++ HNAT_PRI_CTRL_REG |= (ctl.q0_w); ++ HNAT_PRI_CTRL_REG |= (ctl.q1_w << 4); ++ HNAT_PRI_CTRL_REG |= (ctl.q2_w << 8); ++ HNAT_PRI_CTRL_REG |= (ctl.q3_w << 12); ++ return 0; ++ } ++ default: ++ { ++ return -EFAULT; ++ } ++ } ++} ++ ++int get_queue_weight(struct ifreq *ifr) ++{ ++ CNS3XXXQueueWeightEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXQueueWeightEntry)) ) ++ return -EFAULT; ++ ++ switch (ctl.which_port) ++ { ++ case 0: ++ { ++ QUEUE_WEIGHT_GET(0, ctl) ++ break; ++ } ++ case 1: ++ { ++ QUEUE_WEIGHT_GET(1, ctl) ++ break; ++ } ++ case 2: ++ { ++ QUEUE_WEIGHT_GET(2, ctl) ++ break; ++ } ++ case 3: ++ { ++ ctl.sch_mode = ((CPU_PRI_CTRL_REG >> 16 ) & 0x3); ++ ctl.q0_w = ((CPU_PRI_CTRL_REG >> 0 ) & 0x7); ++ ctl.q1_w = ((CPU_PRI_CTRL_REG >> 4 ) & 0x7); ++ ctl.q2_w = ((CPU_PRI_CTRL_REG >> 8 ) & 0x7); ++ ctl.q3_w = ((CPU_PRI_CTRL_REG >> 12 ) & 0x7); ++ break; ++ } ++ case 4: ++ { ++ ctl.sch_mode = ((HNAT_PRI_CTRL_REG >> 16 ) & 0x3); ++ ctl.q0_w = ((HNAT_PRI_CTRL_REG >> 0 ) & 0x7); ++ ctl.q1_w = ((HNAT_PRI_CTRL_REG >> 4 ) & 0x7); ++ ctl.q2_w = ((HNAT_PRI_CTRL_REG >> 8 ) & 0x7); ++ ctl.q3_w = ((HNAT_PRI_CTRL_REG >> 12 ) & 0x7); ++ break; ++ } ++ } ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXQueueWeightEntry)) ) ++ return -EFAULT; ++ ++ return CAVM_OK; ++} ++ ++int set_rate_limit(struct ifreq *ifr) ++{ ++ CNS3XXXRateLimitEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXRateLimitEntry)) ) ++ return -EFAULT; ++ switch (ctl.which_port) ++ { ++ case 0: ++ { ++ RATE_CTRL_REG &= (~(0x7f << 8)); ++ RATE_CTRL_REG |= ( ctl.band_width << 8); ++ RATE_CTRL_REG &= (~(0x3)); ++ RATE_CTRL_REG |= ctl.base_rate; ++ return 0; ++ } ++ case 1: ++ { ++ RATE_CTRL_REG &= (~(0x7f << 16)); ++ RATE_CTRL_REG |= ( ctl.band_width << 16); ++ RATE_CTRL_REG &= (~(0x3 << 2)); ++ RATE_CTRL_REG |= (ctl.base_rate << 2); ++ return 0; ++ } ++ case 2: ++ { ++ RATE_CTRL_REG &= (~(0x7f << 24)); ++ RATE_CTRL_REG |= ( ctl.band_width << 24); ++ RATE_CTRL_REG &= (~(0x3 << 4)); ++ RATE_CTRL_REG |= (ctl.base_rate << 4); ++ return 0; ++ } ++ case 3: // port 0 extra dma ++ { ++ TC_CTRL_REG &= (~0x7f); ++ TC_CTRL_REG |= ctl.band_width; ++ RATE_CTRL_REG &= (~(0x3 << 6)); ++ RATE_CTRL_REG |= (ctl.base_rate << 6); ++ return 0; ++ } ++ default: ++ { ++ return -EFAULT; ++ } ++ } ++} ++ ++int get_rate_limit(struct ifreq *ifr) ++{ ++ CNS3XXXRateLimitEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXRateLimitEntry)) ) ++ return -EFAULT; ++ switch (ctl.which_port) ++ { ++ case 0: ++ { ++ ctl.band_width = (RATE_CTRL_REG >> 8) & 0x7f; ++ ctl.base_rate = RATE_CTRL_REG & 0x3; ++ break; ++ } ++ case 1: ++ { ++ ctl.band_width = (RATE_CTRL_REG >> 16) & 0x7f; ++ ctl.base_rate = (RATE_CTRL_REG >> 2) & 0x3; ++ break; ++ } ++ case 2: ++ { ++ ctl.band_width = (RATE_CTRL_REG >> 24) & 0x7f; ++ ctl.base_rate = (RATE_CTRL_REG >> 4) & 0x3; ++ break; ++ } ++ case 3: // port 0 extra dma ++ { ++ ctl.band_width = (TC_CTRL_REG) & 0x7f; ++ ctl.base_rate = (RATE_CTRL_REG >> 6) & 0x3; ++ break; ++ } ++ default: ++ { ++ return -EFAULT; ++ } ++ } ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXRateLimitEntry)) ) ++ return -EFAULT; ++ ++ return CAVM_OK; ++} ++ ++int set_fc(struct ifreq *ifr) ++{ ++ CNS3XXXFCEntry ctl; ++ u32 port_offset[]={0x0c, 0x10, 0x18, 0x14}; // 0x14 is cpu port offset ++ u32 val=0; ++ ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXFCEntry)) ) ++ return -EFAULT; ++ ++ val = SWITCH_REG_VALUE(port_offset[ctl.port]); ++ if (ctl.port == 3) { // cpu port, only can set rx fc ++ val &= (~(1 << 31)); ++ if (ctl.fc_en) ++ val |= (1 << 31); ++ } else { ++ val &= (~(1 << 11)); // disable rx fc ++ val &= (~(1 << 12)); // disable tx fc ++ val |= (ctl.fc_en << 11); ++ } ++ ++ SWITCH_REG_VALUE(port_offset[ctl.port]) = val; ++ return CAVM_OK; ++} ++ ++int get_fc(struct ifreq *ifr) ++{ ++ CNS3XXXFCEntry ctl; ++ u32 port_offset[]={0x0c, 0x10, 0x18, 0x14}; // 0x14 is cpu port offset ++ u32 val=0; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXFCEntry)) ) ++ return -EFAULT; ++ ++ val = SWITCH_REG_VALUE(port_offset[ctl.port]); ++ if (ctl.port == 3) { // cpu port, only can set rx fc ++ ctl.fc_en = ((val >> 31) & 1); ++ } else { ++ ctl.fc_en = ((val >> 11) & 3); ++ ++ } ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXFCEntry)) ) ++ return -EFAULT; ++ ++ return CAVM_OK; ++} ++ ++int set_ivl(struct ifreq *ifr) ++{ ++ CNS3XXXIVLEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXIVLEntry)) ) ++ return -EFAULT; ++ ++ cns3xxx_ivl(ctl.enable); ++ ++ return CAVM_OK; ++} ++ ++int get_ivl(struct ifreq *ifr) ++{ ++ CNS3XXXIVLEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXIVLEntry)) ) ++ return -EFAULT; ++ ++ ctl.enable = ((MAC_GLOB_CFG_REG >> 7) & 0x1); ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXIVLEntry)) ) ++ return -EFAULT; ++ ++ return CAVM_OK; ++} ++ ++int set_wan_port(struct ifreq *ifr) ++{ ++ CNS3XXXWANPortEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXWANPortEntry)) ) ++ return -EFAULT; ++ VLAN_CFG &= (~(0x1f << 8)); ++ VLAN_CFG |= (ctl.wan_port << 8); ++ ++ return CAVM_OK; ++} ++int get_wan_port(struct ifreq *ifr) ++{ ++ CNS3XXXWANPortEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXWANPortEntry)) ) ++ return -EFAULT; ++ ++ ctl.wan_port = ((VLAN_CFG >> 8) & 0x1f); ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXWANPortEntry)) ) ++ return -EFAULT; ++ ++ return CAVM_OK; ++} ++ ++int set_pvid(struct ifreq *ifr) ++{ ++ CNS3XXXPVIDEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXPVIDEntry)) ) ++ return -EFAULT; ++ cns3xxx_set_pvid(ctl.which_port, ctl.pvid); ++ ++ return CAVM_OK; ++} ++ ++int get_pvid(struct ifreq *ifr) ++{ ++ CNS3XXXPVIDEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXPVIDEntry)) ) ++ return -EFAULT; ++ ++ ctl.pvid = cns3xxx_get_pvid(ctl.which_port); ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXPVIDEntry)) ) ++ return -EFAULT; ++ return CAVM_OK; ++} ++ ++int set_qa(struct ifreq *ifr) ++{ ++ CNS3XXXQAEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXQAEntry)) ) ++ return -EFAULT; ++ ++ MAC_GLOB_CFG_EXT_REG &= ~(0x7 << 27); ++ MAC_GLOB_CFG_EXT_REG |= (ctl.qa << 27); ++ ++ return CAVM_OK; ++} ++ ++int get_qa(struct ifreq *ifr) ++{ ++ CNS3XXXQAEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXQAEntry)) ) ++ return -EFAULT; ++ ++ ctl.qa = (MAC_GLOB_CFG_EXT_REG >> 27) & 0x7; ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXQAEntry)) ) ++ return -EFAULT; ++ return CAVM_OK; ++} ++ ++int get_packet_max_len(struct ifreq *ifr) ++{ ++ CNS3XXXMaxLenEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXMaxLenEntry)) ) ++ return -EFAULT; ++ ++ ctl.max_len = (PHY_AUTO_ADDR_REG >> 30) & 0x3; ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXMaxLenEntry)) ) ++ return -EFAULT; ++ return CAVM_OK; ++} ++ ++int set_packet_max_len(struct ifreq *ifr) ++{ ++ CNS3XXXMaxLenEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXMaxLenEntry)) ) ++ return -EFAULT; ++ ++ PHY_AUTO_ADDR_REG &= (~(3 << 30)); ++ PHY_AUTO_ADDR_REG |= (ctl.max_len << 30); ++ ++ return CAVM_OK; ++} ++ ++int set_udp_range(struct ifreq *ifr) ++{ ++ CNS3XXXUdpRangeEtypeControl conf; ++ ++ if (copy_from_user(&conf, ifr->ifr_data, sizeof(CNS3XXXUdpRangeEtypeControl)) ) ++ return -EFAULT; ++ ++ switch (conf.udp_range_num) ++ { ++ case 0: ++ { ++ UDP_RANGE0_REG = 0; ++ UDP_RANGE0_REG |= conf.port_start; ++ UDP_RANGE0_REG |= (conf.port_end << 16); ++ break; ++ } ++ case 1: ++ { ++ UDP_RANGE1_REG = 0; ++ UDP_RANGE1_REG |= conf.port_start; ++ UDP_RANGE1_REG |= (conf.port_end << 16); ++ break; ++ } ++ case 2: ++ { ++ UDP_RANGE2_REG = 0; ++ UDP_RANGE2_REG |= conf.port_start; ++ UDP_RANGE2_REG |= (conf.port_end << 16); ++ break; ++ } ++ case 3: ++ { ++ UDP_RANGE3_REG = 0; ++ UDP_RANGE3_REG |= conf.port_start; ++ UDP_RANGE3_REG |= (conf.port_end << 16); ++ break; ++ } ++ } ++ ++ return CAVM_OK; ++} ++ ++int get_udp_range(struct ifreq *ifr) ++{ ++ CNS3XXXUdpRangeEtypeControl conf; ++ ++ if (copy_from_user(&conf, ifr->ifr_data, sizeof(CNS3XXXUdpRangeEtypeControl)) ) ++ return -EFAULT; ++ ++ switch (conf.udp_range_num) ++ { ++ case 0: ++ { ++ conf.port_start = (UDP_RANGE0_REG & 0xffff); ++ conf.port_end = ((UDP_RANGE0_REG >> 16 )& 0xffff); ++ break; ++ } ++ case 1: ++ { ++ conf.port_start = (UDP_RANGE1_REG & 0xffff); ++ conf.port_end = ((UDP_RANGE1_REG >> 16 )& 0xffff); ++ break; ++ } ++ case 2: ++ { ++ conf.port_start = (UDP_RANGE2_REG & 0xffff); ++ conf.port_end = ((UDP_RANGE2_REG >> 16 )& 0xffff); ++ break; ++ } ++ case 3: ++ { ++ conf.port_start = (UDP_RANGE3_REG & 0xffff); ++ conf.port_end = ((UDP_RANGE3_REG >> 16 )& 0xffff); ++ break; ++ } ++ } ++ ++ if (copy_to_user(ifr->ifr_data, &conf, sizeof(CNS3XXXEtypeControl)) ) ++ return -EFAULT; ++ ++ return CAVM_OK; ++} ++ ++int get_etype(struct ifreq *ifr) ++{ ++ CNS3XXXEtypeControl conf; ++ ++ if (copy_from_user(&conf, ifr->ifr_data, sizeof(CNS3XXXEtypeControl)) ) ++ return -EFAULT; ++ switch (conf.etype_num) ++ { ++ case 0: ++ { ++ conf.val = (ETYPE1_ETYPE0_REG & 0xffff); ++ conf.pri = (PRIO_ETYPE_UDP_REG & 0x7); ++ break; ++ } ++ case 1: ++ { ++ conf.val = ((ETYPE1_ETYPE0_REG >> 16 )& 0xffff); ++ conf.pri = ((PRIO_ETYPE_UDP_REG >> 4) & 0x7); ++ break; ++ } ++ case 2: ++ { ++ conf.val = (ETYPE3_ETYPE2_REG & 0xffff); ++ conf.pri = ((PRIO_ETYPE_UDP_REG >> 8) & 0x7); ++ break; ++ } ++ case 3: ++ { ++ conf.val = ((ETYPE3_ETYPE2_REG >> 16 )& 0xffff); ++ conf.pri = ((PRIO_ETYPE_UDP_REG >> 12) & 0x7); ++ break; ++ } ++ } ++ if (copy_to_user(ifr->ifr_data, &conf, sizeof(CNS3XXXEtypeControl)) ) ++ return -EFAULT; ++ ++ return CAVM_OK; ++} ++ ++int set_etype(struct ifreq *ifr) ++{ ++ CNS3XXXEtypeControl conf; ++ ++ if (copy_from_user(&conf, ifr->ifr_data, sizeof(CNS3XXXEtypeControl)) ) ++ return -EFAULT; ++ switch (conf.etype_num) ++ { ++ case 0: ++ { ++ ETYPE1_ETYPE0_REG &= (~0xffff); ++ ETYPE1_ETYPE0_REG |= conf.val; ++ ++ PRIO_ETYPE_UDP_REG &= (~7); ++ PRIO_ETYPE_UDP_REG |= (conf.pri); ++ break; ++ } ++ case 1: ++ { ++ ETYPE1_ETYPE0_REG &= (~(0xffff << 16)); ++ ETYPE1_ETYPE0_REG |= (conf.val << 16); ++ ++ PRIO_ETYPE_UDP_REG &= (~(7 << 4)); ++ PRIO_ETYPE_UDP_REG |= (conf.pri << 4); ++ break; ++ } ++ case 2: ++ { ++ ETYPE3_ETYPE2_REG &= (~0xffff); ++ ETYPE3_ETYPE2_REG |= conf.val; ++ ++ PRIO_ETYPE_UDP_REG &= (~(7 << 8)); ++ PRIO_ETYPE_UDP_REG |= (conf.pri << 8); ++ break; ++ } ++ case 3: ++ { ++ ETYPE3_ETYPE2_REG &= (~(0xffff << 16)); ++ ETYPE3_ETYPE2_REG |= (conf.val << 16); ++ ++ PRIO_ETYPE_UDP_REG &= (~(7 << 12)); ++ PRIO_ETYPE_UDP_REG |= (conf.pri << 12); ++ break; ++ } ++ } ++ return CAVM_OK; ++} ++ ++int get_pri_ip_dscp(struct ifreq *ifr) ++{ ++ CNS3XXXPriIpDscpControl conf; ++ ++ if (copy_from_user(&conf, ifr->ifr_data, sizeof(CNS3XXXPriIpDscpControl)) ) ++ return -EFAULT; ++ ++ if ( 0 <= conf.ip_dscp_num && conf.ip_dscp_num <= 7) { ++ conf.pri = ((PRIO_IPDSCP_7_0_REG >> (conf.ip_dscp_num * 4)) & 0x7); ++ } else if ( 8 <= conf.ip_dscp_num && conf.ip_dscp_num <= 15) { ++ conf.pri = ((PRIO_IPDSCP_15_8_REG >> ((conf.ip_dscp_num-8) * 4)) & 0x7); ++ } else if ( 16 <= conf.ip_dscp_num && conf.ip_dscp_num <= 23) { ++ conf.pri = ((PRIO_IPDSCP_23_16_REG >> ((conf.ip_dscp_num-16) * 4)) & 0x7); ++ } else if ( 24 <= conf.ip_dscp_num && conf.ip_dscp_num <= 31) { ++ conf.pri = ((PRIO_IPDSCP_31_24_REG >> ((conf.ip_dscp_num-24) * 4)) & 0x7); ++ } else if ( 32 <= conf.ip_dscp_num && conf.ip_dscp_num <= 39) { ++ conf.pri = ((PRIO_IPDSCP_39_32_REG >> ((conf.ip_dscp_num-32) * 4)) & 0x7); ++ } else if ( 40 <= conf.ip_dscp_num && conf.ip_dscp_num <= 47) { ++ conf.pri = ((PRIO_IPDSCP_47_40_REG >> ((conf.ip_dscp_num-40) * 4)) & 0x7); ++ } else if ( 48 <= conf.ip_dscp_num && conf.ip_dscp_num <= 55) { ++ conf.pri = ((PRIO_IPDSCP_55_48_REG >> ((conf.ip_dscp_num-48) * 4)) & 0x7); ++ } else if ( 56 <= conf.ip_dscp_num && conf.ip_dscp_num <= 63) { ++ conf.pri = ((PRIO_IPDSCP_63_56_REG >> ((conf.ip_dscp_num-56) * 4)) & 0x7); ++ } else { ++ return CAVM_ERR; ++ } ++ ++ ++ if (copy_to_user(ifr->ifr_data, &conf, sizeof(CNS3XXXPriIpDscpControl)) ) ++ return -EFAULT; ++ return CAVM_OK; ++} ++ ++ ++int set_pri_ip_dscp(struct ifreq *ifr) ++{ ++ CNS3XXXPriIpDscpControl conf; ++ ++ if (copy_from_user(&conf, ifr->ifr_data, sizeof(CNS3XXXPriIpDscpControl)) ) ++ return -EFAULT; ++ ++ if ( 0 <= conf.ip_dscp_num && conf.ip_dscp_num <= 7) { ++ PRIO_IPDSCP_7_0_REG &= (~(0x7 << (conf.ip_dscp_num * 4) ) ); ++ PRIO_IPDSCP_7_0_REG |= (conf.pri << (conf.ip_dscp_num * 4)); ++ } else if ( 8 <= conf.ip_dscp_num && conf.ip_dscp_num <= 15) { ++ PRIO_IPDSCP_15_8_REG &= (~(0x7 << ((conf.ip_dscp_num-8) * 4) ) ); ++ PRIO_IPDSCP_15_8_REG |= (conf.pri << ((conf.ip_dscp_num-8) * 4)); ++ } else if ( 16 <= conf.ip_dscp_num && conf.ip_dscp_num <= 23) { ++ PRIO_IPDSCP_23_16_REG &= (~(0x7 << ((conf.ip_dscp_num-16) * 4) ) ); ++ PRIO_IPDSCP_23_16_REG |= (conf.pri << ((conf.ip_dscp_num-16) * 4)); ++ ++ } else if ( 24 <= conf.ip_dscp_num && conf.ip_dscp_num <= 31) { ++ PRIO_IPDSCP_31_24_REG &= (~(0x7 << ((conf.ip_dscp_num-24) * 4) ) ); ++ PRIO_IPDSCP_31_24_REG |= (conf.pri << ((conf.ip_dscp_num-24) * 4)); ++ ++ } else if ( 32 <= conf.ip_dscp_num && conf.ip_dscp_num <= 39) { ++ PRIO_IPDSCP_39_32_REG &= (~(0x7 << ((conf.ip_dscp_num-32) * 4) ) ); ++ PRIO_IPDSCP_39_32_REG |= (conf.pri << ((conf.ip_dscp_num-32) * 4)); ++ ++ } else if ( 40 <= conf.ip_dscp_num && conf.ip_dscp_num <= 47) { ++ PRIO_IPDSCP_47_40_REG &= (~(0x7 << ((conf.ip_dscp_num-40) * 4) ) ); ++ PRIO_IPDSCP_47_40_REG |= (conf.pri << ((conf.ip_dscp_num-40) * 4)); ++ } else if ( 48 <= conf.ip_dscp_num && conf.ip_dscp_num <= 55) { ++ PRIO_IPDSCP_55_48_REG &= (~(0x7 << ((conf.ip_dscp_num-48) * 4) ) ); ++ PRIO_IPDSCP_55_48_REG |= (conf.pri << ((conf.ip_dscp_num-48) * 4)); ++ } else if ( 56 <= conf.ip_dscp_num && conf.ip_dscp_num <= 63) { ++ PRIO_IPDSCP_63_56_REG &= (~(0x7 << ((conf.ip_dscp_num-56) * 4) ) ); ++ PRIO_IPDSCP_63_56_REG |= (conf.pri << ((conf.ip_dscp_num-56) * 4)); ++ } else { ++ return CAVM_ERR; ++ } ++ return CAVM_OK; ++} ++ ++ ++int bcm53115M_reg_read_ioctl(struct ifreq *ifr) ++{ ++ int bcm53115M_reg_read(int page, int offset, u8 *buf, int len); ++ CNS3XXXBCM53115M conf; ++ int __init_or_module gpio_direction_output(unsigned int pin, unsigned int state); ++ ++ ++ if (copy_from_user(&conf, ifr->ifr_data, sizeof(CNS3XXXBCM53115M)) ) ++ return -EFAULT; ++ printk("conf.page: %x\n", conf.page); ++ printk("conf.offset: %x\n", conf.offset); ++ printk("conf.data_len: %x\n", conf.data_len); ++ switch (conf.data_len) ++ { ++ case 1: ++ { ++ bcm53115M_reg_read(conf.page, conf.offset, (u8 *)&conf.u8_val, 1); ++ printk("conf.u8_val: %x\n", conf.u8_val); ++ break; ++ } ++ case 2: ++ { ++ bcm53115M_reg_read(conf.page, conf.offset, (u8 *)&conf.u16_val, 2); ++ printk("conf.u16_val: %x\n", conf.u16_val); ++ break; ++ } ++ case 4: ++ { ++ bcm53115M_reg_read(conf.page, conf.offset, (u8 *)&conf.u32_val, 4); ++ printk("conf.u32_val: %x\n", conf.u32_val); ++ break; ++ } ++ default: ++ { ++ printk("[kernel mode]: don't support date length: %d\n", conf.data_len); ++ } ++ } ++ ++ ++ ++ if (copy_to_user(ifr->ifr_data, &conf, sizeof(CNS3XXXBCM53115M)) ) ++ return -EFAULT; ++ return CAVM_OK; ++} ++ ++int bcm53115M_reg_write_ioctl(struct ifreq *ifr) ++{ ++ int bcm53115M_reg_write(int page, int offset, u8 *buf, int len); ++ CNS3XXXBCM53115M conf; ++ ++ if (copy_from_user(&conf, ifr->ifr_data, sizeof(CNS3XXXBCM53115M)) ) ++ return -EFAULT; ++ ++ switch (conf.data_len) ++ { ++ case 1: ++ { ++ bcm53115M_reg_write(conf.page, conf.offset, (u8 *)&conf.u8_val, 1); ++ break; ++ } ++ case 2: ++ { ++ bcm53115M_reg_write(conf.page, conf.offset, (u8 *)&conf.u16_val, 2); ++ break; ++ } ++ case 4: ++ { ++ bcm53115M_reg_write(conf.page, conf.offset, (u8 *)&conf.u32_val, 4); ++ break; ++ } ++ default: ++ { ++ printk("[kernel mode]: don't support date length: %d\n", conf.data_len); ++ } ++ } ++ return CAVM_OK; ++} ++ ++#if 0 ++int get_rxring(struct ifreq *ifr) ++{ ++ CNS3XXXRingStatus conf; ++ ++ if (copy_from_user(&conf, ifr->ifr_data, sizeof(CNS3XXXRingStatus)) ) ++ return -EFAULT; ++ conf.rx_ring=g_ring_info.rx_ring; ++ conf.tx_ring=0; ++ if (copy_to_user(ifr->ifr_data, &conf, sizeof(CNS3XXXRingStatus)) ) ++ return -EFAULT; ++} ++#endif ++ ++int dump_mib_counter(struct ifreq *ifr) ++{ ++ CNS3XXXMIBCounter conf; ++ int addr=0,i=0; ++ ++ if (copy_from_user(&conf, ifr->ifr_data, sizeof(CNS3XXXMIBCounter)) ) ++ return -EFAULT; ++ ++ for (addr=0x300; addr <= 0x334 ; addr+=4) ++ conf.mib[i++]=SWITCH_REG_VALUE(addr); ++ for (addr=0x400; addr <= 0x434 ; addr+=4) ++ conf.mib[i++]=SWITCH_REG_VALUE(addr); ++ for (addr=0x600; addr <= 0x634 ; addr+=4) ++ conf.mib[i++]=SWITCH_REG_VALUE(addr); ++ // cpu mib counter ++ for (addr=0x500; addr <= 0x528 ; addr+=4) ++ conf.mib[i++]=SWITCH_REG_VALUE(addr); ++ conf.mib_len=i; ++ if (copy_to_user(ifr->ifr_data, &conf, sizeof(CNS3XXXMIBCounter)) ) ++ return -EFAULT; ++ return 0; ++} ++ ++// reference e100.c ++int cns3xxx_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) ++{ ++ CNS3XXXIoctlCmd ioctl_cmd; ++ ++ //printk("cns3xxx_do_ioctl begin\n"); ++ ++ if (cmd != SIOCDEVPRIVATE) { ++ return -EOPNOTSUPP; ++ } ++ if (copy_from_user(&ioctl_cmd, ifr->ifr_data, sizeof(CNS3XXXIoctlCmd))) ++ return -EFAULT; ++ ++ //printk("ioctl_cmd: %d\n", ioctl_cmd); ++ switch (ioctl_cmd) { ++ case CNS3XXX_ARP_REQUEST_SET: ++ { ++ CNS3XXXArpRequestControl ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXArpRequestControl)) ) ++ return -EFAULT; ++ ++ (ctl.val==0) ? (MAC_GLOB_CFG_REG &= (~(1 << 23)) ): (MAC_GLOB_CFG_REG |= (1 << 23) ); ++ ++ } ++ ++ case CNS3XXX_ARP_REQUEST_GET: ++ { ++ CNS3XXXArpRequestControl ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXArpRequestControl)) ) ++ return -EFAULT; ++ ++ ctl.val = ((MAC_GLOB_CFG_REG >> 23) & 1); ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXArpRequestControl)) ) ++ return -EFAULT; ++ return CAVM_OK; ++ } ++ ++ case CNS3XXX_HOL_PREVENT_SET: ++ { ++ CNS3XXXHOLPreventControl ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXHOLPreventControl)) ) ++ return -EFAULT; ++ (ctl.enable == 1) ? (TC_CTRL_REG |= (1 << 29)) : (TC_CTRL_REG &= (~(1 << 29))) ; ++ ++ return CAVM_OK; ++ } ++ case CNS3XXX_HOL_PREVENT_GET: ++ { ++ CNS3XXXHOLPreventControl ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXHOLPreventControl)) ) ++ return -EFAULT; ++ ++ ctl.enable = ((TC_CTRL_REG >> 29) & 0x1); ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXHOLPreventControl)) ) ++ return -EFAULT; ++ return CAVM_OK; ++ } ++ ++ // for S component or C conponent ++ case CNS3XXX_BRIDGE_SET: ++ { ++ CNS3XXXBridgeControl ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXBridgeControl)) ) ++ return -EFAULT; ++ (ctl.type == 1) ? (VLAN_CFG |= (1 << 1)) : (VLAN_CFG &= (~(1 << 1))) ; ++ ++ ++ } ++ case CNS3XXX_BRIDGE_GET: ++ { ++ CNS3XXXBridgeControl ctl; ++ ++ ctl.type = ((VLAN_CFG >> 1) & 0x1); ++ printk("[kernel mode] ctl.type: %d\n", ctl.type); ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXBridgeControl)) ) ++ return -EFAULT; ++ ++ return CAVM_OK; ++ } ++ ++ case CNS3XXX_PORT_NEIGHBOR_SET: ++ { ++ CNS3XXXPortNeighborControl ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXPortNeighborControl)) ) ++ return -EFAULT; ++ switch (ctl.which_port) ++ { ++ case 0: ++ { ++ (ctl.type == 1) ? (VLAN_CFG |= (1 << 4)) : (VLAN_CFG &= (~(1 << 4))) ; ++ return 0; ++ } ++ case 1: ++ { ++ (ctl.type == 1) ? (VLAN_CFG |= (1 << 5)) : (VLAN_CFG &= (~(1 << 5))) ; ++ return 0; ++ } ++ case 2: ++ { ++ (ctl.type == 1) ? (VLAN_CFG |= (1 << 7)) : (VLAN_CFG &= (~(1 << 7))) ; ++ return 0; ++ } ++ case 3: // cpu port ++ { ++ (ctl.type == 1) ? (VLAN_CFG |= (1 << 6)) : (VLAN_CFG &= (~(1 << 6))) ; ++ return 0; ++ } ++ default: ++ return -EFAULT; ++ } ++ ++ } ++ ++ case CNS3XXX_PORT_NEIGHBOR_GET: ++ { ++ CNS3XXXPortNeighborControl ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXPortNeighborControl)) ) ++ return -EFAULT; ++ switch (ctl.which_port) ++ { ++ case 0: ++ { ++ ctl.type = ((VLAN_CFG >> 4 ) & 0x1); ++ break; ++ } ++ case 1: ++ { ++ ctl.type = ((VLAN_CFG >> 5 ) & 0x1); ++ break; ++ } ++ case 2: ++ { ++ ctl.type = ((VLAN_CFG >> 7 ) & 0x1); ++ break; ++ } ++ case 3: // cpu port ++ { ++ ctl.type = ((VLAN_CFG >> 6 ) & 0x1); ++ break; ++ } ++ } ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXPortNeighborControl)) ) ++ return -EFAULT; ++ ++ return CAVM_OK; ++ } ++ ++ case CNS3XXX_VLAN_TABLE_LOOKUP: ++ { ++ CNS3XXXVLANTableEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXVLANTableEntry)) ) ++ return -EFAULT; ++ if (cns3xxx_vlan_table_lookup(&ctl.entry) == CAVM_NOT_FOUND) { ++ return CAVM_NOT_FOUND; ++ } ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXVLANTableEntry))) ++ return -EFAULT; ++ ++ return CAVM_FOUND; ++ } ++ case CNS3XXX_VLAN_TABLE_READ: ++ { ++ CNS3XXXVLANTableEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXVLANTableEntry)) ) ++ { ++ return -EFAULT; ++ } ++ cns3xxx_vlan_table_read(&ctl.entry); ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXVLANTableEntry))) ++ return -EFAULT; ++ ++ return 0; ++ } ++ case CNS3XXX_VLAN_TABLE_ADD: ++ { ++ CNS3XXXVLANTableEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXVLANTableEntry)) ) ++ return -EFAULT; ++ cns3xxx_vlan_table_add(&ctl.entry); ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXVLANTableEntry))) ++ return -EFAULT; ++ ++ return 0; ++ } ++ ++ case CNS3XXX_ARL_TABLE_ADD: ++ { ++ CNS3XXXARLTableEntry ctl; ++ ++ printk("[kernel mode] CNS3XXX_ARL_TABLE_ADD\n"); ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXARLTableEntry)) ) ++ return -EFAULT; ++ cns3xxx_arl_table_add(&ctl.entry); ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXARLTableEntry))) ++ return -EFAULT; ++ ++ return 0; ++ } ++ ++ ++ case CNS3XXX_ARL_TABLE_DEL: ++ { ++ CNS3XXXARLTableEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXARLTableEntry)) ) ++ return -EFAULT; ++ cns3xxx_arl_table_invalid(&ctl.entry); ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXARLTableEntry))) ++ return -EFAULT; ++ ++ return 0; ++ } ++ case CNS3XXX_VLAN_TABLE_DEL: ++ { ++ CNS3XXXARLTableEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXARLTableEntry)) ) ++ return -EFAULT; ++ cns3xxx_arl_table_invalid(&ctl.entry); ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXARLTableEntry))) ++ return -EFAULT; ++ ++ return CAVM_FOUND; ++ } ++ ++ case CNS3XXX_ARL_TABLE_SEARCH: ++ { ++ CNS3XXXARLTableEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXARLTableEntry)) ) ++ return -EFAULT; ++ if (cns3xxx_arl_table_search(&ctl.entry) == CAVM_NOT_FOUND){ ++ printk("[kernel mode] not found\n"); ++ return CAVM_NOT_FOUND; ++ } ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXARLTableEntry))) ++ return -EFAULT; ++ ++ return CAVM_FOUND; ++ } ++ case CNS3XXX_ARL_IS_TABLE_END: ++ { ++ CNS3XXXARLTableEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXARLTableEntry)) ) ++ return -EFAULT; ++ if (cns3xxx_is_arl_table_end() == CAVM_ERR) ++ return CAVM_ERR; ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXARLTableEntry))) ++ return -EFAULT; ++ ++ return CAVM_OK; ++ } ++ ++ case CNS3XXX_ARL_TABLE_SEARCH_AGAIN: ++ { ++ CNS3XXXARLTableEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXARLTableEntry)) ) ++ return -EFAULT; ++ if (cns3xxx_arl_table_search_again(&ctl.entry) == CAVM_NOT_FOUND) ++ return CAVM_NOT_FOUND; ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXARLTableEntry))) ++ return -EFAULT; ++ ++ return CAVM_FOUND; ++ } ++ ++ case CNS3XXX_ARL_TABLE_FLUSH: ++ { ++ CNS3XXXARLTableEntry ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXARLTableEntry)) ) ++ return -EFAULT; ++ ++ cns3xxx_arl_table_flush(); ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXARLTableEntry))) ++ return -EFAULT; ++ ++ return CAVM_FOUND; ++ } ++ ++ ++ ++ case CNS3XXX_ARL_TABLE_LOOKUP: ++ { ++ CNS3XXXARLTableEntry ctl; ++ ++ ++ printk("[kernel mode] in CNS3XXX_ARL_TABLE_LOOKUP\n"); ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXARLTableEntry)) ) ++ return -EFAULT; ++ if (cns3xxx_arl_table_lookup(&ctl.entry) == CAVM_NOT_FOUND) ++ return CAVM_NOT_FOUND; ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXARLTableEntry))) ++ return -EFAULT; ++ ++ return CAVM_FOUND; ++ } ++ ++ case CNS3XXX_TC_SET: ++ { ++ CNS3XXXTrafficClassControl ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXTrafficClassControl)) ) ++ return -EFAULT; ++ TC_CTRL_REG &= (~(0x3 << 30)); ++ TC_CTRL_REG |= (ctl.tc << 30); ++ return CAVM_OK; ++ } ++ case CNS3XXX_TC_GET: ++ { ++ CNS3XXXTrafficClassControl ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXTrafficClassControl)) ) ++ return -EFAULT; ++ ++ ctl.tc = ((TC_CTRL_REG >> 30) & 0x3); ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXTrafficClassControl)) ) ++ return -EFAULT; ++ ++ return CAVM_OK; ++ } ++ ++ case CNS3XXX_PRI_CTRL_SET: ++ { ++ CNS3XXXPriCtrlControl ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXPriCtrlControl)) ) ++ return -EFAULT; ++ ++ switch (ctl.which_port) ++ { ++ case 0: ++ { ++ MAC0_PRI_CTRL_REG &= (~(0x7 << 24)); ++ MAC0_PRI_CTRL_REG &= (~(0xf << 18)); ++ ++ MAC0_PRI_CTRL_REG |= (ctl.port_pri << 24); ++ ++ MAC0_PRI_CTRL_REG |= (ctl.ether_pri_en << 18); ++ MAC0_PRI_CTRL_REG |= (ctl.vlan_pri_en << 19); ++ MAC0_PRI_CTRL_REG |= (ctl.dscp_pri_en << 20); ++ MAC0_PRI_CTRL_REG |= (ctl.udp_pri_en << 21); ++ break; ++ } ++ case 1: ++ { ++ MAC1_PRI_CTRL_REG &= (~(0x7 << 24)); ++ MAC1_PRI_CTRL_REG &= (~(0xf << 18)); ++ ++ MAC1_PRI_CTRL_REG |= (ctl.port_pri << 24); ++ ++ MAC1_PRI_CTRL_REG |= (ctl.ether_pri_en << 18); ++ MAC1_PRI_CTRL_REG |= (ctl.vlan_pri_en << 19); ++ MAC1_PRI_CTRL_REG |= (ctl.dscp_pri_en << 20); ++ MAC1_PRI_CTRL_REG |= (ctl.udp_pri_en << 21); ++ break; ++ } ++ case 2: ++ { ++ MAC2_PRI_CTRL_REG &= (~(0x7 << 24)); ++ MAC2_PRI_CTRL_REG &= (~(0xf << 18)); ++ ++ MAC2_PRI_CTRL_REG |= (ctl.port_pri << 24); ++ ++ MAC2_PRI_CTRL_REG |= (ctl.ether_pri_en << 18); ++ MAC2_PRI_CTRL_REG |= (ctl.vlan_pri_en << 19); ++ MAC2_PRI_CTRL_REG |= (ctl.dscp_pri_en << 20); ++ MAC2_PRI_CTRL_REG |= (ctl.udp_pri_en << 21); ++ break; ++ } ++ case 3: // cpu ++ { ++ printk("[kernel mode] CPU_PRI_CTRL_REG: %#x\n", CPU_PRI_CTRL_REG); ++ CPU_PRI_CTRL_REG &= (~(0x7 << 24)); ++ CPU_PRI_CTRL_REG &= (~(0xf << 18)); ++ ++ CPU_PRI_CTRL_REG |= (ctl.port_pri << 24); ++ ++ CPU_PRI_CTRL_REG |= (ctl.ether_pri_en << 18); ++ CPU_PRI_CTRL_REG |= (ctl.vlan_pri_en << 19); ++ CPU_PRI_CTRL_REG |= (ctl.dscp_pri_en << 20); ++ CPU_PRI_CTRL_REG |= (ctl.udp_pri_en << 21); ++ break; ++ } ++ } ++ ++ return CAVM_OK; ++ } ++ ++ case CNS3XXX_PRI_CTRL_GET: ++ { ++ CNS3XXXPriCtrlControl ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXPriCtrlControl)) ) ++ return -EFAULT; ++ ++ ++ if (copy_to_user(ifr->ifr_data, &ctl, sizeof(CNS3XXXPriCtrlControl)) ) ++ return -EFAULT; ++ ++ return CAVM_OK; ++ } ++ ++ case CNS3XXX_DMA_RING_CTRL_SET: ++ { ++ CNS3XXXDmaRingCtrlControl ctl; ++ ++ if (copy_from_user(&ctl, ifr->ifr_data, sizeof(CNS3XXXDmaRingCtrlControl)) ) ++ return -EFAULT; ++ ++ (ctl.ts_double_ring_en == 0) ? DMA_RING_CTRL_REG &= (~(0x1 << 16)) : (DMA_RING_CTRL_REG |= (ctl.ts_double_ring_en << 16)); ++ (ctl.fs_double_ring_en == 0) ? DMA_RING_CTRL_REG &= (~(0x1 << 0)) : (DMA_RING_CTRL_REG |= (ctl.fs_double_ring_en << 0)); ++ (ctl.fs_pkt_allocate == 0) ? DMA_RING_CTRL_REG &= (~(0x1 << 1)) : (DMA_RING_CTRL_REG |= (ctl.fs_pkt_allocate << 1)); ++ } ++ ++ case CNS3XXX_PRI_IP_DSCP_SET: ++ { ++ return set_pri_ip_dscp(ifr); ++ } ++ case CNS3XXX_PRI_IP_DSCP_GET: ++ { ++ return get_pri_ip_dscp(ifr); ++ } ++ ++ case CNS3XXX_ETYPE_SET: ++ { ++ return set_etype(ifr); ++ } ++ case CNS3XXX_ETYPE_GET: ++ { ++ return get_etype(ifr); ++ } ++ ++ case CNS3XXX_UDP_RANGE_SET: ++ { ++ return set_udp_range(ifr); ++ } ++ case CNS3XXX_UDP_RANGE_GET: ++ { ++ return get_udp_range(ifr); ++ } ++ ++ case CNS3XXX_RATE_LIMIT_SET: ++ { ++ return set_rate_limit(ifr); ++ } ++ case CNS3XXX_RATE_LIMIT_GET: ++ { ++ return get_rate_limit(ifr); ++ } ++ case CNS3XXX_QUEUE_WEIGHT_SET: ++ { ++ return set_queue_weight(ifr); ++ } ++ case CNS3XXX_QUEUE_WEIGHT_GET: ++ { ++ return get_queue_weight(ifr); ++ } ++ ++ case CNS3XXX_FC_RLS_SET: ++ { ++ return set_fc_rls(ifr); ++ } ++ case CNS3XXX_FC_RLS_GET: ++ { ++ return get_fc_rls(ifr); ++ } ++ ++ case CNS3XXX_FC_SET_SET: ++ { ++ return set_fc_set(ifr); ++ } ++ case CNS3XXX_FC_SET_GET: ++ { ++ return get_fc_set(ifr); ++ } ++ ++ case CNS3XXX_SARL_RLS_SET: ++ { ++ return set_sarl_rls(ifr); ++ } ++ case CNS3XXX_SARL_RLS_GET: ++ { ++ return get_sarl_rls(ifr); ++ } ++ ++ case CNS3XXX_SARL_SET_SET: ++ { ++ return set_sarl_set(ifr); ++ } ++ case CNS3XXX_SARL_SET_GET: ++ { ++ return get_sarl_set(ifr); ++ } ++ ++ case CNS3XXX_SARL_OQ_SET: ++ { ++ return set_sarl_oq(ifr); ++ } ++ case CNS3XXX_SARL_OQ_GET: ++ { ++ return get_sarl_oq(ifr); ++ } ++ ++ case CNS3XXX_SARL_ENABLE_SET: ++ { ++ return set_sarl_enable(ifr); ++ } ++ case CNS3XXX_SARL_ENABLE_GET: ++ { ++ return get_sarl_enable(ifr); ++ } ++ ++ case CNS3XXX_FC_SET: ++ { ++ return set_fc(ifr); ++ } ++ case CNS3XXX_FC_GET: ++ { ++ return get_fc(ifr); ++ } ++ ++ case CNS3XXX_IVL_SET: ++ { ++ return set_ivl(ifr); ++ } ++ case CNS3XXX_IVL_GET: ++ { ++ return get_ivl(ifr); ++ } ++ ++ case CNS3XXX_WAN_PORT_SET: ++ { ++ return set_wan_port(ifr); ++ } ++ case CNS3XXX_WAN_PORT_GET: ++ { ++ return get_wan_port(ifr); ++ } ++ ++ case CNS3XXX_PVID_SET: ++ { ++ return set_pvid(ifr); ++ } ++ case CNS3XXX_PVID_GET: ++ { ++ return get_pvid(ifr); ++ } ++ ++ case CNS3XXX_QA_GET: ++ { ++ return get_qa(ifr); ++ } ++ case CNS3XXX_QA_SET: ++ { ++ return set_qa(ifr); ++ } ++ ++ case CNS3XXX_PACKET_MAX_LEN_GET: ++ { ++ return get_packet_max_len(ifr); ++ } ++ case CNS3XXX_PACKET_MAX_LEN_SET: ++ { ++ return set_packet_max_len(ifr); ++ } ++ ++ case CNS3XXX_BCM53115M_REG_READ: ++ { ++ return bcm53115M_reg_read_ioctl(ifr); ++ } ++ case CNS3XXX_BCM53115M_REG_WRITE: ++ { ++ return bcm53115M_reg_write_ioctl(ifr); ++ } ++ ++#if 0 ++ case CNS3XXX_RXRING_STATUS: ++ { ++ return get_rxring(ifr); ++ } ++#endif ++ case CNS3XXX_DUMP_MIB_COUNTER: ++ { ++ return dump_mib_counter(ifr); ++ } ++ ++ ++ default: ++ { ++ printk("[kernel mode] don't match any command\n"); ++ break; ++ } ++ ++ } // end switch (ioctl_cmd) ++ return 0; ++} ++ ++#ifdef CONFIG_CNS3XXX_NAPI ++static int cns3xxx_poll(struct napi_struct *napi, int budget) ++{ ++ ++ CNS3XXXPrivate *sp = container_of(napi, CNS3XXXPrivate, napi); ++ int work_done = 0; ++ int work_to_do = budget; // define minima value ++ ++ cns3xxx_receive_packet(sp, 0, &work_done, work_to_do); ++ ++ budget -= work_done; ++ ++ if (work_done) { ++ if (test_bit(0, (unsigned long *)&sp->is_qf) == 1){ ++ clear_bit(0, (unsigned long *)&sp->is_qf); ++ enable_rx_dma(sp->ring_index, 1); ++ return 1; ++ } ++ } else { ++ //netif_rx_complete(napi_dev, &sp->napi); ++ napi_complete(napi); ++#ifdef CNS3XXX_USE_MASK ++ cns3xxx_write_pri_mask(0xf0); ++#else ++ if (sp->ring_index == 0) ++ cns3xxx_enable_irq(FSRC_RING0_INTERRUPT_ID); ++ else ++ cns3xxx_enable_irq(FSRC_RING1_INTERRUPT_ID); ++#endif ++ return 0; ++ } ++ ++ return 1; ++} ++#endif ++ ++static struct net_device_stats *cns3xxx_get_stats(struct net_device *dev) ++{ ++ CNS3XXXPrivate *priv = netdev_priv(dev); ++ ++ return &priv->stats; ++} ++ ++static int cns3xxx_change_mtu(struct net_device *dev, int new_mtu) ++{ ++ if (new_mtu < cns3xxx_min_mtu() || new_mtu > cns3xxx_max_mtu()) ++ return -EINVAL; ++ ++ dev->mtu = new_mtu; ++ ++ return 0; ++} ++ ++static void cns3xxx_timeout(struct net_device *dev) ++{ ++ //star_gsw_enable(dev); ++ netif_wake_queue(dev); ++ dev->trans_start = jiffies; ++} ++ ++#ifdef LINUX2631 ++static const struct net_device_ops cns3xxx_netdev_ops = { ++ .ndo_open = cns3xxx_open, ++ .ndo_stop = cns3xxx_close, ++ .ndo_start_xmit = cns3xxx_send_packet, ++ //.ndo_validate_addr = eth_validate_addr, ++ //.ndo_set_multicast_list = cns3xxx_set_multicast_list, ++ .ndo_set_mac_address = cns3xxx_set_mac_addr, ++ .ndo_change_mtu = cns3xxx_change_mtu, ++ .ndo_do_ioctl = cns3xxx_do_ioctl, ++ .ndo_tx_timeout = cns3xxx_timeout, ++ .ndo_get_stats = cns3xxx_get_stats, ++ ++#if defined(CNS3XXX_VLAN_8021Q) ++ .ndo_vlan_rx_register = cns3xxx_vlan_rx_register, ++ //.ndo_vlan_rx_add_vid = e1000_vlan_rx_add_vid, ++ .ndo_vlan_rx_kill_vid = cns3xxx_vlan_rx_kill_vid, ++#endif ++ ++#ifdef CONFIG_NET_POLL_CONTROLLER ++ .ndo_poll_controller = cns3xxx_netpoll, ++#endif ++}; ++#endif // LINUX2631 ++ ++static int __init cns3xxx_probe(RingInfo ring_info) ++{ ++ void cns3xxx_set_ethtool_ops(struct net_device *netdev); ++ ++ int netdev_size = sizeof(net_device_prive)/sizeof(NetDevicePriv); ++ int i=0, err=0; ++ struct net_device *netdev=0; ++ CNS3XXXPrivate *priv=0; ++ struct sockaddr sock_addr; ++ ++ for (i=0 ; i < netdev_size ; ++i) { ++ if (init_port & (1 << i)) { ++ ++ netdev = alloc_etherdev(sizeof(CNS3XXXPrivate)); ++ if (!netdev) { ++ err = -ENOMEM; ++ goto err_alloc_etherdev; ++ } ++ if (net_device_prive[i].name) ++ strcpy(netdev->name, net_device_prive[i].name); ++ ++ ++ net_dev_array[net_device_prive[i].vlan_tag] = netdev; ++ if (intr_netdev==0) ++ intr_netdev = netdev; ++ ++ SET_NETDEV_DEV(netdev, NULL); ++ priv = netdev_priv(netdev); ++ spin_lock_init(&priv->lock); ++ memset(priv, 0, sizeof(CNS3XXXPrivate)); ++ ++#if 1 ++ priv->num_rx_queues = ring_info.num_rx_queues; ++ priv->num_tx_queues = ring_info.num_tx_queues; ++ priv->rx_ring = ring_info.rx_ring; ++ priv->tx_ring = ring_info.tx_ring; ++#endif ++ ++ priv->net_device_priv = &net_device_prive[i]; ++ ++ // set netdev MAC address ++ memcpy(sock_addr.sa_data, net_device_prive[i].mac, 6); ++ cns3xxx_set_mac_addr(netdev, &sock_addr); ++ ++#ifdef LINUX2631 ++ netdev->netdev_ops = &cns3xxx_netdev_ops; ++#endif ++ ++ cns3xxx_set_ethtool_ops(netdev); ++#ifdef LINUX2627 ++ //netdev->base_addr = IO_ADDRESS(GSW_BASE_ADDR); ++ netdev->base_addr = 0; ++ netdev->open = cns3xxx_open; ++ netdev->stop = cns3xxx_close; ++ netdev->hard_start_xmit = cns3xxx_send_packet; ++ //netdev->hard_start_xmit = 0; ++ netdev->do_ioctl = cns3xxx_do_ioctl; ++ netdev->change_mtu = cns3xxx_change_mtu; ++ ++ //netdev->get_stats = cns3xxx_get_stats; ++ netdev->watchdog_timeo = 5 * HZ; // ref e1000_main.c ++ netdev->tx_timeout = cns3xxx_timeout; ++ netdev->set_mac_address = cns3xxx_set_mac_addr; ++#endif ++ ++#if defined(CNS3XXX_TX_HW_CHECKSUM) ++ netdev->features |= (NETIF_F_IP_CSUM | NETIF_F_SG); ++ //netdev->features |= (NETIF_F_HW_CSUM | NETIF_F_SG); ++#endif ++ ++ ++#ifdef CONFIG_CNS3XXX_NAPI ++ //netif_napi_add(netdev, &priv->napi, cns3xxx_poll, CNS3XXX_NAPI_WEIGHT); ++#endif ++ ++#if defined(CNS3XXX_VLAN_8021Q) ++ // do not let 8021Q module insert vlan tag ++ // can use the snippet code to get vlan tage ++ // if (priv->vlgrp && vlan_tx_tag_present(skb)) ++ // vlan_tag = cpu_to_be16(vlan_tx_tag_get(skb)); ++#ifdef CNS3XXX_8021Q_HW_TX ++ // hardware support insert VLAN tag on TX path ++ netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; ++#else ++ netdev->features |= NETIF_F_HW_VLAN_RX; // remove NETIF_F_HW_VLAN_TX flag that 8021Q module to insert vlan tag. ++#endif ++ ++ //netdev->vlan_rx_register = cns3xxx_vlan_rx_register; ++ //netdev->vlan_rx_kill_vid = cns3xxx_vlan_rx_kill_vid; ++#endif ++ ++ ++ err = register_netdev(netdev); ++ if (err) { ++ goto err_register_netdev; ++ } ++ ++ netif_carrier_off(netdev); ++ netdev = 0; ++ } ++ } // for (i=0 ; i < netdev_size ; ++i) ++ ++ return 0; ++ ++ ++err_register_netdev: ++ free_netdev(netdev); ++ ++err_alloc_etherdev: ++ return err; ++} ++ ++int cns3xxx_gsw_config_mac_port0(void) ++{ ++ INIT_PORT0_PHY ++ INIT_PORT0_MAC ++ PORT0_LINK_DOWN ++ return 0; ++} ++ ++int cns3xxx_gsw_config_mac_port1(void) ++{ ++ INIT_PORT1_PHY ++ INIT_PORT1_MAC ++ PORT1_LINK_DOWN ++ return 0; ++} ++ ++int cns3xxx_gsw_config_mac_port2(void) ++{ ++ INIT_PORT2_PHY ++ INIT_PORT2_MAC ++ PORT2_LINK_DOWN ++ return 0; ++} ++ ++static int cns3xxx_notify_reboot(struct notifier_block *nb, unsigned long event, void *ptr) ++{ ++ // stop the DMA ++ enable_rx_dma(0, 0); ++ enable_tx_dma(0, 0); ++ enable_rx_dma(1, 0); ++ enable_tx_dma(1, 0); ++ ++ // disable Port 0 ++ enable_port(0, 0); ++ enable_port(1, 0); ++ enable_port(2, 0); ++ enable_port(3, 0); ++ return NOTIFY_DONE; ++} ++ ++#ifdef CONFIG_CNS3XXX_NAPI ++static struct net_device *init_napi_dev(struct net_device *ndev, const RingInfo *ring_info) ++{ ++ CNS3XXXPrivate *priv; ++ ++ ndev = alloc_etherdev(sizeof(CNS3XXXPrivate)); ++ if (!ndev) { ++ BUG(); ++ } ++ priv = netdev_priv(ndev); ++ memset(priv, 0, sizeof(CNS3XXXPrivate)); ++ ++ //priv = netdev_priv(napi_dev); ++ priv->num_rx_queues = ring_info->num_rx_queues; ++ priv->num_tx_queues = ring_info->num_tx_queues; ++ priv->rx_ring = ring_info->rx_ring; ++ priv->tx_ring = ring_info->tx_ring; ++ //priv->is_qf=0; // because of memset, so need not the line ++ ++ netif_napi_add(ndev, &priv->napi , cns3xxx_poll, CNS3XXX_NAPI_WEIGHT); ++ dev_hold(ndev); ++ set_bit(__LINK_STATE_START, &ndev->state); ++ ++ return ndev; ++} ++#endif ++ ++ ++void cns3xxx_config_intr(void) ++{ ++ u32 v=0xffffffff; ++ ++ get_interrupt_type(FSRC_RING0_INTERRUPT_ID, &v); ++#if 1 ++ set_interrupt_type(FSRC_RING0_INTERRUPT_ID, RISING_EDGE); ++ get_interrupt_type(FSRC_RING0_INTERRUPT_ID, &v); ++ ++ get_interrupt_type(FSRC_RING1_INTERRUPT_ID, &v); ++ set_interrupt_type(FSRC_RING1_INTERRUPT_ID, RISING_EDGE); ++ get_interrupt_type(FSRC_RING1_INTERRUPT_ID, &v); ++ ++ get_interrupt_type(FSQF_RING0_INTERRUPT_ID, &v); ++ set_interrupt_type(FSQF_RING0_INTERRUPT_ID, RISING_EDGE); ++ get_interrupt_type(FSQF_RING0_INTERRUPT_ID, &v); ++ ++ get_interrupt_type(FSQF_RING1_INTERRUPT_ID, &v); ++ set_interrupt_type(FSQF_RING1_INTERRUPT_ID, RISING_EDGE); ++ get_interrupt_type(FSQF_RING1_INTERRUPT_ID, &v); ++ ++ #ifdef CNS3XXX_USE_MASK ++ get_interrupt_pri(FSRC_RING0_INTERRUPT_ID, &v); ++ set_interrupt_pri(FSRC_RING0_INTERRUPT_ID, 0xc); ++ get_interrupt_pri(FSRC_RING0_INTERRUPT_ID, &v); ++ ++ get_interrupt_pri(FSRC_RING1_INTERRUPT_ID, &v); ++ set_interrupt_pri(FSRC_RING1_INTERRUPT_ID, 0xc); ++ get_interrupt_pri(FSRC_RING1_INTERRUPT_ID, &v); ++ ++ get_interrupt_pri(FSQF_RING1_INTERRUPT_ID, &v); ++ set_interrupt_pri(FSQF_RING1_INTERRUPT_ID, 0xc); ++ get_interrupt_pri(FSQF_RING1_INTERRUPT_ID, &v); ++ ++ #ifndef CONFIG_CNS3XXX_NAPI ++ set_interrupt_pri(FSQF_RING0_INTERRUPT_ID, 0xc); ++ #endif ++ ++ ++ #endif // CNS3XXX_USE_MASK ++#endif ++} ++ ++static int __devinit cns3xxx_init(struct platform_device *pdev) ++{ ++ // when tx_ring/rx_ring alloc memory, ++ // don't free them until cns3xxx_exit_module ++ ++ struct eth_plat_info *plat = pdev->dev.platform_data; ++ init_port = plat->ports; ++ memcpy(cpu_vlan_table_entry.my_mac, plat->cpu_hwaddr, ETH_ALEN); ++#if defined (CONFIG_CNS3XXX_SPPE) ++ memcpy(net_device_prive[3].mac, plat->cpu_hwaddr, ETH_ALEN); ++#endif ++ ++ RingInfo ring_info; ++ int i=0; ++ //spin_lock_init(&star_gsw_send_lock); ++ ++ ++#ifdef CNS3XXX_DOUBLE_RX_RING ++ ring_info.num_rx_queues = 2; ++#else ++ ring_info.num_rx_queues = 1; ++#endif ++ ++#ifdef CNS3XXX_DOUBLE_TX_RING ++ ring_info.num_tx_queues = 2; ++#else ++ ring_info.num_tx_queues = 1; ++#endif ++ ++ ring_info.rx_ring = kcalloc(ring_info.num_rx_queues, sizeof(RXRing), GFP_KERNEL); ++ if (!ring_info.rx_ring) ++ return -ENOMEM; ++ ++ for (i=0 ; i < ring_info.num_rx_queues ; ++i) { ++ memset(ring_info.rx_ring + i, 0, sizeof(RXRing)); ++ } ++ ++ ++ ring_info.tx_ring = kcalloc(ring_info.num_tx_queues, sizeof(TXRing), GFP_KERNEL); ++ ++ ++ if (!ring_info.tx_ring) ++ return -ENOMEM; ++ ++ for (i=0 ; i < ring_info.num_tx_queues ; ++i) { ++ memset(ring_info.tx_ring + i, 0, sizeof(TXRing)); ++ } ++ ++ ++ g_ring_info = ring_info; ++ ++ cns3xxx_gsw_hw_init(); ++ ++#ifdef CONFIG_FPGA ++ // GIGA mode disable ++ MAC0_CFG_REG &= (~(1<<16)); ++ MAC1_CFG_REG &= (~(1<<16)); ++ MAC2_CFG_REG &= (~(1<<16)); ++#endif ++ ++ if ((init_port & 1) == 1) { ++ memcpy(vlan_table_entry[0].my_mac, plat->eth0_hwaddr, ETH_ALEN); ++ memcpy(arl_table_entry[0].mac, plat->eth0_hwaddr, ETH_ALEN); ++ memcpy(net_device_prive[0].mac, plat->eth0_hwaddr, ETH_ALEN); ++ cns3xxx_gsw_config_mac_port0(); ++ } ++ ++ if (((init_port >> 1) & 1) == 1) { ++ memcpy(vlan_table_entry[1].my_mac, plat->eth1_hwaddr, ETH_ALEN); ++ memcpy(arl_table_entry[1].mac, plat->eth1_hwaddr, ETH_ALEN); ++ memcpy(net_device_prive[1].mac, plat->eth1_hwaddr, ETH_ALEN); ++ cns3xxx_gsw_config_mac_port1(); ++ } ++ ++ if (((init_port >> 2) & 1) == 1) { ++ memcpy(vlan_table_entry[2].my_mac, plat->eth2_hwaddr, ETH_ALEN); ++ memcpy(arl_table_entry[2].mac, plat->eth2_hwaddr, ETH_ALEN); ++ memcpy(net_device_prive[2].mac, plat->eth2_hwaddr, ETH_ALEN); ++ cns3xxx_gsw_config_mac_port2(); ++ } ++ ++ cns3xxx_probe(ring_info); ++ cns3xxx_config_intr(); ++ ++#ifdef CNS3XXX_VLAN_8021Q ++#ifdef CNS3XXX_NIC_MODE_8021Q ++ cns3xxx_nic_mode(1); ++#endif ++#endif ++ spin_lock_init(&tx_lock); ++ spin_lock_init(&rx_lock); ++ ++#ifdef CONFIG_CNS3XXX_NAPI ++ napi_dev = init_napi_dev(napi_dev, &ring_info); ++ #ifdef CNS3XXX_DOUBLE_RX_RING ++ r1_napi_dev = init_napi_dev(r1_napi_dev, &ring_info); ++ #endif ++#endif ++ ++ register_reboot_notifier(&cns3xxx_notifier_reboot); ++ clear_fs_dma_state(0); ++ ++ if (ring_info.num_rx_queues == 2) { ++ // enable RX dobule ring ++ DMA_RING_CTRL_REG |= 1; ++ } ++ ++ if (ring_info.num_tx_queues == 2 ) { ++ // enable TX dobule ring ++ DMA_RING_CTRL_REG |= (1 << 16); ++ } ++ ++ ++ return 0; ++} ++ ++static int __devexit cns3xxx_remove(struct platform_device *pdev) ++{ ++ int i=0; ++ ++#if 1 ++ for (i=0 ; i < NETDEV_SIZE ; ++i) { ++ CNS3XXXPrivate *priv = 0; ++ ++ if (net_dev_array[i]){ ++ priv = netdev_priv(net_dev_array[i]); ++ ++ kfree(priv->tx_ring); ++ priv->tx_ring = 0; ++ ++ kfree(priv->rx_ring); ++ priv->rx_ring = 0; ++ ++ unregister_netdev(net_dev_array[i]); ++ free_netdev(net_dev_array[i]); ++ } ++ ++ ++#if 0 ++ sprintf(netdev_name, "eth%d", i); ++ netdev=__dev_get_by_name(&init_net, netdev_name); ++ // if no unregister_netdev and free_netdev, ++ // after remove module, ifconfig will hang. ++ #if 1 ++ if (netdev) { ++ unregister_netdev(netdev); ++ free_netdev(netdev); ++ } ++#endif ++ #endif ++ } ++#endif ++ ++#ifdef CONFIG_CNS3XXX_NAPI ++ free_netdev(napi_dev); ++ #ifdef CNS3XXX_DOUBLE_RX_RING ++ free_netdev(r1_napi_dev); ++ #endif ++#endif ++ ++ ++#if 0 ++ //star_gsw_buffer_free(); ++#endif ++ unregister_reboot_notifier(&cns3xxx_notifier_reboot); ++} ++ ++ ++// this snippet code ref 8139cp.c ++#if defined(CNS3XXX_VLAN_8021Q) ++void cns3xxx_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) ++{ ++ CNS3XXXPrivate *priv = netdev_priv(dev); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ priv->vlgrp = grp; ++ spin_unlock_irqrestore(&priv->lock, flags); ++} ++ ++void cns3xxx_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) ++{ ++ CNS3XXXPrivate *priv = netdev_priv(dev); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&priv->lock, flags); ++ // reference: linux-2.6.24-current/drivers/netvia-velocity.c ++ vlan_group_set_device(priv->vlgrp, vid, NULL); ++ //priv->vlgrp->vlan_devices[vid] = NULL; ++ spin_unlock_irqrestore(&priv->lock, flags); ++} ++ ++#endif ++ ++static struct platform_driver drv = { ++ .driver.name = "cns3xxx-net", ++ .probe = cns3xxx_init, ++ .remove = cns3xxx_remove, ++}; ++ ++static int __init cns3xxx_init_module(void) ++{ ++ return platform_driver_register(&drv); ++} ++ ++static void __exit cns3xxx_exit_module(void) ++{ ++ platform_driver_unregister(&drv); ++} ++ ++MODULE_AUTHOR("Cavium Networks, <tech@XXXX.com>"); ++MODULE_DESCRIPTION("CNS3XXX Switch Driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ ++module_init(cns3xxx_init_module); ++module_exit(cns3xxx_exit_module); ++ +--- /dev/null ++++ b/drivers/net/cns3xxx/cns3xxx_phy.c +@@ -0,0 +1,1968 @@ ++/******************************************************************************* ++ * ++ * ++ * Copyright (c) 2009 Cavium Networks ++ * ++ * 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 ++1* 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. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ ********************************************************************************/ ++ ++#include "cns3xxx_phy.h" ++#include "cns3xxx_symbol.h" ++ ++ ++#if defined(LINUX_KERNEL) ++#include "cns3xxx_tool.h" ++#include <linux/cns3xxx/switch_api.h> // for CAVM_OK ... macro ++#include <linux/delay.h> ++#include "cns3xxx_config.h" ++#else // u-boot ++#include <common.h> ++#include "cns3xxx_switch_type.h" ++#define printk printf ++#endif ++ ++int cns3xxx_phy_reset(u8 phy_addr) ++{ ++ u16 phy_data=0; ++ ++ if (cns3xxx_read_phy(phy_addr, 0, &phy_data) != CAVM_OK) ++ return CAVM_ERR; ++ phy_data |= (0x1 << 15); ++ if (cns3xxx_write_phy(phy_addr, 0, phy_data) != CAVM_OK) ++ return CAVM_ERR; ++ ++ return CAVM_OK; ++} ++ ++// mac_port: 0, 1, 2 ++int cns3xxx_enable_mac_clock(u8 mac_port, u8 en) ++{ ++ switch (mac_port) ++ { ++ case 0: ++ { ++ (en==1)?(PHY_AUTO_ADDR_REG |= 1 << 7) :(PHY_AUTO_ADDR_REG &= (~(1 << 7)) ); ++ break; ++ } ++ case 1: ++ { ++ (en==1)?(PHY_AUTO_ADDR_REG |= (1 << 15)) :(PHY_AUTO_ADDR_REG &= (~(1 << 15)) ); ++ break; ++ } ++ case 2: ++ { ++ (en==1)?(PHY_AUTO_ADDR_REG |= (1 << 23)) :(PHY_AUTO_ADDR_REG &= (~(1 << 23)) ); ++ break; ++ } ++ } ++ ++ return CAVM_OK; ++} ++ ++// dis: 1 disable ++// dis: 0 enable ++int cns3xxx_phy_auto_polling_enable(u8 port, u8 en) ++{ ++ u8 phy_addr[]={5, 13, 21}; ++ ++ PHY_AUTO_ADDR_REG &= (~(1 << phy_addr[port])); ++ if (en) { ++ PHY_AUTO_ADDR_REG |= (1 << phy_addr[port]); ++ } ++ return CAVM_OK; ++} ++ ++// dis: 1 disable ++// dis: 0 enable ++int cns3xxx_mdc_mdio_disable(u8 dis) ++{ ++ ++ PHY_CTRL_REG &= (~(1 << 7)); ++ if (dis) { ++ PHY_CTRL_REG |= (1 << 7); ++ } ++ return CAVM_OK; ++} ++ ++ ++static int cns3xxx_phy_auto_polling_conf(int mac_port, u8 phy_addr) ++{ ++ if ( (mac_port < 0) || (mac_port > 2) ) { ++ return CAVM_ERR; ++ } ++ ++ switch (mac_port) ++ { ++ case 0: ++ { ++ PHY_AUTO_ADDR_REG &= (~0x1f); ++ PHY_AUTO_ADDR_REG |= phy_addr; ++ break; ++ } ++ case 1: ++ { ++ PHY_AUTO_ADDR_REG &= (~(0x1f << 8)); ++ PHY_AUTO_ADDR_REG |= (phy_addr << 8); ++ break; ++ } ++ case 2: ++ { ++ PHY_AUTO_ADDR_REG &= (~(0x1f << 16)); ++ PHY_AUTO_ADDR_REG |= (phy_addr << 16); ++ break; ++ } ++ } ++ cns3xxx_phy_auto_polling_enable(mac_port, 1); ++ return CAVM_OK; ++} ++ ++ ++ ++int cns3xxx_read_phy(u8 phy_addr, u8 phy_reg, u16 *read_data) ++{ ++ int delay=0; ++ u32 volatile tmp = PHY_CTRL_REG; ++ ++ PHY_CTRL_REG |= (1 << 15); // clear "command completed" bit ++ // delay ++ for (delay=0; delay<10; delay++); ++ tmp &= (~0x1f); ++ tmp |= phy_addr; ++ ++ tmp &= (~(0x1f << 8)); ++ tmp |= (phy_reg << 8); ++ ++ tmp |= (1 << 14); // read command ++ ++ PHY_CTRL_REG = tmp; ++ ++ // wait command complete ++ while ( ((PHY_CTRL_REG >> 15) & 1) == 0); ++ ++ *read_data = (PHY_CTRL_REG >> 16); ++ ++ PHY_CTRL_REG |= (1 << 15); // clear "command completed" bit ++ ++ return CAVM_OK; ++} ++ ++int cns3xxx_write_phy(u8 phy_addr, u8 phy_reg, u16 write_data) ++{ ++ int delay=0; ++ u32 tmp = PHY_CTRL_REG; ++ ++ PHY_CTRL_REG |= (1 << 15); // clear "command completed" bit ++ // delay ++ for (delay=0; delay<10; delay++); ++ ++ tmp &= (~(0xffff << 16)); ++ tmp |= (write_data << 16); ++ ++ tmp &= (~0x1f); ++ tmp |= phy_addr; ++ ++ tmp &= (~(0x1f << 8)); ++ tmp |= (phy_reg << 8); ++ ++ tmp |= (1 << 13); // write command ++ ++ PHY_CTRL_REG = tmp; ++ ++ // wait command complete ++ while ( ((PHY_CTRL_REG >> 15) & 1) == 0); ++ ++ return CAVM_OK; ++} ++ ++// port 0,1,2 ++void cns3xxx_rxc_dly(u8 port, u8 val) ++{ ++ switch (port) ++ { ++ case 0: ++ { ++ SLK_SKEW_CTRL_REG &= (~(0x3 << 4)); ++ SLK_SKEW_CTRL_REG |= (val << 4); ++ break; ++ } ++ case 1: ++ { ++ SLK_SKEW_CTRL_REG &= (~(0x3 << 12)); ++ SLK_SKEW_CTRL_REG |= (val << 12); ++ break; ++ } ++ case 2: ++ { ++ SLK_SKEW_CTRL_REG &= (~(0x3 << 20)); ++ SLK_SKEW_CTRL_REG |= (val << 20); ++ break; ++ } ++ } ++} ++ ++// port 0,1,2 ++void cns3xxx_txc_dly(u8 port, u8 val) ++{ ++ switch (port) ++ { ++ case 0: ++ { ++ SLK_SKEW_CTRL_REG &= (~(0x3 << 6)); ++ SLK_SKEW_CTRL_REG |= (val << 6); ++ break; ++ } ++ case 1: ++ { ++ SLK_SKEW_CTRL_REG &= (~(0x3 << 14)); ++ SLK_SKEW_CTRL_REG |= (val << 14); ++ break; ++ } ++ case 2: ++ { ++ SLK_SKEW_CTRL_REG &= (~(0x3 << 22)); ++ SLK_SKEW_CTRL_REG |= (val << 22); ++ break; ++ } ++ } ++} ++ ++void cns3xxx_mac2_gtxd_dly(u8 val) ++{ ++ SLK_SKEW_CTRL_REG &= (~(0x3 << 24)); ++ SLK_SKEW_CTRL_REG |= (val << 24); ++} ++ ++// VITESSE suggest use isolate bit. ++int vsc8601_power_down(int phy_addr, int y) ++{ ++ u16 phy_data = 0; ++ /* set isolate bit instead of powerdown */ ++ cns3xxx_read_phy(phy_addr, 0, &phy_data); ++ if (y==1) // set isolate ++ phy_data |= (0x1 << 10); ++ if (y==0) // unset isolate ++ phy_data &= (~(0x1 << 10)); ++ cns3xxx_write_phy(phy_addr, 0, phy_data); ++ ++ return 0; ++} ++ ++ ++// port : 0 => port0 ; port : 1 => port1 ++// y = 1 ; disable AN ++void disable_AN(int port, int y) ++{ ++ u32 mac_port_config=0; ++ ++ switch (port) ++ { ++ case 0: ++ { ++ mac_port_config = MAC0_CFG_REG; ++ break; ++ } ++ case 1: ++ { ++ mac_port_config = MAC1_CFG_REG; ++ break; ++ } ++ case 2: ++ { ++ mac_port_config = MAC2_CFG_REG; ++ break; ++ } ++ } ++ ++ ++ // disable PHY's AN ++ if (y==1) ++ { ++ mac_port_config &= ~(0x1 << 7); ++ } ++ ++ // enable PHY's AN ++ if (y==0) ++ { ++ mac_port_config |= (0x1 << 7); ++ } ++ ++ switch (port) ++ { ++ case 0: ++ { ++ MAC0_CFG_REG = mac_port_config; ++ break; ++ } ++ case 1: ++ { ++ MAC1_CFG_REG = mac_port_config; ++ break; ++ } ++ case 2: ++ { ++ MAC2_CFG_REG = mac_port_config; ++ break; ++ } ++ } ++} ++ ++int cns3xxx_std_phy_power_down(int phy_addr, int y) ++{ ++ u16 phy_data = 0; ++ // power-down or up the PHY ++ cns3xxx_read_phy(phy_addr, 0, &phy_data); ++ if (y==1) // down ++ phy_data |= (0x1 << 11); ++ if (y==0) // up ++ phy_data &= (~(0x1 << 11)); ++ cns3xxx_write_phy(phy_addr, 0, phy_data); ++ ++ phy_data=0; ++ cns3xxx_read_phy(phy_addr, 0, &phy_data); ++ ++ return 0; ++} ++ ++ ++#if defined(LINUX_KERNEL) ++int cns3xxx_spi_tx_rx_n(u32 tx_data, u32 *rx_data, u32 tx_channel, u32 tx_eof_flag) ++{ ++ u8 cns3xxx_spi_tx_rx(u8 tx_channel, u8 tx_eof, u32 tx_data, u32 * rx_data); ++ ++ return cns3xxx_spi_tx_rx(tx_channel, tx_eof_flag, tx_data, rx_data); ++} ++ ++int bcm53115M_reg_read(int page, int offset, u8 *buf, int len) ++{ ++ u32 ch = BCM53115_SPI_CHANNEL; ++ u8 cmd_byte; ++ u32 dumy_word; ++ u32 spi_status; ++ int i; ++ ++ /* ++ * Normal SPI Mode (Command Byte) ++ * Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 ++ * 0 1 1 Mode=0 CHIP_ID2 ID1 ID0(lsb) Rd/Wr(0/1) ++ * ++ */ ++ ++ /* Normal Read Operation */ ++ /* 1. Issue a normal read command(0x60) to poll the SPIF bit in the ++ SPI status register(0XFE) to determine the operation can start */ ++ do ++ { ++ cmd_byte = 0x60; ++ cns3xxx_spi_tx_rx_n(cmd_byte, &dumy_word, ch, 0); ++ cns3xxx_spi_tx_rx_n(0xFE, &dumy_word, ch, 0); ++ cns3xxx_spi_tx_rx_n(0x00, &spi_status, ch, 1); ++ udelay(100); ++ }while ((spi_status >> ROBO_SPIF_BIT) & 1) ; // wait SPI bit to 0 ++ ++ /* 2. Issue a normal write command(0x61) to write the register page value ++ into the SPI page register(0xFF) */ ++ cmd_byte = 0x61; ++ cns3xxx_spi_tx_rx_n(cmd_byte, &dumy_word, ch, 0); ++ cns3xxx_spi_tx_rx_n(0xFF, &dumy_word, ch, 0); ++ cns3xxx_spi_tx_rx_n(page, &dumy_word, ch, 1); ++ ++ /* 3. Issue a normal read command(0x60) to setup the required RobiSwitch register ++ address */ ++ cmd_byte = 0x60; ++ cns3xxx_spi_tx_rx_n(cmd_byte, &dumy_word, ch, 0); ++ cns3xxx_spi_tx_rx_n(offset, &dumy_word, ch, 0); ++ cns3xxx_spi_tx_rx_n(0x00, &dumy_word, ch, 1); ++ ++ /* 4. Issue a normal read command(0x60) to poll the RACK bit in the ++ SPI status register(0XFE) to determine the completion of read */ ++ do ++ { ++ cmd_byte = 0x60; ++ cns3xxx_spi_tx_rx_n(cmd_byte, &dumy_word, ch, 0); ++ cns3xxx_spi_tx_rx_n(0xFE, &dumy_word, ch, 0); ++ cns3xxx_spi_tx_rx_n(0x00, &spi_status, ch, 1); ++ udelay(100); ++ }while (((spi_status >> ROBO_RACK_BIT) & 1) == 0); // wait RACK bit to 1 ++ ++ /* 5. Issue a normal read command(0x60) to read the specific register's conternt ++ placed in the SPI data I/O register(0xF0) */ ++ cmd_byte = 0x60; ++ cns3xxx_spi_tx_rx_n(cmd_byte, &dumy_word, ch, 0); ++ cns3xxx_spi_tx_rx_n(0xF0, &dumy_word, ch, 0); ++ // read content ++ for (i=0; i<len; i++) { ++ cns3xxx_spi_tx_rx_n(0x00, &dumy_word, ch, ((i==(len-1)) ? 1 : 0)); ++ buf[i] = (u8)dumy_word; ++ } ++ ++ return 0; ++ ++} ++ ++int bcm53115M_reg_write(int page, int offset, u8 *buf, int len) ++{ ++ u32 ch = BCM53115_SPI_CHANNEL; ++ u8 cmd_byte; ++ u32 dumy_word; ++ u32 spi_status; ++ int i; ++ ++ /* ++ * Normal SPI Mode (Command Byte) ++ * Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 ++ * 0 1 1 Mode=0 CHIP_ID2 ID1 ID0(lsb) Rd/Wr(0/1) ++ * ++ */ ++ ++ /* Normal Write Operation */ ++ /* 1. Issue a normal read command(0x60) to poll the SPIF bit in the ++ SPI status register(0XFE) to determine the operation can start */ ++ ++ do ++ { ++ cmd_byte = 0x60; ++ cns3xxx_spi_tx_rx_n(cmd_byte, &dumy_word, ch, 0); ++ cns3xxx_spi_tx_rx_n(0xFE, &dumy_word, ch, 0); ++ cns3xxx_spi_tx_rx_n(0x00, &spi_status, ch, 1); ++ }while ((spi_status >> ROBO_SPIF_BIT) & 1) ; // wait SPI bit to 0 ++ ++ /* 2. Issue a normal write command(0x61) to write the register page value ++ into the SPI page register(0xFF) */ ++ cmd_byte = 0x61; ++ cns3xxx_spi_tx_rx_n((u32)cmd_byte, &dumy_word, ch, 0); ++ cns3xxx_spi_tx_rx_n(0xFF, &dumy_word, ch, 0); ++ cns3xxx_spi_tx_rx_n(page, &dumy_word, ch, 1); ++ ++ /* 3. Issue a normal write command(0x61) and write the address of the accessed ++ register followed by the write content starting from a lower byte */ ++ cmd_byte = 0x61; ++ cns3xxx_spi_tx_rx_n((u32)cmd_byte, &dumy_word, ch, 0); ++ cns3xxx_spi_tx_rx_n(offset, &dumy_word, ch, 0); ++ // write content ++ for (i=0; i<len; i++) { ++ cns3xxx_spi_tx_rx_n((u32)buf[i], &dumy_word, ch, ((i==(len-1)) ? 1 : 0)); ++ } ++ ++ return 0; ++} ++ ++int __init_or_module gpio_direction_output(unsigned int pin, unsigned int state); ++ ++void bcm53115M_init_mac(u8 mac_port, u16 phy_addr) ++{ ++ u32 mac_port_config = 0; ++ u8 mac_addr[]={0x0c, 0x10, 0x18}; ++ ++ cns3xxx_enable_mac_clock(mac_port, 1); ++ cns3xxx_phy_auto_polling_enable(mac_port, 0); ++ ++ mac_port_config = SWITCH_REG_VALUE(mac_addr[mac_port]); ++ ++ // enable GMII, MII, reverse MII ++ mac_port_config &= (~(1 << 15)); ++ ++ // enable RGMII ++ mac_port_config |= (1 << 15); ++ ++ // disable GIGA mode ++ mac_port_config &= (~(1<<16)); ++ ++ // enable GIGA mode ++ mac_port_config |= (1<<16); ++ ++ // disable PHY's AN ++ mac_port_config &= (~(0x1 << 7)); ++ ++ // force 1000Mbps ++ mac_port_config &= (~(0x3 << 8)); ++ mac_port_config |= (0x2 << 8); ++ ++ // force duplex ++ mac_port_config |= (0x1 << 10); ++ ++ // TX flow control on ++ mac_port_config |= (0x1 << 12); ++ ++ // RX flow control on ++ mac_port_config |= (0x1 << 11); ++ ++ // Turn off GSW_PORT_TX_CHECK_EN_BIT ++ mac_port_config &= (~(0x1 << 13)); ++ ++ // Turn on GSW_PORT_TX_CHECK_EN_BIT ++ mac_port_config |= (0x1 << 13); ++ ++ SWITCH_REG_VALUE(mac_addr[mac_port]) = mac_port_config; ++} ++ ++typedef struct bcm53115M_vlan_entry_t ++{ ++ u16 vid; ++ u16 forward_map; ++ u16 untag_map; ++}bcm53115M_vlan_entry; ++ ++ ++ ++int bcm53115M_write_vlan(bcm53115M_vlan_entry *v) ++{ ++ u8 bval; ++ u16 wval; ++ u32 dwval; ++ ++ // fill vid ++ wval = (u16)v->vid; ++ bcm53115M_reg_write(0x05, 0x81, (u8*)&wval, 2); ++ ++ // fill table content ++ dwval = 0; ++ dwval |= (v->forward_map & 0x1FF); ++ dwval |= ((v->untag_map& 0x1FF) << 9); ++ bcm53115M_reg_write(0x05, 0x83, (u8*)&wval, 4); ++ ++ // write cmd ++ bval = VLAN_WRITE_CMD; ++ bval |= (1 << VLAN_START_BIT); ++ bcm53115M_reg_write(0x05, 0x80, (u8*)&bval, 1); ++ ++ // wait cmd complete ++ while(1) { ++ bcm53115M_reg_read(0x05, 0x80, (u8*)&bval, 1); ++ if (((bval >> VLAN_START_BIT) & 1) == 0) break; ++ } ++ ++ return CAVM_OK; ++} ++ ++typedef struct bcm_port_cfg_t ++{ ++ u8 link; ++ u8 fdx; ++ BCM_PORT_SPEED speed; ++ u8 rx_flw_ctrl; ++ u8 tx_flw_ctrl; ++ u8 ow; ++}bcm_port_cfg; ++ ++ ++ ++int bcm53115M_mac_port_config(int port, bcm_port_cfg *cfg) ++{ ++ u8 bval = 0; ++ int page, addr; ++ ++ if (cfg->link) bval |= (1<<0); ++ if (cfg->fdx) bval |= (1<<1); ++ bval |= ((cfg->speed&0x3) << 2); ++ if (cfg->rx_flw_ctrl) bval |= (1<<4); ++ if (cfg->tx_flw_ctrl) bval |= (1<<5); ++ ++ if (port == BCM_PORT_IMP) { ++ bval |= (1<<7); // Use content of this register ++ page = 0x00; ++ addr = 0x0E; ++ }else { ++ page = 0x00; ++ addr = 0x58+port; ++ } ++ ++ bcm53115M_reg_write(page, addr, &bval, 1); ++ ++ return 0; ++} ++ ++int bcm53115M_init_internal_phy(void) ++{ ++ int p, page; ++ u16 wval; ++ ++ for (p=BCM_PORT_0; p<=BCM_PORT_4; p++) { ++ page = 0x10+p; ++ ++ // reset phy ++ bcm53115M_reg_read(page, 0x00, (u8*)&wval, 2); ++ wval |= 0x8000; ++ bcm53115M_reg_write(page, 0x00, (u8*)&wval, 2); ++ ++ // config auto-nego & all advertisement ++ bcm53115M_reg_read(page, 0x00, (u8*)&wval, 2); ++ wval |= (1<<12); // auto-nego ++ bcm53115M_reg_write(page, 0x00, (u8*)&wval, 2); ++ ++ bcm53115M_reg_read(page, 0x08, (u8*)&wval, 2); ++ wval |= 0x1E0; // advertisement all ++ bcm53115M_reg_write(page, 0x08, (u8*)&wval, 2); ++ ++ // 1000BASE-T ++ bcm53115M_reg_read(page, 0x12, (u8*)&wval, 2); ++ wval &= ~(1<<12); // automatic master/slave configuration ++ wval |= 0x300; // 1000-base full/half advertisements ++ bcm53115M_reg_write(page, 0x12, (u8*)&wval, 2); ++ } ++ ++ return 0; ++} ++ ++int bcm53115M_led_init(void) ++{ ++ u16 led_func, bval, wval; ++ ++ /* LED function 1G/ACT, 100M/ACT, 10M/ACT, not used */ ++ led_func = 0x2C00; ++ bcm53115M_reg_write(0x00, 0x10, (u8*)&led_func, 2); ++ bcm53115M_reg_write(0x00, 0x12, (u8*)&led_func, 2); ++ ++ /* LED map enable */ ++ wval = 0x1F; // port0~4 ++ bcm53115M_reg_write(0x00, 0x16, (u8*)&wval, 2); ++ ++ /* LED mode map */ ++ wval = 0x1F; // led auto mode ++ bcm53115M_reg_write(0x00, 0x18, (u8*)&wval, 2); ++ bcm53115M_reg_write(0x00, 0x1A, (u8*)&wval, 2); ++ ++ /* LED enable */ ++ bcm53115M_reg_read(0x00, 0x0F, (u8*)&bval, 1); ++ bval |= 0x80; ++ bcm53115M_reg_write(0x00, 0x0F, (u8*)&bval, 1); ++ ++ return 0; ++} ++ ++//#define BCM53115M_DUMMY_SWITCH ++#define BCM53115M_DISABLE_LEARNING ++ ++int bcm53115M_init(u8 mac_port, u16 phy_addr) ++{ ++ u32 u32_val=0; ++ u16 u16_val=0; ++ u8 bval=0; ++ int i=0; ++ bcm53115M_vlan_entry v_ent; ++ bcm_port_cfg pc; ++ u8 page=0, offset=0; ++ ++ printk("bcm53115M init\n"); ++ ++ memset(&v_ent, 0, sizeof(bcm53115M_vlan_entry)); ++ ++ // gpio B pin 18 ++ gpio_direction_output(50, 0); ++ bcm53115M_init_mac(0, 0); ++ bcm53115M_init_mac(1, 1); ++ ++ // read device id ++ bcm53115M_reg_read(0x02, 0x30, (u8*)&u32_val, 4); ++ printk("bcm53115M device id:(0x%x)\r\n", u32_val); ++ ++ if (u32_val != 0x53115) { ++ printk("bad device id(0x%x)\r\n", u32_val); ++ return -1; ++ } ++ ++ u16_val=0; ++ // read phy id ++ bcm53115M_reg_read(0x10, 0x04, (u8 *)&u16_val, 2); ++ printk("bcm53115M phy id_1:(0x%x)\r\n", u16_val); ++ ++ if (u16_val != 0x143) { ++ printk("bad phy id1(0x%x)\r\n", u16_val); ++ return CAVM_ERR; ++ } ++ ++ u16_val=0; ++ // read phy id2 ++ bcm53115M_reg_read(0x10, 0x06, (u8 *)&u16_val, 2); ++ printk("bcm53115M phy id_2:(0x%x)\r\n", u16_val); ++ ++#ifdef BCM53115M_DUMMY_SWITCH ++ bval=0; ++ bcm53115M_reg_read(0x00, 0x0e, (u8 *)&bval, 1); ++ printk("bcm53115M page:0 addr:0x0e ## %x\n", bval); ++ bval |= (1 << 7); ++ bval |= 1; ++ ++ bval = 0x8b; ++ bval |= (1 << 5); ++ bval |= (1 << 4); ++ printk("bval : %x\n", bval); ++ bcm53115M_reg_write(0x00, 0x0e, (u8 *)&bval, 1); ++ bcm53115M_reg_read(0x00, 0x0e, (u8 *)&bval, 1); ++ printk("bcm53115M page:0 addr:0x0e ## %x\n", bval); ++ ++ /* Unmanagement mode */ ++ // Switch Mode. Page 00h,Address 0Bh ++ bval = 0x06; // forward enable, unmanaged mode ++ //bval = 0x3; // forward enable, managed mode ++ bcm53115M_reg_write(0x0, 0xb, &bval, 1); ++ bcm53115M_reg_read(0x0, 0xb, (u8 *)&bval, 1); ++ printk("bcm53115M page:0 addr:0xb ## %x\n", bval); ++ ++ page=0x0; ++ offset=0x5d; // port 5 ++ bval=0x7b; ++ bcm53115M_reg_write(page, offset, (u8 *)&bval, 1); ++ bcm53115M_reg_read(page, offset, (u8 *)&bval, 1); ++ ++ printk("bcm53115M page:%x addr:%x ## %x\n", page, offset, bval); ++ ++ page=0x0; ++ offset=0x58; // port 0 ++ bval=0x7b; ++ bcm53115M_reg_write(page, offset, (u8 *)&bval, 1); ++ bcm53115M_reg_read(page, offset, (u8 *)&bval, 1); ++ printk("bcm53115M page:%x addr:%x ## %x\n", page, offset, bval); ++ ++#ifdef CONFIG_CNS3XXX_JUMBO_FRAME ++ printk("enable BCM53115 jumbo frame\n"); ++ ++ page=0x40; ++ offset=0x01; ++ u32_val=0x013f; // enable 0-5 port and IMP port jumbo frame. MAX frame: 9720 bytes. ++ bcm53115M_reg_write(page, offset, (u8 *)&u32_val, 4); ++ bcm53115M_reg_read(page, offset, (u8 *)&u32_val, 4); ++ printk("bcm53115M page:%x addr:%x ## %x\n", page, offset, u32_val); ++ ++#if 0 ++ page=0x40; ++ offset=0x05; ++ u16_val=0; ++ bcm53115M_reg_write(page, offset, (u8 *)&u16_val, 2); ++#endif ++ ++#endif ++ ++#else // !BCM53115M_DUMMY_SWITCH ++ /* Loop detection disable */ ++ bcm53115M_reg_read(0x72, 0x00, (u8 *)&u16_val, 2); ++ u16_val &= ~(0x3<<11); ++ bcm53115M_reg_write(0x72, 0x00, (u8 *)&u16_val, 2); ++ ++ ++ /* VLAN forwarding mask */ ++ // Bit8 IMP port, Bits[5:0] correspond to ports[5:0] ++ // port 0 <-> port IMP ++ u16_val = 0x103; ++ bcm53115M_reg_write(0x31, 0x0, (u8 *)&u16_val, 2); // port 0 ++ u16_val = 0x103; ++ bcm53115M_reg_write(0x31, 0x10, (u8 *)&u16_val, 2); // IMP ++ ++ ++ // port 4 <-> port 5 ++ u16_val = 0x3c; ++ bcm53115M_reg_write(0x31, 0x08, (u8 *)&u16_val, 2); // port 4 ++ u16_val = 0x3c; ++ bcm53115M_reg_write(0x31, 0x0A, (u8 *)&u16_val, 2); // port 5 ++ ++ ++ // others <-> none ++ u16_val = 0x00; ++ bcm53115M_reg_write(0x31, 0x02, (u8 *)&u16_val, 2); // port 1 ++ bcm53115M_reg_write(0x31, 0x04, (u8 *)&u16_val, 2); // port 2 ++ bcm53115M_reg_write(0x31, 0x06, (u8 *)&u16_val, 2); // port 3 ++ ++ // port 1 <-> port IMP ++ u16_val = 0x103; ++ bcm53115M_reg_write(0x31, 0x2, (u8 *)&u16_val, 2); // port 1 ++ ++ // port 2 <-> port 5 ++ u16_val = 0x3c; ++ bcm53115M_reg_write(0x31, 0x4, (u8 *)&u16_val, 2); // port 2 ++ ++ // port 3 <-> port 5 ++ u16_val = 0x3c; ++ bcm53115M_reg_write(0x31, 0x6, (u8 *)&u16_val, 2); // port 3 ++ ++ /* Create VLAN1 for default port pvid */ ++#if 0 ++ v_ent.vid = 1; ++ v_ent.forward_map = 0x13F; // all ports ++ robo_write_vlan(&v_ent); ++#endif ++ ++ /* Unmanagement mode */ ++ // Switch Mode. Page 00h,Address 0Bh ++ bval = 0x02; // forward enable, unmanaged mode ++ bcm53115M_reg_write(0x0, 0xb, &bval, 1); ++ ++ /* Init port5 & IMP (test giga mode first) */ ++ // IMP port control. Page 00h,Address 08h ++ bval = 0x1C; // RX UCST/MCST/BCST enable ++ bcm53115M_reg_write(0x0, 0x8, &bval, 1); ++ ++ offset=0x5d; // port 5 ++ bval=0x7b; ++ bcm53115M_reg_write(page, offset, (u8 *)&bval, 1); ++ bcm53115M_reg_read(page, offset, (u8 *)&bval, 1); ++ ++ // Speed, dulplex......etc ++ // setting in Gsw_Configure_Gsw_Hardware() ++ ++ // Mgmt configuration, Page 02h, Address 00h ++ bval = 0; ++ bcm53115M_reg_write(0x02, 0x00, &bval, 1); ++ // BRCM header, Page 02h, Address 03h ++ bval = 0; // without additional header information ++ bcm53115M_reg_write(0x02, 0x03, &bval, 1); ++ ++ /* Init front ports, port0-4 */ ++ // MAC ++ pc.speed = BCM_PORT_1G; ++ pc.link = 0; // link detect by robo_port_update() ++ pc.ow = 0; ++ for (i=BCM_PORT_0; i<=BCM_PORT_4; i++) ++ bcm53115M_mac_port_config(i, &pc); ++ // Internal Phy ++ bcm53115M_init_internal_phy(); ++ ++ /* Enable all port, STP_STATE=No spanning tree, TX/RX enable */ ++ // Page 00h, Address 00h-05h ++ bval = 0x0; ++ for (i=0; i<=5; i++) ++ bcm53115M_reg_write(0x0, i, &bval, 1); ++ ++ // Disable broadcast storm control due to h/w strap pin BC_SUPP_EN ++ // Page 41h, Address 10h-13h, bit28&22 ++ ++ // for port 0 ~ 5 ++ for (i=0 ; i <= 0x14; i+=4) { ++ bcm53115M_reg_read(0x41, 0x10+i, (u8 *)&u32_val, 4); ++ u32_val &= ~((1<<28) | (1<<22)); ++ bcm53115M_reg_write(0x41, 0x10+i, (u8 *)&u32_val, 4); ++ } ++ ++ // for IMP port ++ bcm53115M_reg_read(0x41, 0x30, (u8 *)&u32_val, 4); ++ u32_val &= ~((1<<28) | (1<<22)); ++ bcm53115M_reg_write(0x41, 0x30, (u8 *)&u32_val, 4); ++ ++ /* Misc */ ++ // led ++ bcm53115M_led_init(); ++ // multicast fwd rule, Page 00h, Address 2Fh ++ bval = 0; ++ bcm53115M_reg_write(0x00, 0x2F, &bval, 1); ++ ++#ifdef BCM53115M_DISABLE_LEARNING ++ // disable learning ++ page=0x00; ++ offset=0x3c; ++ u16_val=0x13f; ++ bcm53115M_reg_write(page, offset, (u8 *)&u16_val, 2); ++ bcm53115M_reg_read(page, offset, (u8 *)&u16_val, 2); ++ ++ page=0x02; ++ offset=0x06; ++ u32_val=4; ++ bcm53115M_reg_write(page, offset, (u8 *)&u32_val, 4); ++#endif ++#endif ++ return CAVM_OK; ++} ++#endif // defined(LINUX_KERNEL) ++ ++//#define MAC2_RGMII ++#define CNS3XXX_MAC2_IP1001_GIGA_MODE ++ ++void icp_ip1001_init_mac(u8 mac_port, u16 phy_addr) ++{ ++ u32 mac_port_config = 0; ++ u8 mac_addr[]={0x0c, 0x10, 0x18}; ++ ++ cns3xxx_enable_mac_clock(mac_port, 1); ++ ++ mac_port_config = SWITCH_REG_VALUE(mac_addr[mac_port]); ++ ++ //cns3xxx_txc_dly(mac_port, 2); ++ //cns3xxx_rxc_dly(mac_port, 2); ++ //SLK_SKEW_CTRL_REG ++#if 1 ++ ++ // enable GMII, MII, reverse MII ++ mac_port_config &= (~(1 << 15)); ++ ++#ifdef MAC2_RGMII ++ mac_port_config |= (1 << 15); ++#endif ++ ++ // TXC check disable ++ //mac_port_config &= (~(1 << 13)); ++ ++ // disable GIGA mode ++ mac_port_config &= (~(1<<16)); ++ ++#ifdef CNS3XXX_MAC2_IP1001_GIGA_MODE ++ // enable GIGA mode ++ mac_port_config |= (1<<16); ++ ++ //mac_port_config |= (1<<19); ++#endif ++ ++ // disable PHY's AN ++ mac_port_config &= (~(0x1 << 7)); ++ ++ // enable PHY's AN ++ mac_port_config |= (0x1 << 7); ++#else ++ // disable PHY's AN ++ mac_port_config &= (~(0x1 << 7)); ++ // disable GIGA mode ++ mac_port_config &= (~(1<<16)); ++ ++ // force 100Mbps ++ mac_port_config &= (~(0x3 << 8)); ++ mac_port_config |= (0x1 << 8); ++ ++ // force duplex ++ mac_port_config |= (0x1 << 10); ++ ++ // TX flow control off ++ mac_port_config &= (~(0x1 << 12)); ++ ++ // RX flow control off ++ mac_port_config &= (~(0x1 << 11)); ++ ++#if 0 ++ // TX flow control on ++ mac_port_config |= (0x1 << 12); ++ ++ // RX flow control on ++ mac_port_config |= (0x1 << 11); ++#endif ++ ++ // enable GMII, MII, reverse MII ++ mac_port_config &= (~(1 << 15)); ++#endif ++ SWITCH_REG_VALUE(mac_addr[mac_port]) = mac_port_config; ++ ++ // If mac port AN turns on, auto polling needs to turn on. ++ cns3xxx_phy_auto_polling_conf(mac_port, phy_addr); ++ ++} ++ ++int icp_ip1001_init(u8 mac_port, u8 phy_addr) ++{ ++ u16 phy_data = 0; ++ ++ printk("mac_port: %d ## phy_addr: %d\n", mac_port, phy_addr); ++ cns3xxx_mdc_mdio_disable(0); ++ ++#if 0 ++ // GMII2 high speed drive strength ++ IOCDA_REG &= ((~3 << 10)); ++ IOCDA_REG |= (1 << 10); ++#endif ++ IOCDA_REG = 0x55555800; ++ ++ phy_data = get_phy_id(phy_addr); // should be 0x243 ++ ++ printk("ICPLUS IP 1001 phy id : %x\n", phy_data); ++ ++ if (phy_data != 0x0243) { ++ printk("wrong phy id!!\n"); ++ return CAVM_ERR; ++ } ++ ++ ++ cns3xxx_phy_reset(phy_addr); ++ ++ icp_ip1001_init_mac(mac_port, phy_addr); ++ ++ // read advertisement register ++ cns3xxx_read_phy(phy_addr, 0x4, &phy_data); ++ ++ // enable PAUSE frame capability ++ phy_data |= (0x1 << 10); ++ ++ phy_data &= (~(0x1 << 5)); ++ phy_data &= (~(0x1 << 6)); ++ phy_data &= (~(0x1 << 7)); ++ phy_data &= (~(0x1 << 8)); ++ ++#if 1 ++ phy_data |= (0x1 << 5); ++ phy_data |= (0x1 << 6); ++ phy_data |= (0x1 << 7); ++ phy_data |= (0x1 << 8); ++#endif ++ ++ cns3xxx_write_phy(phy_addr, 0x4, phy_data); ++ ++ cns3xxx_read_phy(phy_addr, 9, &phy_data); ++ ++ phy_data &= (~(1<<8)); // remove advertise 1000 half duples ++ phy_data &= (~(1<<9)); // remove advertise 1000 full duples ++#ifdef CNS3XXX_MAC2_IP1001_GIGA_MODE ++ //phy_data |= (1<<8); // add advertise 1000 half duples ++ phy_data |= (1<<9); // add advertise 1000 full duples ++#endif ++ cns3xxx_write_phy(phy_addr, 9, phy_data); ++ ++ cns3xxx_read_phy(phy_addr, 9, &phy_data); ++ ++ cns3xxx_read_phy(phy_addr, 0, &phy_data); ++ // AN enable ++ phy_data |= (0x1 << 12); ++ cns3xxx_write_phy(phy_addr, 0, phy_data); ++ ++ cns3xxx_read_phy(phy_addr, 0, &phy_data); ++ // restart AN ++ phy_data |= (0x1 << 9); ++ cns3xxx_write_phy(phy_addr, 0, phy_data); ++ return 0; ++} ++ ++#define PHY_CONTROL_REG_ADDR 0x00 ++#define PHY_AN_ADVERTISEMENT_REG_ADDR 0x04 ++ ++int icp_101a_init_mac(u8 port, u8 phy_addr) ++{ ++ u32 mac_port_config = 0; ++ ++ cns3xxx_enable_mac_clock(port, 1); ++ ++ switch (port) ++ { ++ case 0: ++ { ++ mac_port_config = MAC0_CFG_REG; ++ break; ++ } ++ case 1: ++ { ++ mac_port_config = MAC1_CFG_REG; ++ break; ++ } ++ case 2: ++ { ++ mac_port_config = MAC2_CFG_REG; ++ break; ++ } ++ } ++ ++ // enable GMII, MII, reverse MII ++ mac_port_config &= (~(1 << 15)); ++ ++ // disable PHY's AN, use force mode ++ mac_port_config &= (~(0x1 << 7)); ++#ifdef CONFIG_FPGA_FORCE ++ ++ // force 100Mbps ++ mac_port_config &= (~(0x3 << 8)); ++ mac_port_config |= (0x1 << 8); ++ ++ // force duplex ++ mac_port_config |= (0x1 << 10); ++ ++ // TX flow control on ++ mac_port_config |= (0x1 << 12); ++ ++ // RX flow control on ++ mac_port_config |= (0x1 << 11); ++ ++ // Turn off GSW_PORT_TX_CHECK_EN_BIT ++ mac_port_config &= (~(0x1 << 13)); ++#else ++ // enable PHY's AN ++ mac_port_config |= (0x1 << 7); ++ // If mac port AN turns on, auto polling needs to turn on. ++ cns3xxx_phy_auto_polling_conf(port, phy_addr); ++#endif ++ // normal MII ++ mac_port_config &= (~(1 << 14)); ++ ++ ++ switch (port) ++ { ++ case 0: ++ { ++ MAC0_CFG_REG = mac_port_config; ++ break; ++ } ++ case 1: ++ { ++ MAC1_CFG_REG = mac_port_config; ++ break; ++ } ++ case 2: ++ { ++ MAC2_CFG_REG = mac_port_config; ++ break; ++ } ++ } ++ ++ ++ return CAVM_OK; ++} ++ ++int icp_101a_init(u8 mac_port, u8 phy_addr) ++{ ++ u32 mac_port_config=0; ++ u16 phy_data = 0; ++ ++ cns3xxx_mdc_mdio_disable(0); ++ cns3xxx_phy_reset(phy_addr); ++ ++ phy_data = get_phy_id(mac_port); ++ if (phy_data != 0x0243) { ++ printk("ICPLUS 101A phy id should be 0x243, but the phy id is : %x\n", phy_data); ++ return CAVM_ERR; ++ } ++ printk("phy id : %x\n", phy_data); ++ printk("init IC+101A\n"); ++ ++ icp_101a_init_mac(mac_port, phy_addr); ++ ++ // read advertisement register ++ cns3xxx_read_phy(phy_addr, 0x4, &phy_data); ++ ++ // enable PAUSE frame capability ++ phy_data |= (0x1 << 10); ++ ++ cns3xxx_write_phy(phy_addr, 0x4, phy_data); ++ ++#ifndef CONFIG_FPGA_FORCE ++ ++ switch (mac_port) ++ { ++ case 0: ++ { ++ mac_port_config = MAC0_CFG_REG; ++ break; ++ } ++ case 1: ++ { ++ mac_port_config = MAC1_CFG_REG; ++ break; ++ } ++ case 2: ++ { ++ mac_port_config = MAC2_CFG_REG; ++ break; ++ } ++ } ++ ++#if 0 ++ if (!(mac_port_config & (0x1 << 5))) { ++ if (cns3xxx_read_phy (port, PHY_AN_ADVERTISEMENT_REG_ADDR, &phy_data) == CAVM_ERR) ++ { ++ //PDEBUG("\n PORT%d, enable local flow control capability Fail\n", port); ++ return CAVM_ERR; ++ } ++ else ++ { ++ // enable PAUSE frame capability ++ phy_data |= (0x1 << 10); ++ ++ if (cns3xxx_write_phy (port, PHY_AN_ADVERTISEMENT_REG_ADDR, phy_data) == CAVM_ERR) ++ { ++ //PDEBUG("\nPORT%d, enable PAUSE frame capability Fail\n", port); ++ return CAVM_ERR; ++ } ++ } ++ } ++#endif ++ ++ cns3xxx_read_phy(phy_addr, 0, &phy_data); ++ // an enable ++ phy_data |= (0x1 << 12); ++ ++ // restart AN ++ phy_data |= (0x1 << 9); ++ cns3xxx_write_phy(phy_addr, 0, phy_data); ++ ++ while (1) ++ { ++ //PDEBUG ("\n Polling PHY%d AN \n", port); ++ cns3xxx_read_phy (phy_data, 0, &phy_data); ++ ++ if (phy_data & (0x1 << 9)) { ++ continue; ++ } else { ++ //PDEBUG ("\n PHY%d AN restart is complete \n", port); ++ break; ++ } ++ } ++ ++#endif ++ ++ return CAVM_OK; ++} ++ ++int cns3xxx_config_VSC8601_mac(u8 port) ++{ ++ u32 mac_port_config = 0; ++ ++ switch (port) ++ { ++ case 0: ++ { ++ mac_port_config = MAC0_CFG_REG; ++ break; ++ } ++ case 1: ++ { ++ mac_port_config = MAC1_CFG_REG; ++ break; ++ } ++ case 2: ++ { ++ mac_port_config = MAC2_CFG_REG; ++ break; ++ } ++ } ++ ++ switch (port) ++ { ++ case 0: ++ { ++ MAC0_CFG_REG = mac_port_config; ++ break; ++ } ++ case 1: ++ { ++ MAC1_CFG_REG = mac_port_config; ++ break; ++ } ++ case 2: ++ { ++ MAC2_CFG_REG = mac_port_config; ++ break; ++ } ++ } ++ return CAVM_OK; ++} ++ ++u16 get_phy_id(u8 phy_addr) ++{ ++ u16 read_data; ++ ++ cns3xxx_read_phy(phy_addr, 2, &read_data); ++ ++ return read_data; ++} ++ ++u32 get_vsc8601_recv_err_counter(u8 phy_addr) ++{ ++ u16 read_data=0; ++ cns3xxx_read_phy(phy_addr, 19, &read_data); ++ return read_data; ++} ++ ++u32 get_crc_good_counter(u8 phy_addr) ++{ ++ u16 read_data=0; ++ ++ // enter extended register mode ++ cns3xxx_write_phy(phy_addr, 31, 0x0001); ++ ++ cns3xxx_read_phy(phy_addr, 18, &read_data); ++ ++ // back to normal register mode ++ cns3xxx_write_phy(phy_addr, 31, 0x0000); ++ ++ return read_data; ++} ++ ++int cns3xxx_config_VSC8601(u8 mac_port, u8 phy_addr) ++{ ++ u16 phy_data=0; ++ u32 mac_port_config=0; ++ //u8 tx_skew=1, rx_skew=1; ++ u16 phy_id=0; ++ ++ cns3xxx_mdc_mdio_disable(0); ++ ++ cns3xxx_read_phy(phy_addr, 0, &phy_data); ++ // software reset ++ phy_data |= (0x1 << 15); ++ cns3xxx_write_phy(phy_addr, 0, phy_data); ++ udelay(10); ++ ++ phy_id = get_phy_id(phy_addr); ++ if (phy_id != 0x143) { ++ return CAVM_ERR; ++ } ++ ++ switch (mac_port) ++ { ++ case 0: ++ { ++ mac_port_config = MAC0_CFG_REG; ++ break; ++ } ++ case 1: ++ { ++ mac_port_config = MAC1_CFG_REG; ++ break; ++ } ++ case 2: ++ { ++ mac_port_config = MAC2_CFG_REG; ++ break; ++ } ++ } ++ ++ cns3xxx_enable_mac_clock(mac_port, 1); ++ //phy_auto_polling(mac_port, phy_addr); ++ ++ // enable RGMII-PHY mode ++ mac_port_config |= (0x1 << 15); ++ ++ // If mac AN turns on, auto polling needs to turn on. ++ // enable PHY's AN ++ mac_port_config |= (0x1 << 7); ++ cns3xxx_phy_auto_polling_conf(mac_port, phy_addr); ++ ++ // enable GSW MAC port 0 ++ mac_port_config &= ~(0x1 << 18); ++ ++ // normal MII ++ mac_port_config &= (~(1 << 14)); ++ ++ switch (mac_port) ++ { ++ case 0: ++ { ++ MAC0_CFG_REG = mac_port_config; ++ printk("8601 MAC0_CFG_REG: %x\n", MAC0_CFG_REG); ++ break; ++ } ++ case 1: ++ { ++ MAC1_CFG_REG = mac_port_config; ++ printk("8601 MAC1_CFG_REG: %x\n", MAC1_CFG_REG); ++ break; ++ } ++ case 2: ++ { ++ MAC2_CFG_REG = mac_port_config; ++ break; ++ } ++ } ++ ++ cns3xxx_write_phy(phy_addr, 0x18, 0xf1e7); ++ cns3xxx_write_phy(phy_addr, 0x1c, 0x8e00); ++ cns3xxx_write_phy(phy_addr, 0x10, 0x20); ++ cns3xxx_write_phy(phy_addr, 0x1c, 0xa41f); ++ cns3xxx_write_phy(phy_addr, 0x1c, 0xb41a); ++ cns3xxx_write_phy(phy_addr, 0x1c, 0xb863); ++ cns3xxx_write_phy(phy_addr, 0x17, 0xf04); ++ cns3xxx_write_phy(phy_addr, 0x15, 0x1); ++ cns3xxx_write_phy(phy_addr, 0x17, 0x0); ++ ++ return CAVM_OK; ++} ++ ++ ++ ++#ifdef CONFIG_LIBRA ++void icp_175c_all_phy_power_down(int y) ++{ ++ int i=0; ++ ++ for (i=0 ; i < 5 ; ++i) ++ std_phy_power_down(i, y); ++ ++} ++ ++static int star_gsw_config_icplus_175c_phy4(void) ++{ ++ u16 phy_data = 0, phy_data2 = 0; ++ u32 volatile ii, jj; ++ u8 phy_speed_dup = 0, phy_flowctrl = 0; ++ u32 volatile reg; ++ u8 gsw_mac_0_phy_addr = 0; ++ u8 gsw_mac_1_phy_addr = 1; ++ ++ ++ printk("config IC+175C\n"); ++ /* ++ * Configure MAC port 0 ++ * For IP175C Switch setting ++ * Force 100Mbps, and full-duplex, and flow control on ++ */ ++ reg = GSW_MAC_PORT_0_CONFIG_REG; ++ ++ // disable PHY's AN ++ reg &= ~(0x1 << 7); ++ ++ // disable RGMII-PHY mode ++ reg &= ~(0x1 << 15); ++ ++ // force speed = 100Mbps ++ reg &= ~(0x3 << 8); ++ reg |= (0x1 << 8); ++ ++ // force full-duplex ++ reg |= (0x1 << 10); ++ ++ // force Tx/Rx flow-control on ++ reg |= (0x1 << 11) | (0x1 << 12); ++ ++ GSW_MAC_PORT_0_CONFIG_REG = reg; ++ ++ ++ for (ii = 0; ii < 0x2000; ii++) ++ { ++ reg = GSW_MAC_PORT_0_CONFIG_REG; ++ ++ if ((reg & 0x1) && !(reg & 0x2)) ++ { ++ /* ++ * enable MAC port 0 ++ */ ++ reg &= ~(0x1 << 18); ++ ++ ++ /* ++ * enable the forwarding of unknown, multicast and broadcast packets to CPU ++ */ ++ reg &= ~((0x1 << 25) | (0x1 << 26) | (0x1 << 27)); ++ ++ /* ++ * include unknown, multicast and broadcast packets into broadcast storm ++ */ ++ reg |= ((0x1 << 29) | (0x1 << 30) | ((u32)0x1 << 31)); ++ ++ GSW_MAC_PORT_0_CONFIG_REG = reg; ++ ++ break; ++ } ++ else ++ { ++ for (jj = 0; jj < 0x1000; jj++); ++ ++ ++ if ((ii % 4) == 0) ++ printk("\rCheck MAC/PHY 0 Link Status : |"); ++ else if ((ii % 4) == 1) ++ printk("\rCheck MAC/PHY 0 Link Status : /"); ++ else if ((ii % 4) == 2) ++ printk("\rCheck MAC/PHY 0 Link Status : -"); ++ else if ((ii % 4) == 3) ++ printk("\rCheck MAC/PHY 0 Link Status : \\"); ++ } ++ } ++ ++ ++ if (!(reg & 0x1) || (reg & 0x2)) ++ { ++ /* ++ * Port 0 PHY link down or no TXC in Port 0 ++ */ ++ printk("\rCheck MAC/PHY 0 Link Status : DOWN!\n"); ++ ++ return -1; ++ } ++ else ++ { ++ printk("\rCheck MAC/PHY 0 Link Status : UP!\n"); ++ } ++ ++ ++ ++ /* ++ * Configure MAC port 1 ++ */ ++ reg = GSW_MAC_PORT_0_CONFIG_REG; ++ ++ // disable MAC's AN ++ reg &= ~(0x1 << 7); ++ ++ GSW_MAC_PORT_0_CONFIG_REG = reg; ++ ++ ++ /* enable flow control on (PAUSE frame) */ ++ star_gsw_read_phy(gsw_mac_1_phy_addr, 0x4, &phy_data); ++ ++ phy_data |= (0x1 << 10); ++ ++ star_gsw_write_phy(gsw_mac_1_phy_addr, 0x4, phy_data); ++ ++#if 1 ++ /* 2007/12/18 Jerry ++ The software reset of IC+ 175C won't reset MII register 29, 30, 31. ++ Router Control Register: bit 7 (TAG_VLAN_EN) is a VLAN related filed which affect vlan setting. ++ Router Control Register: bit 3 (ROUTER_EN) enable router function at MII port. ++ We set them to default to let U-boot properly work. ++ */ ++ phy_data = 0x1001; ++ star_gsw_write_phy(30, 9, phy_data); ++#endif ++ /* restart PHY auto neg. */ ++ star_gsw_read_phy(gsw_mac_1_phy_addr, 0x0, &phy_data); ++ ++ phy_data |= (0x1 << 9) | (0x1 << 12); ++ ++ star_gsw_write_phy(gsw_mac_1_phy_addr, 0x0, phy_data); ++ ++ ++ ++ /* wait for PHY auto neg. complete */ ++ for (ii = 0; ii < 0x20; ii++) ++ { ++ star_gsw_read_phy(gsw_mac_1_phy_addr, 0x1, &phy_data); ++ ++ if ((phy_data & (0x1 << 2)) && (phy_data & (0x1 << 5))) ++ { ++ break; ++ } ++ else ++ { ++ if ((ii % 4) == 0) ++ printk("\rCheck MAC/PHY 1 Link Status : |"); ++ else if ((ii % 4) == 1) ++ printk("\rCheck MAC/PHY 1 Link Status : /"); ++ else if ((ii % 4) == 2) ++ printk("\rCheck MAC/PHY 1 Link Status : -"); ++ else if ((ii % 4) == 3) ++ printk("\rCheck MAC/PHY 1 Link Status : \\"); ++ } ++ } ++ ++ ++ if (ii >= 0x20) ++ { ++ printk("\rCheck MAC/PHY 1 Link Status : DOWN!\n"); ++ ++ return -1; ++ } ++ else ++ { ++ printk("\rCheck MAC/PHY 1 Link Status : UP!\n"); ++ } ++ ++ ++ star_gsw_read_phy(gsw_mac_1_phy_addr, 0x4, &phy_data); ++ ++ star_gsw_read_phy(gsw_mac_1_phy_addr, 0x5, &phy_data2); ++ ++ ++ if (phy_data & 0x0400) //FC on ++ { ++ //printk("<FC ON>"); ++ phy_flowctrl = 1; ++ } ++ else ++ { ++ // printk("<FC OFF>"); ++ phy_flowctrl = 0; ++ } ++ ++ ++ phy_speed_dup = 0; ++ ++ if ((phy_data & 0x0100) && (phy_data2 & 0x0100)) //100F ++ { ++ // printk("<100F>"); ++ phy_speed_dup |= (0x1 << 3); //set bit3 for 100F ++ } ++ else if ((phy_data & 0x0080) && (phy_data2 & 0x0080)) //100F ++ { ++ // printk("<100H>"); ++ phy_speed_dup |= (0x1 << 2); ++ } ++ else if ((phy_data & 0x0040) && (phy_data2 & 0x0040)) //100F ++ { ++ // printk("<10F>"); ++ phy_speed_dup |= (0x1 << 1); ++ } ++ else if ((phy_data & 0x0020) && (phy_data2 & 0x0020)) //100F ++ { ++ // printk("<10H>"); ++ phy_speed_dup |= 0x1; ++ } ++ ++ ++ /* ++ * Configure MAC port 1 in forced setting subject to the current PHY status ++ */ ++ reg = GSW_MAC_PORT_1_CONFIG_REG; ++ ++ reg &= ~(0x1 << 7); //AN off ++ ++ reg &= ~(0x3 << 8); ++ ++ if (phy_speed_dup & 0x0C) //100 ++ { ++ //printk("<set 100>"); ++ reg |= (0x01 << 8); ++ } ++ else if (phy_speed_dup & 0x03) //10 ++ { ++ //printk("<set 10>"); ++ reg |= (0x00 << 8); ++ } ++ ++ reg &= ~(0x1 << 11); ++ ++ if (phy_flowctrl) //FC on ++ { ++ //printk("<set FC on>"); ++ reg |= (0x1 << 11); ++ } ++ else ++ { ++ //printk("<set FC off>"); ++ reg |= (0x0 << 11); ++ } ++ ++ reg &= ~(0x1 << 10); ++ ++ if ((phy_speed_dup & 0x2) || (phy_speed_dup & 0x8)) //FullDup ++ { ++ //printk("<set full>"); ++ reg |= (0x1 << 10); ++ } ++ else //HalfDup ++ { ++ //printk("<set half>"); ++ reg |= (0x0 << 10); //Half ++ } ++ ++ GSW_MAC_PORT_1_CONFIG_REG = reg; ++ ++ ++ /* ++ * Check MAC port 1 link status ++ */ ++ for (ii = 0; ii < 0x1000; ii++) ++ { ++ reg = GSW_MAC_PORT_1_CONFIG_REG; ++ ++ if ((reg & 0x1) && !(reg & 0x2)) ++ { ++ /* ++ * enable MAC port 1 ++ */ ++ reg &= ~(0x1 << 18); ++ ++ /* ++ * enable the forwarding of unknown, multicast and broadcast packets to CPU ++ */ ++ reg &= ~((0x1 << 25) | (0x1 << 26) | (0x1 << 27)); ++ ++ /* ++ * include unknown, multicast and broadcast packets into broadcast storm ++ */ ++ reg |= ((0x1 << 29) | (0x1 << 30) | ((u32)0x1 << 31)); ++ ++ GSW_MAC_PORT_1_CONFIG_REG = reg; ++ ++ return 0; ++ } ++ } ++ ++ ++ if (ii > 0x1000) ++ { ++ /* ++ * Port 1 PHY link down or no TXC in Port 1 ++ */ ++ printk("\rCheck MAC/PHY 1 Link Status : DOWN!\n"); ++ ++ return -1; ++ } ++ return 0; ++} ++#endif ++ ++#if 0 ++static int star_gsw_config_VSC8201(u8 mac_port, u8 phy_addr) // include cicada 8201 ++{ ++ //u32 mac_port_base = 0; ++ u32 mac_port_config=0; ++ u16 phy_reg; ++ int i; ++ ++ printk("\nconfigure VSC8201\n"); ++ //PDEBUG("mac port : %d phy addr : %d\n", mac_port, phy_addr); ++ /* ++ * Configure MAC port 0 ++ * For Cicada CIS8201 single PHY ++ */ ++ if (mac_port == 0) { ++ //PDEBUG("port 0\n"); ++ mac_port_config = GSW_MAC_PORT_0_CONFIG_REG; ++ } ++ if (mac_port == 1) { ++ //PDEBUG("port 1\n"); ++ mac_port_config = GSW_MAC_PORT_1_CONFIG_REG; ++ } ++ ++ star_gsw_set_phy_addr(mac_port, phy_addr); ++ //star_gsw_set_phy_addr(1, 1); ++ ++ //mac_port_config = __REG(mac_port_base); ++ ++ // enable PHY's AN ++ mac_port_config |= (0x1 << 7); ++ ++ // enable RGMII-PHY mode ++ mac_port_config |= (0x1 << 15); ++ ++ // enable GSW MAC port 0 ++ mac_port_config &= ~(0x1 << 18); ++ ++ if (mac_port == 0) { ++ //PDEBUG("port 0\n"); ++ GSW_MAC_PORT_0_CONFIG_REG = mac_port_config; ++ } ++ if (mac_port == 1) { ++ //PDEBUG("port 1\n"); ++ GSW_MAC_PORT_1_CONFIG_REG = mac_port_config; ++ } ++ ++ /* ++ * Configure Cicada's CIS8201 single PHY ++ */ ++#ifdef CONFIG_STAR9100_SHNAT_PCI_FASTPATH ++ /* near-end loopback mode */ ++ star_gsw_read_phy(phy_addr, 0x0, &phy_reg); ++ phy_reg |= (0x1 << 14); ++ star_gsw_write_phy(phy_addr, 0x0, phy_reg); ++#endif ++ ++ star_gsw_read_phy(phy_addr, 0x1C, &phy_reg); ++ ++ // configure SMI registers have higher priority over MODE/FRC_DPLX, and ANEG_DIS pins ++ phy_reg |= (0x1 << 2); ++ ++ star_gsw_write_phy(phy_addr, 0x1C, phy_reg); ++ ++ star_gsw_read_phy(phy_addr, 0x17, &phy_reg); ++ ++ // enable RGMII MAC interface mode ++ phy_reg &= ~(0xF << 12); ++ phy_reg |= (0x1 << 12); ++ ++ // enable RGMII I/O pins operating from 2.5V supply ++ phy_reg &= ~(0x7 << 9); ++ phy_reg |= (0x1 << 9); ++ ++ star_gsw_write_phy(phy_addr, 0x17, phy_reg); ++ ++ star_gsw_read_phy(phy_addr, 0x4, &phy_reg); ++ ++ // Enable symmetric Pause capable ++ phy_reg |= (0x1 << 10); ++ ++ star_gsw_write_phy(phy_addr, 0x4, phy_reg); ++ ++ ++ ++ if (mac_port == 0) { ++ //PDEBUG("port 0\n"); ++ mac_port_config = GSW_MAC_PORT_0_CONFIG_REG; ++ } ++ if (mac_port == 1) { ++ //PDEBUG("port 1\n"); ++ mac_port_config = GSW_MAC_PORT_1_CONFIG_REG; ++ } ++ ++ ++ ++ ++ ++ ++ ++ // enable PHY's AN ++ mac_port_config |= (0x1 << 7); ++ ++ if (mac_port == 0) { ++ //PDEBUG("port 0\n"); ++ GSW_MAC_PORT_0_CONFIG_REG = mac_port_config; ++ } ++ if (mac_port == 1) { ++ //PDEBUG("port 1\n"); ++ GSW_MAC_PORT_1_CONFIG_REG = mac_port_config; ++ } ++ ++ /* ++ * Enable PHY1 AN restart bit to restart PHY1 AN ++ */ ++ star_gsw_read_phy(phy_addr, 0x0, &phy_reg); ++ ++ phy_reg |= (0x1 << 9) | (0x1 << 12); ++ ++ star_gsw_write_phy(phy_addr, 0x0, phy_reg); ++ ++ /* ++ * Polling until PHY0 AN restart is complete ++ */ ++ for (i = 0; i < 0x1000; i++) { ++ star_gsw_read_phy(phy_addr, 0x1, &phy_reg); ++ ++ if ((phy_reg & (0x1 << 5)) && (phy_reg & (0x1 << 2))) { ++ printk("0x1 phy reg: %x\n", phy_reg); ++ break; ++ } else { ++ udelay(100); ++ } ++ } ++ ++ if (mac_port == 0) { ++ //PDEBUG("port 0\n"); ++ mac_port_config = GSW_MAC_PORT_0_CONFIG_REG; ++ } ++ if (mac_port == 1) { ++ //PDEBUG("port 1\n"); ++ mac_port_config = GSW_MAC_PORT_1_CONFIG_REG; ++ } ++ ++ if (((mac_port_config & 0x1) == 0) || (mac_port_config & 0x2)) { ++ printk("Check MAC/PHY%s Link Status : DOWN!\n", (mac_port == 0 ? "0" : "1")); ++ } else { ++ printk("Check MAC/PHY%s Link Status : UP!\n", (mac_port == 0 ? "0" : "1")); ++ /* ++ * There is a bug for CIS8201 PHY operating at 10H mode, and we use the following ++ * code segment to work-around ++ */ ++ star_gsw_read_phy(phy_addr, 0x05, &phy_reg); ++ ++ if ((phy_reg & (0x1 << 5)) && (!(phy_reg & (0x1 << 6))) && (!(phy_reg & (0x1 << 7))) && (!(phy_reg & (0x1 << 8)))) { /* 10H,10F/100F/100H off */ ++ star_gsw_read_phy(phy_addr, 0x0a, &phy_reg); ++ ++ if ((!(phy_reg & (0x1 << 10))) && (!(phy_reg & (0x1 << 11)))) { /* 1000F/1000H off */ ++ star_gsw_read_phy(phy_addr, 0x16, &phy_reg); ++ ++ phy_reg |= (0x1 << 13) | (0x1 << 15); // disable "Link integrity check(B13)" & "Echo mode(B15)" ++ ++ star_gsw_write_phy(phy_addr, 0x16, phy_reg); ++ } ++ } ++ } ++ ++ if (mac_port == 0) { ++ // adjust MAC port 0 RX/TX clock skew ++ GSW_BIST_RESULT_TEST_0_REG &= ~((0x3 << 24) | (0x3 << 26)); ++ GSW_BIST_RESULT_TEST_0_REG |= ((0x2 << 24) | (0x2 << 26)); ++ } ++ ++ if (mac_port == 1) { ++ // adjust MAC port 1 RX/TX clock skew ++ GSW_BIST_RESULT_TEST_0_REG &= ~((0x3 << 28) | (0x3 << 30)); ++ GSW_BIST_RESULT_TEST_0_REG |= ((0x2 << 28) | (0x2 << 30)); ++ } ++ ++ return 0; ++} ++ ++ ++ ++ ++static void star_gsw_config_VSC8X01() ++{ ++ u16 phy_id = 0; ++ ++#ifdef CONFIG_DORADO2 ++ star_gsw_set_phy_addr(1,1); ++ star_gsw_read_phy(1, 0x02, &phy_id); ++ // printk("phy id = %X\n", phy_id); ++ if (phy_id == 0x000F) //VSC8201 ++ star_gsw_config_VSC8201(1,1); ++ else ++ star_gsw_config_VSC8601(1,1); ++#else ++#ifdef CONFIG_LEO ++ star_gsw_set_phy_addr(0,0); ++ star_gsw_read_phy(0, 0x02, &phy_id); ++ // printk("phy id = %X\n", phy_id); ++ if (phy_id == 0x000F) //VSC8201 ++ star_gsw_config_VSC8201(0,0); ++ else ++ star_gsw_config_VSC8601(0,0); ++#endif ++#endif ++} ++#endif ++ ++#if defined(CONFIG_DORADO) || defined(CONFIG_DORADO2) ++static int star_gsw_config_port0_VSC7385(void) ++{ ++ u32 mac_port_config=0; ++ int i; ++ ++ printk("config VSC7385\n"); ++ ++ mac_port_config = GSW_MAC_PORT_0_CONFIG_REG; ++ ++ // disable PHY's AN ++ mac_port_config &= ~(0x1 << 7); ++ ++ // enable RGMII-PHY mode ++ mac_port_config |= (0x1 << 15); ++ ++ // force speed = 1000Mbps ++ mac_port_config &= ~(0x3 << 8); ++ mac_port_config |= (0x2 << 8); ++ ++ // force full-duplex ++ mac_port_config |= (0x1 << 10); ++ ++ // force Tx/Rx flow-control on ++ mac_port_config |= (0x1 << 11) | (0x1 << 12); ++ ++ GSW_MAC_PORT_0_CONFIG_REG = mac_port_config; ++ ++ udelay(1000); ++ ++ for (i = 0; i < 50000; i++) { ++ mac_port_config = GSW_MAC_PORT_0_CONFIG_REG; ++ if ((mac_port_config & 0x1) && !(mac_port_config & 0x2)) { ++ break; ++ } else { ++ udelay(100); ++ } ++ } ++ ++ if (!(mac_port_config & 0x1) || (mac_port_config & 0x2)) { ++ printk("MAC0 PHY Link Status : DOWN!\n"); ++ return -1; ++ } else { ++ printk("MAC0 PHY Link Status : UP!\n"); ++ } ++ ++ // enable MAC port 0 ++ mac_port_config &= ~(0x1 << 18); ++ ++ // disable SA learning ++ mac_port_config |= (0x1 << 19); ++ ++ // forward unknown, multicast and broadcast packets to CPU ++ mac_port_config &= ~((0x1 << 25) | (0x1 << 26) | (0x1 << 27)); ++ ++ // storm rate control for unknown, multicast and broadcast packets ++ mac_port_config |= (0x1 << 29) | (0x1 << 30) | ((u32)0x1 << 31); ++ ++ GSW_MAC_PORT_0_CONFIG_REG = mac_port_config; ++ ++ // disable MAC port 1 ++ mac_port_config = GSW_MAC_PORT_1_CONFIG_REG; ++ mac_port_config |= (0x1 << 18); ++ GSW_MAC_PORT_1_CONFIG_REG = mac_port_config; ++ ++ // adjust MAC port 0 /RX/TX clock skew ++ GSW_BIST_RESULT_TEST_0_REG &= ~((0x3 << 24) | (0x3 << 26)); ++ GSW_BIST_RESULT_TEST_0_REG |= ((0x2 << 24) | (0x2 << 26)); ++ ++ return 0; ++} ++#endif +--- /dev/null ++++ b/drivers/net/cns3xxx/cns3xxx_phy.h +@@ -0,0 +1,82 @@ ++/******************************************************************************* ++ * ++ * ++ * Copyright (c) 2009 Cavium Networks ++ * ++ * 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 ++1* 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. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ ********************************************************************************/ ++ ++#ifndef CNS3XXX_PHY_H ++#define CNS3XXX_PHY_H ++ ++#define LINUX_KERNEL // if don't define LINUX_KERNEL, mean u-boot ++ ++#if defined(LINUX_KERNEL) ++#include <linux/version.h> ++#include <linux/types.h> ++#else // u-boot ++#define __init_or_module ++#include "cns3xxx_symbol.h" ++#endif ++ ++void disable_AN(int port, int y); ++ ++u16 get_phy_id(u8 phy_addr); ++int cns3xxx_std_phy_power_down(int phy_addr, int y); ++u32 get_vsc8601_recv_err_counter(u8 phy_addr); ++u32 get_crc_good_counter(u8 phy_addr); ++int cns3xxx_config_VSC8601(u8 mac_port, u8 phy_addr); ++int vsc8601_power_down(int phy_addr, int y); ++int icp_101a_init(u8 mac_port, u8 phy_addr); ++int bcm53115M_init(u8 mac_port, u16 phy_addr); ++int icp_ip1001_init(u8 mac_port, u8 phy_addr); ++ ++int cns3xxx_phy_auto_polling_enable(u8 port, u8 en); ++ ++int cns3xxx_read_phy(u8 phy_addr, u8 phy_reg, u16 *read_data); ++int cns3xxx_write_phy(u8 phy_addr, u8 phy_reg, u16 write_data); ++ ++// wrap cns3xxx_spi_tx_rx() for argument order ++int cns3xxx_spi_tx_rx_n(u32 tx_data, u32 *rx_data, u32 tx_channel, u32 tx_eof_flag); ++ ++// for bcm53115M ++#define ROBO_SPIF_BIT 7 ++#define BCM53115_SPI_CHANNEL 1 ++#define ROBO_RACK_BIT 5 ++ ++#define VLAN_START_BIT 7 ++#define VLAN_WRITE_CMD 0 ++ ++//#define BCM_PORT_1G 2 ++typedef enum ++{ ++ BCM_PORT_10M = 0, ++ BCM_PORT_100M, ++ BCM_PORT_1G, ++}BCM_PORT_SPEED; ++ ++#define BCM_PORT_0 0 ++#define BCM_PORT_1 1 ++#define BCM_PORT_2 2 ++#define BCM_PORT_3 3 ++#define BCM_PORT_4 4 ++#define BCM_PORT_5 5 ++#define BCM_PORT_IMP 6 ++ ++#endif // end #ifndef CNS3XXX_PHY_H +--- /dev/null ++++ b/drivers/net/cns3xxx/cns3xxx_sppe_hook.c +@@ -0,0 +1,39 @@ ++/****************************************************************************** ++ * ++ * Copyright (c) 2008 Cavium Networks ++ * ++ * This file is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License, Version 2, as ++ * published by the Free Software Foundation. ++ * ++ * This file is distributed in the hope that it will be useful, ++ * but AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or ++ * NONINFRINGEMENT. See the GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this file; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA or ++ * visit http://www.gnu.org/licenses/. ++ * ++ * This file may also be available under a different license from Cavium. ++ * Contact Cavium Networks for more information ++ * ++ ******************************************************************************/ ++ ++#if defined(CONFIG_CNS3XXX_SPPE) ++#include <linux/module.h> ++#include <linux/cns3xxx/sppe.h> ++ ++int sppe_hook_ready = 0; ++int (*sppe_func_hook)(SPPE_PARAM *param) = NULL; ++int sppe_pci_fp_ready = 0; ++int (*sppe_pci_fp_hook)(SPPE_PARAM *param) = NULL; ++ ++EXPORT_SYMBOL(sppe_hook_ready); ++EXPORT_SYMBOL(sppe_func_hook); ++EXPORT_SYMBOL(sppe_pci_fp_ready); ++EXPORT_SYMBOL(sppe_pci_fp_hook); ++ ++#endif //#if defined(CONFIG_CNS3XXX_SPPE) ++ +--- /dev/null ++++ b/drivers/net/cns3xxx/cns3xxx_symbol.h +@@ -0,0 +1,317 @@ ++/******************************************************************************* ++ * ++ * Copyright (c) 2009 Cavium Networks ++ * ++ * 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. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ ********************************************************************************/ ++ ++// the symbol define memory map register. ++ ++#ifndef CNS3XXX_SYMBOL_H ++#define CNS3XXX_SYMBOL_H ++ ++#define DRV_VERSION "Cavium CNS3XXX Switch Driver-0.0.1" ++ ++ ++#define LINUX_KERNEL // if don't define LINUX_KERNEL, mean u-boot ++ ++#if defined(LINUX_KERNEL) ++// linux kernel ++#include <mach/board.h> ++ ++#define SWITCH_REG_VALUE(offset) (*((volatile unsigned int *)(CNS3XXX_SWITCH_BASE_VIRT+offset))) ++#define PMU_REG_VALUE(offset) (*((volatile unsigned int *)(CNS3XXX_PM_BASE_VIRT+offset))) ++#define MISC_REG_VALUE(offset) (*((volatile unsigned int *)(CNS3XXX_MISC_BASE_VIRT+offset))) ++ ++ ++#define NETDEV_SIZE 4097+3 ++ ++#define PORT0_NETDEV_INDEX NETDEV_SIZE-3 ++#define PORT1_NETDEV_INDEX NETDEV_SIZE-2 ++#define PORT2_NETDEV_INDEX NETDEV_SIZE-1 ++ ++#if defined (CONFIG_CNS3XXX_SPPE) ++#define FP_NETDEV_INDEX NETDEV_SIZE-4 ++#endif ++ ++#define PORT0_NETDEV net_dev_array[PORT0_NETDEV_INDEX] ++#define PORT1_NETDEV net_dev_array[PORT1_NETDEV_INDEX] ++#define PORT2_NETDEV net_dev_array[PORT2_NETDEV_INDEX] ++ ++#if defined (CONFIG_CNS3XXX_SPPE) ++#define FP_NETDEV net_dev_array[FP_NETDEV_INDEX] ++#endif ++ ++#else // u-boot ++#include <malloc.h> // for u8, u32 ++ ++#include "cns3000.h" ++#define CAVM_OK 0 ++#define CAVM_ERR 1 ++#define CAVM_NOT_FOUND 2 ++#define CAVM_FOUND 3 ++#define CAVM_FAIL -1 // use minus ++ ++#define SWITCH_REG_VALUE(addr) (*((volatile unsigned int *)(CNS3000_VEGA_SWITCH_BASE+addr))) ++#define PMU_REG_VALUE(addr) (*((volatile unsigned int *)(CNS3000_VEGA_PM_BASE+addr))) ++#define MISC_REG_VALUE(offset) (*((volatile unsigned int *)(CNS3000_VEGA_MISC_BASE+offset))) ++ ++#endif ++ ++// for VLAN and ARL table MB_PMAP ++#define MAC_PORT0_PMAP 1 ++#define MAC_PORT1_PMAP (1 << 1) ++#define MAC_PORT2_PMAP (1 << 4) ++#define CPU_PORT_PMAP (1 << 2) ++ ++ ++ ++// memory map register definition ++ ++//#define PHY_CTRL_REG (*(u32 volatile*(0xff))) ++#define PHY_CTRL_REG SWITCH_REG_VALUE(0x0) ++#define PHY_AUTO_ADDR_REG SWITCH_REG_VALUE(0x04) ++ ++#define MAC_GLOB_CFG_REG SWITCH_REG_VALUE(0x08) ++#define MAC_GLOB_CFG_EXT_REG SWITCH_REG_VALUE(0xf4) ++#define MAC0_CFG_REG SWITCH_REG_VALUE(0x0c) ++#define MAC1_CFG_REG SWITCH_REG_VALUE(0x10) ++#define MAC2_CFG_REG SWITCH_REG_VALUE(0x18) ++#define CPU_CFG_REG SWITCH_REG_VALUE(0x14) ++ ++#define MAC0_PRI_CTRL_REG SWITCH_REG_VALUE(0x1c) ++#define MAC1_PRI_CTRL_REG SWITCH_REG_VALUE(0x20) ++#define CPU_PRI_CTRL_REG SWITCH_REG_VALUE(0x24) ++#define HNAT_PRI_CTRL_REG SWITCH_REG_VALUE(0x28) ++#define MAC2_PRI_CTRL_REG SWITCH_REG_VALUE(0x2c) ++ ++#define MAC0_PRI_CTRL_EXT_REG SWITCH_REG_VALUE(0x30) ++ ++#define ETYPE1_ETYPE0_REG SWITCH_REG_VALUE(0x34) ++#define ETYPE3_ETYPE2_REG SWITCH_REG_VALUE(0x38) ++ ++#define UDP_RANGE0_REG SWITCH_REG_VALUE(0x3c) ++#define UDP_RANGE1_REG SWITCH_REG_VALUE(0x40) ++#define UDP_RANGE2_REG SWITCH_REG_VALUE(0x44) ++#define UDP_RANGE3_REG SWITCH_REG_VALUE(0x48) ++ ++ ++#define PRIO_ETYPE_UDP_REG SWITCH_REG_VALUE(0x4c) ++ ++#define PRIO_IPDSCP_7_0_REG SWITCH_REG_VALUE(0x50) ++#define PRIO_IPDSCP_15_8_REG SWITCH_REG_VALUE(0x54) ++#define PRIO_IPDSCP_23_16_REG SWITCH_REG_VALUE(0x58) ++#define PRIO_IPDSCP_31_24_REG SWITCH_REG_VALUE(0x5c) ++#define PRIO_IPDSCP_39_32_REG SWITCH_REG_VALUE(0x60) ++#define PRIO_IPDSCP_47_40_REG SWITCH_REG_VALUE(0x64) ++#define PRIO_IPDSCP_55_48_REG SWITCH_REG_VALUE(0x68) ++#define PRIO_IPDSCP_63_56_REG SWITCH_REG_VALUE(0x6c) ++ ++#define TC_CTRL_REG SWITCH_REG_VALUE(0x70) ++#define RATE_CTRL_REG SWITCH_REG_VALUE(0x74) ++ ++#define FC_GLOB_THRS_REG SWITCH_REG_VALUE(0x78) ++#define FC_PORT_THRS_REG SWITCH_REG_VALUE(0x7c) ++#define MC_GLOB_THRS_REG SWITCH_REG_VALUE(0x80) ++#define DC_GLOB_THRS_REG SWITCH_REG_VALUE(0x84) ++ ++#define ARL_VLAN_CMD_REG SWITCH_REG_VALUE(0x88) ++ ++#define ARL_CTRL0_REG SWITCH_REG_VALUE(0x8c) ++#define ARL_CTRL1_REG SWITCH_REG_VALUE(0x90) ++#define ARL_CTRL2_REG SWITCH_REG_VALUE(0x94) ++ ++#define VLAN_CFG SWITCH_REG_VALUE(0x098) ++ ++#define MAC1_MAC0_PVID_REG SWITCH_REG_VALUE(0x9c) ++#define MAC2_CPU_PVID_REG SWITCH_REG_VALUE(0xa0) ++ ++#define VLAN_CTRL0_REG SWITCH_REG_VALUE(0xa4) ++#define VLAN_CTRL1_REG SWITCH_REG_VALUE(0xa8) ++#define VLAN_CTRL2_REG SWITCH_REG_VALUE(0xac) ++ ++#define SESSION_ID_1_0_REG SWITCH_REG_VALUE(0xb0) ++#define SESSION_ID_3_2_REG SWITCH_REG_VALUE(0xb4) ++#define SESSION_ID_5_4_REG SWITCH_REG_VALUE(0xb8) ++#define SESSION_ID_7_6_REG SWITCH_REG_VALUE(0xbc) ++#define SESSION_ID_9_8_REG SWITCH_REG_VALUE(0xc0) ++#define SESSION_ID_11_10_REG SWITCH_REG_VALUE(0xc4) ++#define SESSION_ID_13_12_REG SWITCH_REG_VALUE(0xc8) ++#define SESSION_ID_15_14_REG SWITCH_REG_VALUE(0xcc) ++ ++#define INTR_STAT_REG SWITCH_REG_VALUE(0xd0) ++#define INTR_MASK_REG SWITCH_REG_VALUE(0xd4) ++ ++#define SRAM_TEST_REG SWITCH_REG_VALUE(0xd8) ++ ++#define MEM_QUEUE_REG SWITCH_REG_VALUE(0xdc) ++ ++#define SARL_CTRL_REG SWITCH_REG_VALUE(0xe0) ++#define SARL_OQ_GTH_REG SWITCH_REG_VALUE(0xe4) ++#define SARL_OQ_YTH_REG SWITCH_REG_VALUE(0xe8) ++#define SARL_OQ_RTH_REG SWITCH_REG_VALUE(0xec) ++ ++#define SLK_SKEW_CTRL_REG SWITCH_REG_VALUE(0xf0) ++ ++#define DMA_RING_CTRL_REG SWITCH_REG_VALUE(0x100) ++ ++#define DMA_AUTO_POLL_CFG_REG SWITCH_REG_VALUE(0x104) ++ ++#define DELAY_INTR_CFG_REG SWITCH_REG_VALUE(0x108) ++ ++#define TS_DMA_CTRL0_REG SWITCH_REG_VALUE(0x110) ++#define TS_DESC_PTR0_REG SWITCH_REG_VALUE(0x114) ++#define TS_DESC_BASE_ADDR0_REG SWITCH_REG_VALUE(0x118) ++ ++#define FS_DMA_CTRL0_REG SWITCH_REG_VALUE(0x120) ++#define FS_DESC_PTR0_REG SWITCH_REG_VALUE(0x124) ++#define FS_DESC_BASE_ADDR0_REG SWITCH_REG_VALUE(0x128) ++ ++#define TS_DMA_CTRL1_REG SWITCH_REG_VALUE(0x130) ++#define TS_DESC_PTR1_REG SWITCH_REG_VALUE(0x134) ++#define TS_DESC_BASE_ADDR1_REG SWITCH_REG_VALUE(0x138) ++ ++#define FS_DMA_CTRL1_REG SWITCH_REG_VALUE(0x140) ++#define FS_DESC_PTR1_REG SWITCH_REG_VALUE(0x144) ++#define FS_DESC_BASE_ADDR1_REG SWITCH_REG_VALUE(0x148) ++ ++#define TS_DMA_STA_REG SWITCH_REG_VALUE(0x150) ++#define FS_DMA_STA_REG SWITCH_REG_VALUE(0x154) ++ ++#define TS_MRD_CMD_CNT_REG SWITCH_REG_VALUE(0x158) ++#define TS_MWT_CMD_CNT_REG SWITCH_REG_VALUE(0x15c) ++ ++#define FS_MRD_CMD_CNT_REG SWITCH_REG_VALUE(0x160) ++#define FS_MWT_CMD_CNT_REG SWITCH_REG_VALUE(0x164) ++ ++#define C_RXOKPKT_MAC0_REG SWITCH_REG_VALUE(0x300) ++#define C_RXOKBYTE_MAC0_REG SWITCH_REG_VALUE(0x304) ++#define C_RXRUNT_MAC0_REG SWITCH_REG_VALUE(0x308) ++#define C_RXLONG_MAC0_REG SWITCH_REG_VALUE(0x30c) ++#define C_RXDROP_MAC0_REG SWITCH_REG_VALUE(0x310) ++#define C_RXCRC_MAC0_REG SWITCH_REG_VALUE(0x314) ++#define C_RXARLDROP_MAC0_REG SWITCH_REG_VALUE(0x318) ++#define C_VIDROP_MAC0_REG SWITCH_REG_VALUE(0x31c) ++#define C_VEDROP_MAC0_REG SWITCH_REG_VALUE(0x320) ++#define C_RXRL_MAC0_REG SWITCH_REG_VALUE(0x324) ++#define C_RXPAUSE_MAC0_REG SWITCH_REG_VALUE(0x328) ++ ++#define C_TXOKPKT_MAC0_REG SWITCH_REG_VALUE(0x32c) ++#define C_TXOKBYTE_MAC0_REG SWITCH_REG_VALUE(0x330) ++#define C_TXPAUSECOL_MAC0_REG SWITCH_REG_VALUE(0x334) ++ ++#define C_RXOKPKT_MAC1_REG SWITCH_REG_VALUE(0x400) ++#define C_RXOKBYTE_MAC1_REG SWITCH_REG_VALUE(0x404) ++#define C_RXRUNT_MAC1_REG SWITCH_REG_VALUE(0x408) ++#define C_RXLONG_MAC1_REG SWITCH_REG_VALUE(0x40c) ++#define C_RXDROP_MAC1_REG SWITCH_REG_VALUE(0x410) ++#define C_RXCRC_MAC1_REG SWITCH_REG_VALUE(0x414) ++#define C_RXARLDROP_MAC1_REG SWITCH_REG_VALUE(0x418) ++#define C_VIDROP_MAC1_REG SWITCH_REG_VALUE(0x41c) ++#define C_VEDROP_MAC1_REG SWITCH_REG_VALUE(0x420) ++#define C_RXRL_MAC1_REG SWITCH_REG_VALUE(0x424) ++#define C_RXPAUSE_MAC1_REG SWITCH_REG_VALUE(0x428) ++ ++#define C_TXOKPKT_MAC1_REG SWITCH_REG_VALUE(0x42c) ++#define C_TXOKBYTE_MAC1_REG SWITCH_REG_VALUE(0x430) ++#define C_TXPAUSECOL_MAC1_REG SWITCH_REG_VALUE(0x434) ++ ++#define C_TSOKPKT_CPU_REG SWITCH_REG_VALUE(0x500) ++#define C_TSOKBYTE_CPU_REG SWITCH_REG_VALUE(0x504) ++#define C_TSRUNT_CPU_REG SWITCH_REG_VALUE(0x508) ++#define C_TSLONG_CPU_REG SWITCH_REG_VALUE(0x50c) ++#define C_TSNODSTDROP_CPU_REG SWITCH_REG_VALUE(0x510) ++#define C_TSARLDROP_CPU_REG SWITCH_REG_VALUE(0x514) ++#define C_TSVIDROP_CPU_REG SWITCH_REG_VALUE(0x518) ++#define C_TSVEDROP_CPU_REG SWITCH_REG_VALUE(0x51c) ++#define C_TSRL_CPU_REG SWITCH_REG_VALUE(0x520) ++ ++#define C_FSOKPKT_CPU_REG SWITCH_REG_VALUE(0x524) ++#define C_FSOKBYTE_CPU_REG SWITCH_REG_VALUE(0x528) ++ ++#define C_RXOKPKT_MAC2_REG SWITCH_REG_VALUE(0x600) ++#define C_RXOKBYTE_MAC2_REG SWITCH_REG_VALUE(0x604) ++#define C_RXRUNT_MAC2_REG SWITCH_REG_VALUE(0x608) ++#define C_RXLONG_MAC2_REG SWITCH_REG_VALUE(0x60c) ++#define C_RXDROP_MAC2_REG SWITCH_REG_VALUE(0x610) ++#define C_RXCRC_MAC2_REG SWITCH_REG_VALUE(0x614) ++#define C_RXARLDROP_MAC2_REG SWITCH_REG_VALUE(0x618) ++#define C_VIDROP_MAC2_REG SWITCH_REG_VALUE(0x61c) ++#define C_VEDROP_MAC2_REG SWITCH_REG_VALUE(0x620) ++#define C_RXRL_MAC2_REG SWITCH_REG_VALUE(0x624) ++#define C_RXPAUSE_MAC2_REG SWITCH_REG_VALUE(0x628) ++ ++#define C_TXOKPKT_MAC2_REG SWITCH_REG_VALUE(0x62c) ++#define C_TXOKBYTE_MAC2_REG SWITCH_REG_VALUE(0x630) ++#define C_TXPAUSECOL_MAC2_REG SWITCH_REG_VALUE(0x634) ++ ++#define C_TXOKPKT_MAC0_EXT_REG SWITCH_REG_VALUE(0x72c) ++#define C_TXOKBYTE_MAC0_EXT_REG SWITCH_REG_VALUE(0x730) ++ ++#define CLK_GATE_REG PMU_REG_VALUE(0x0) ++#define SOFT_RST_REG PMU_REG_VALUE(0x4) ++#define PLL_HM_PD_CTRL_REG PMU_REG_VALUE(0x1c) ++ ++#define GPIOB_PIN_EN_REG MISC_REG_VALUE(0x18) ++#define IOCDA_REG MISC_REG_VALUE(0x1c) ++ ++#define LEVEL_HIGH 0 ++#define RISING_EDGE 1 ++ ++#ifdef CONFIG_SILICON ++ ++#define STATUS_INTERRUPT_ID 49 ++ ++#define FSRC_RING0_INTERRUPT_ID 51 ++#define FSQF_RING0_INTERRUPT_ID 53 ++ ++#define FSRC_RING1_INTERRUPT_ID 55 ++#define FSQF_RING1_INTERRUPT_ID 57 ++ ++#define TSTC_RING0_INTERRUPT_ID 50 ++ ++#define TSTC_RING1_INTERRUPT_ID 54 ++ ++#define HNAT_INTERRUPT_ID 58 ++ ++#else ++ ++//#define STATUS_INTERRUPT_ID 49 ++#define STATUS_INTERRUPT_ID 38 ++//#define FSRC_RING0_INTERRUPT_ID 51 ++#define FSRC_RING0_INTERRUPT_ID 40 ++ ++#define TSQE_RING0_INTERRUPT_ID 52 ++ ++//#define FSQF_RING0_INTERRUPT_ID 53 ++#define FSQF_RING0_INTERRUPT_ID 42 ++ ++#define FSQF_RING1_INTERRUPT_ID 46 ++#define FSRC_RING1_INTERRUPT_ID 44 ++ ++//#define FSRC_RING1_INTERRUPT_ID 55 ++ ++#define TSTC_RING0_INTERRUPT_ID 39 ++#define TSTC_RING1_INTERRUPT_ID 43 ++ ++#define TSQE_RING1_INTERRUPT_ID 56 ++#define HNAT_INTERRUPT_ID 58 ++#endif // #ifdef CONFIG_SILICON ++ ++#endif +--- /dev/null ++++ b/drivers/net/cns3xxx/cns3xxx_tool.h +@@ -0,0 +1,898 @@ ++/******************************************************************************* ++ * ++ * ++ * Copyright (c) 2009 Cavium Networks ++ * ++ * 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. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ ********************************************************************************/ ++ ++#ifndef CNS3XXX_TOOL_H ++#define CNS3XXX_TOOL_H ++ ++#define PRINT_INFO printk ++ ++#if defined(__KERNEL__) ++ ++#include "cns3xxx.h" ++#include <linux/kernel.h> // for printk ++ ++#else // u-boot ++ ++#endif ++ ++#define SHOW_DEBUG_MESSAGE ++#ifdef SHOW_DEBUG_MESSAGE ++ ++extern int MSG_LEVEL; ++ ++#define NO_MSG 0 ++#define NORMAL_MSG 1 ++#define WARNING_MSG (1 << 1) ++#define CRITICAL_MSG (1 << 2) ++#define DUMP_RX_PKT_INFO (1 << 3) ++#define DUMP_TX_PKT_INFO (1 << 4) ++ ++#define DEBUG_MSG(msg_level, fmt, args...)\ ++{ \ ++ int i=0; \ ++\ ++ for(i=0 ; i < 3 ; ++i) { \ ++ if ((MSG_LEVEL & msg_level) >> i) \ ++ printk(KERN_INFO "*cns3xxx gsw debug* " fmt, ## args); \ ++ } \ ++} ++ ++#endif ++ ++#define GET_MAC_PORT_CFG(port, cfg) \ ++{ \ ++ switch (port) \ ++ { \ ++ case MAC_PORT0: \ ++ { \ ++ cfg = MAC0_CFG_REG; \ ++ break; \ ++ } \ ++ case MAC_PORT1: \ ++ { \ ++ cfg = MAC1_CFG_REG; \ ++ break; \ ++ } \ ++ case MAC_PORT2: \ ++ { \ ++ cfg = MAC2_CFG_REG; \ ++ break; \ ++ } \ ++ } \ ++} ++ ++#define SET_MAC_PORT_CFG(port, cfg) \ ++{ \ ++ switch (port) \ ++ { \ ++ case MAC_PORT0: \ ++ { \ ++ MAC0_CFG_REG = cfg; \ ++ break; \ ++ } \ ++ case MAC_PORT1: \ ++ { \ ++ MAC1_CFG_REG = cfg; \ ++ break; \ ++ } \ ++ case MAC_PORT2: \ ++ { \ ++ MAC2_CFG_REG = cfg; \ ++ break; \ ++ } \ ++ } \ ++} ++ ++#define between(x, start, end) ((x)>=(start) && (x)<=(end)) ++static inline void print_packet(unsigned char *data, int len) ++{ ++ int i,j; ++ ++ printk("packet length: %d%s:\n", len, len>128?"(only show the first 128 bytes)":""); ++#if 0 ++ if(len > 128) { ++ len = 128; ++ } ++#endif ++ for(i=0;len;) { ++ if(len >=16 ) { ++ for(j=0;j<16;j++) { ++ printk("%02x ", data[i++]); ++ } ++ printk("| "); ++ ++ i -= 16; ++ for(j=0;j<16;j++) { ++ if( between(data[i], 0x21, 0x7e) ) { ++ printk("%c", data[i++]); ++ } ++ else { ++ printk("."); ++ i++; ++ } ++ } ++ printk("\n"); ++ ++ len -= 16; ++ } ++ else { ++ /* last line */ ++ ++ for(j=0; j<len; j++) { ++ printk("%02x ", data[i++]); ++ } ++ for(;j<16;j++) { ++ printk(" "); ++ } ++ printk("| "); ++ ++ i -= len; ++ for(j=0;j<len;j++) { ++ if( between(data[i], 0x21, 0x7e) ) { ++ printk("%c", data[i++]); ++ } ++ else { ++ printk("."); ++ i++; ++ } ++ } ++ for(;j<16;j++) { ++ printk(" "); ++ } ++ printk("\n"); ++ ++ len = 0; ++ } ++ } ++ return; ++ ++} ++ ++static inline void cns3xxx_gsw_power_enable(void) ++{ ++ PLL_HM_PD_CTRL_REG &= (~(1 << 2)); // power up PLL_RGMII (for MAC) ++ CLK_GATE_REG |= (1 << 11); // enable switch clock ++} ++ ++static inline void cns3xxx_gsw_software_reset(void) ++{ ++ SOFT_RST_REG &= (~(1 << 11)); ++ SOFT_RST_REG |= (1 << 11); ++} ++ ++ ++ ++ ++// port: ++// 0 : mac port0 ++// 1 : mac port1 ++// 2 : mac port2 ++// 3 : cpu port ++static inline void enable_port(u8 port, u8 enable) ++{ ++ switch (port) ++ { ++ case 0: ++ { ++ (enable==1) ? (MAC0_CFG_REG &= (~(1 << 18)) ) : (MAC0_CFG_REG |= (1 << 18)) ; ++ ++ break; ++ } ++ case 1: ++ { ++ (enable==1) ? (MAC1_CFG_REG &= (~(1 << 18)) ) : (MAC1_CFG_REG |= (1 << 18)) ; ++ break; ++ } ++ case 2: ++ { ++ (enable==1) ? (MAC2_CFG_REG &= (~(1 << 18)) ) : (MAC2_CFG_REG |= (1 << 18)) ; ++ break; ++ } ++ case 3: ++ { ++ (enable==1) ? (CPU_CFG_REG &= (~(1 << 18)) ) : (CPU_CFG_REG |= (1 << 18)) ; ++ break; ++ } ++ } ++} ++ ++static inline int cns3xxx_vlan_table_lookup(VLANTableEntry *entry) ++{ ++ VLAN_CTRL2_REG |= entry->vid; ++ ARL_VLAN_CMD_REG |= (1 << 8); // look up vlan table command ++ ++ // wait for vlan command complete ++ while(( (ARL_VLAN_CMD_REG >> 9) & 1) == 0) ; ++ ++ if (!((ARL_VLAN_CMD_REG >> 10) & 1)) { ++ // not found any entry ++ return CAVM_NOT_FOUND; ++ } ++ ++ entry->valid = ((VLAN_CTRL0_REG >> 31) & 0x1); ++ entry->vid = ((VLAN_CTRL2_REG >> 31) & 0xfff); ++ entry->wan_side = ((VLAN_CTRL0_REG >> 30) & 0x1); ++ entry->etag_pmap = ((VLAN_CTRL0_REG >> 25) & 0x1f); ++ entry->mb_pmap = ((VLAN_CTRL0_REG >> 9) & 0x1f); ++ ++ entry->my_mac[0] = ((VLAN_CTRL1_REG >> 24) & 0xff); ++ entry->my_mac[1] = ((VLAN_CTRL1_REG >> 16) & 0xff); ++ entry->my_mac[2] = ((VLAN_CTRL1_REG >> 8) & 0xff); ++ entry->my_mac[3] = (VLAN_CTRL1_REG & 0xff); ++ ++ entry->my_mac[4] = ((VLAN_CTRL2_REG >> 24) & 0xff); ++ entry->my_mac[5] = ((VLAN_CTRL2_REG >> 16) & 0xff); ++ ++ return CAVM_FOUND; ++} ++ ++static inline int cns3xxx_vlan_table_read(VLANTableEntry *entry) ++{ ++ //printf("VLAN_CTRL0_REG: %x\n", VLAN_CTRL0_REG); ++ ARL_VLAN_CMD_REG &= (~0x3f); ++ ARL_VLAN_CMD_REG |= (entry->vlan_index); ++ ARL_VLAN_CMD_REG |= (1 << 7); // read vlan table command ++ //printf("after read ARL_VLAN_CMD_REG: %x\n", ARL_VLAN_CMD_REG); ++ ++ // wait for vlan command complete ++ while(( (ARL_VLAN_CMD_REG >> 9) & 1) == 0) ; ++ ++ //printf("ARL_VLAN_CMD_REG: %x\n", ARL_VLAN_CMD_REG); ++ //printf("VLAN_CTRL0_REG: %x\n", VLAN_CTRL0_REG); ++ ++ entry->valid = ((VLAN_CTRL0_REG >> 31) & 0x1); ++ entry->vid = ((VLAN_CTRL2_REG) & 0xfff); ++ entry->wan_side = ((VLAN_CTRL0_REG >> 30) & 0x1); ++ entry->etag_pmap = ((VLAN_CTRL0_REG >> 25) & 0x1f); ++ entry->mb_pmap = ((VLAN_CTRL0_REG >> 9) & 0x1f); ++ ++ entry->my_mac[0] = ((VLAN_CTRL1_REG >> 24) & 0xff); ++ entry->my_mac[1] = ((VLAN_CTRL1_REG >> 16) & 0xff); ++ entry->my_mac[2] = ((VLAN_CTRL1_REG >> 8) & 0xff); ++ entry->my_mac[3] = (VLAN_CTRL1_REG & 0xff); ++ ++ entry->my_mac[4] = ((VLAN_CTRL2_REG >> 24) & 0xff); ++ entry->my_mac[5] = ((VLAN_CTRL2_REG >> 16) & 0xff); ++ ++ return CAVM_OK; ++ ++} ++ ++ ++// add a entry in the vlan table ++static inline int cns3xxx_vlan_table_add(VLANTableEntry *entry) ++{ ++ VLAN_CTRL0_REG = 0; ++ VLAN_CTRL1_REG = 0; ++ VLAN_CTRL2_REG = 0; ++ ++#if 0 ++ printk("a [kernel mode] VLAN_CTRL0_REG: %x\n", VLAN_CTRL0_REG); ++ printk("a [kernel mode] VLAN_CTRL1_REG: %x\n", VLAN_CTRL1_REG); ++ printk("a [kernel mode] VLAN_CTRL2_REG: %x\n", VLAN_CTRL2_REG); ++#endif ++ ++ //printk("vlan_index: %x\n", entry->vlan_index); ++ VLAN_CTRL0_REG |= (entry->valid << 31); ++ //DEBUG_MSG(NORMAL_MSG, "1 [kernel mode] VLAN_CTRL0_REG: %x\n", VLAN_CTRL0_REG); ++ VLAN_CTRL0_REG |= (entry->wan_side << 30); ++ //DEBUG_MSG(NORMAL_MSG, "2 [kernel mode] VLAN_CTRL0_REG: %x\n", VLAN_CTRL0_REG); ++ //printk("entry->etag_pmap: %x\n", entry->etag_pmap); ++ VLAN_CTRL0_REG |= (entry->etag_pmap << 25); ++ //DEBUG_MSG(NORMAL_MSG, "3 [kernel mode] VLAN_CTRL0_REG: %x\n", VLAN_CTRL0_REG); ++ //printk("entry->mb_pmap: %x\n", entry->mb_pmap); ++ VLAN_CTRL0_REG |= (entry->mb_pmap << 9); ++ //DEBUG_MSG(NORMAL_MSG, "4 [kernel mode] VLAN_CTRL0_REG: %x\n", VLAN_CTRL0_REG); ++ //printk("bb [kernel mode] VLAN_CTRL0_REG: %x\n", VLAN_CTRL0_REG); ++ ++ //printf("vlan index: %d ## add VLAN_CTRL0_REG: %x\n", entry->vlan_index, VLAN_CTRL0_REG); ++ ++ ++ VLAN_CTRL1_REG |= (entry->my_mac[0] << 24); ++ VLAN_CTRL1_REG |= (entry->my_mac[1] << 16); ++ VLAN_CTRL1_REG |= (entry->my_mac[2] << 8); ++ VLAN_CTRL1_REG |= (entry->my_mac[3]); ++ ++ VLAN_CTRL2_REG |= (entry->my_mac[4] << 24); ++ VLAN_CTRL2_REG |= (entry->my_mac[5] << 16); ++ VLAN_CTRL2_REG |= entry->vid; ++ ++#if 0 ++ printk("b [kernel mode] VLAN_CTRL0_REG: %x\n", VLAN_CTRL0_REG); ++ printk("b [kernel mode] VLAN_CTRL1_REG: %x\n", VLAN_CTRL1_REG); ++ printk("b [kernel mode] VLAN_CTRL2_REG: %x\n", VLAN_CTRL2_REG); ++#endif ++ ++ ARL_VLAN_CMD_REG &= (~0x3f); ++ ARL_VLAN_CMD_REG |= (entry->vlan_index); ++ ARL_VLAN_CMD_REG |= (1 << 6); // write vlan table command ++ ++ ++ //printf("after write ARL_VLAN_CMD_REG: %x\n", ARL_VLAN_CMD_REG); ++ ++ // wait for vlan command complete ++ while(( (ARL_VLAN_CMD_REG >> 9) & 1) == 0) ; ++ ++ return CAVM_OK; ++} ++ ++static inline void print_arl_table_entry(ARLTableEntry *entry) ++{ ++ printk("vid: %d\n", entry->vid); ++ printk("pmap: %#x\n", entry->pmap); ++ printk("age_field: %d\n", entry->age_field); ++ printk("vlan_mac: %d\n", entry->vlan_mac); ++ printk("filter: %d\n", entry->filter); ++ printk("mac addr: %x:%x:%x:%x:%x:%x\n", entry->mac[0], entry->mac[1],entry->mac[2],entry->mac[3],entry->mac[4],entry->mac[5]); ++ ++} ++ ++ ++static inline int cns3xxx_arl_table_lookup(ARLTableEntry *entry) ++{ ++ ARL_CTRL0_REG = 0; ++ ARL_CTRL1_REG = 0; ++ ARL_CTRL2_REG = 0; ++ ++ ARL_CTRL0_REG |= (entry->vid << 16); ++ ++ ARL_CTRL1_REG |= (entry->mac[0] << 24); ++ ARL_CTRL1_REG |= (entry->mac[1] << 16); ++ ARL_CTRL1_REG |= (entry->mac[2] << 8); ++ ARL_CTRL1_REG |= entry->mac[3]; ++ ++ ARL_CTRL2_REG |= (entry->mac[4] << 24); ++ ARL_CTRL2_REG |= (entry->mac[5] << 16); ++ ++ ARL_VLAN_CMD_REG |= (1 << 18); // arl table lookup command ++ ++ // wait arl command complete ++ while(( (ARL_VLAN_CMD_REG >> 21) & 1) == 0); ++ ++ if (( (ARL_VLAN_CMD_REG >> 23) & 1)) { ++ // found ++ ++ entry->vid = ((ARL_CTRL0_REG >> 16) & 0xfff); ++ entry->pmap = ((ARL_CTRL0_REG >> 9) & 0x1f); ++ ++ entry->age_field = ((ARL_CTRL2_REG >> 4 ) & 0x7); ++ entry->vlan_mac = ((ARL_CTRL2_REG >> 1 ) & 0x1); ++ entry->filter = (ARL_CTRL2_REG & 0x1); ++ } else { ++ // not found ++ return CAVM_NOT_FOUND; ++ } ++#if 0 ++ printk("[kernel mode] ARL_VLAN_CMD_REG : %#x\n", ARL_VLAN_CMD_REG); ++ printk("[kernel mode] ARL_CTRL0_REG : %#x\n", ARL_CTRL0_REG); ++ printk("[kernel mode] ARL_CTRL1_REG : %#x\n", ARL_CTRL1_REG); ++ printk("[kernel mode] ARL_CTRL2_REG : %#x\n", ARL_CTRL2_REG); ++#endif ++ ++ return CAVM_FOUND; ++} ++ ++static inline int cns3xxx_arl_table_search_again(ARLTableEntry *entry) ++{ ++ ARL_CTRL0_REG = 0; ++ ARL_CTRL1_REG = 0; ++ ARL_CTRL2_REG = 0; ++ ++ ARL_VLAN_CMD_REG |= (1 << 17); // arl table search again command ++ ++ // wait arl command complete ++ while(( (ARL_VLAN_CMD_REG >> 21) & 1) == 0); ++ ++ if ((ARL_VLAN_CMD_REG >> 23) & 1) { ++ ++ // found ++ #if 0 ++ printk("[kernel mode] ARL_VLAN_CMD_REG : %#x\n", ARL_VLAN_CMD_REG); ++ printk("[kernel mode] ARL_CTRL0_REG : %#x\n", ARL_CTRL0_REG); ++ printk("[kernel mode] ARL_CTRL1_REG : %#x\n", ARL_CTRL1_REG); ++ printk("[kernel mode] ARL_CTRL2_REG : %#x\n", ARL_CTRL2_REG); ++ #endif ++ entry->vid = ((ARL_CTRL0_REG >> 16) & 0xfff); ++ entry->pmap = ((ARL_CTRL0_REG >> 9) & 0x1f); ++ ++ entry->age_field = ((ARL_CTRL2_REG >> 4 ) & 0x7); ++ entry->vlan_mac = ((ARL_CTRL2_REG >> 1 ) & 0x1); ++ entry->filter = (ARL_CTRL2_REG & 0x1); ++ ++ entry->mac[0] = (ARL_CTRL1_REG >> 24); ++ entry->mac[1] = (ARL_CTRL1_REG >> 16); ++ entry->mac[2] = (ARL_CTRL1_REG >> 8); ++ entry->mac[3] = ARL_CTRL1_REG; ++ ++ entry->mac[4] = (ARL_CTRL2_REG >> 24); ++ entry->mac[5] = (ARL_CTRL2_REG >> 16); ++ ++ return CAVM_FOUND; ++ } else { ++ // not found ++ return CAVM_NOT_FOUND; ++ } ++} ++ ++static inline int cns3xxx_is_arl_table_end(void) ++{ ++ ARL_CTRL0_REG = 0; ++ ARL_CTRL1_REG = 0; ++ ARL_CTRL2_REG = 0; ++ ++ if (( (ARL_VLAN_CMD_REG >> 22) & 1)) { // search to table end ++ return CAVM_OK; ++ } else { ++ return CAVM_ERR; ++ } ++} ++ ++static inline int cns3xxx_arl_table_search(ARLTableEntry *entry) ++{ ++ ARL_CTRL0_REG = 0; ++ ARL_CTRL1_REG = 0; ++ ARL_CTRL2_REG = 0; ++ ++#if 0 ++ ARL_CTRL0_REG |= (entry->vid << 16); ++ ++ ARL_CTRL1_REG |= (entry->mac[0] << 24); ++ ARL_CTRL1_REG |= (entry->mac[1] << 16); ++ ARL_CTRL1_REG |= (entry->mac[2] << 8); ++ ARL_CTRL1_REG |= entry->mac[3]; ++ ++ ARL_CTRL2_REG |= (entry->mac[4] << 24); ++ ARL_CTRL2_REG |= (entry->mac[5] << 16); ++#endif ++ ARL_VLAN_CMD_REG |= (1 << 16); // arl table search start command ++ ++ // wait arl command complete ++ while(( (ARL_VLAN_CMD_REG >> 21) & 1) == 0); ++ ++ if (((ARL_VLAN_CMD_REG >> 23) & 1)) { ++ // found ++ #if 0 ++ printk("[kernel mode] ARL_VLAN_CMD_REG : %#x\n", ARL_VLAN_CMD_REG); ++ printk("[kernel mode] ARL_CTRL0_REG : %#x\n", ARL_CTRL0_REG); ++ printk("[kernel mode] ARL_CTRL1_REG : %#x\n", ARL_CTRL1_REG); ++ printk("[kernel mode] ARL_CTRL2_REG : %#x\n", ARL_CTRL2_REG); ++ #endif ++ entry->vid = ((ARL_CTRL0_REG >> 16) & 0xfff); ++ entry->pmap = ((ARL_CTRL0_REG >> 9) & 0x1f); ++ ++ entry->age_field = ((ARL_CTRL2_REG >> 4 ) & 0x7); ++ entry->vlan_mac = ((ARL_CTRL2_REG >> 1 ) & 0x1); ++ entry->filter = (ARL_CTRL2_REG & 0x1); ++ ++ entry->mac[0] = (ARL_CTRL1_REG >> 24); ++ entry->mac[1] = (ARL_CTRL1_REG >> 16); ++ entry->mac[2] = (ARL_CTRL1_REG >> 8); ++ entry->mac[3] = ARL_CTRL1_REG; ++ ++ entry->mac[4] = (ARL_CTRL2_REG >> 24); ++ entry->mac[5] = (ARL_CTRL2_REG >> 16); ++ ++ return CAVM_FOUND; ++ } else { ++ // not found ++ return CAVM_NOT_FOUND; ++ } ++} ++ ++ ++// flush all age out entries except static entries ++static inline int cns3xxx_arl_table_flush(void) ++{ ++ ARL_VLAN_CMD_REG |= (1 << 20); // flush arl table command ++ ++ // wait arl command complete ++ while(( (ARL_VLAN_CMD_REG >> 21) & 1) == 0); ++ ++ ++ return CAVM_OK; ++} ++ ++ ++// add a entry in the arl table ++static inline int cns3xxx_arl_table_add(ARLTableEntry *entry) ++{ ++ ARL_CTRL0_REG = 0; ++ ARL_CTRL1_REG = 0; ++ ARL_CTRL2_REG = 0; ++ ++ entry->age_field = 7; // static entry ++ ARL_CTRL0_REG |= (entry->vid << 16); ++ ARL_CTRL0_REG |= (entry->pmap << 9); ++ ++ ARL_CTRL1_REG |= (entry->mac[0] << 24); ++ ARL_CTRL1_REG |= (entry->mac[1] << 16); ++ ARL_CTRL1_REG |= (entry->mac[2] << 8); ++ ARL_CTRL1_REG |= entry->mac[3]; ++ ++ ARL_CTRL2_REG |= (entry->mac[4] << 24); ++ ARL_CTRL2_REG |= (entry->mac[5] << 16); ++ ++ ARL_CTRL2_REG |= (entry->age_field << 4); ++ ARL_CTRL2_REG |= (entry->vlan_mac << 1); ++ ARL_CTRL2_REG |= (entry->filter); ++ ++ //printk("entry->age_field: %d\n", entry->age_field); ++ //printk("ARL_CTRL2_REG: %x\n", ARL_CTRL2_REG); ++ ++ ARL_VLAN_CMD_REG |= (1 << 19); // arl table write command ++ ++ // wait arl command complete ++ while(( (ARL_VLAN_CMD_REG >> 21) & 1) == 0); ++ ++ return CAVM_OK; ++} ++ ++// invalid a entry in the arl table ++static inline int cns3xxx_arl_table_invalid(ARLTableEntry *entry) ++{ ++ entry->age_field = 0; // invalid ++ return cns3xxx_arl_table_add(entry); ++} ++ ++// port: ++// 0 : mac port0 ++// 1 : mac port1 ++// 2 : mac port2 ++// 3 : cpu port ++static inline void cns3xxx_set_pvid(u8 port, u16 pvid) ++{ ++ switch (port) ++ { ++ case 0: ++ { ++ MAC1_MAC0_PVID_REG &= (~0x0fff); ++ MAC1_MAC0_PVID_REG |= pvid; ++ break; ++ } ++ case 1: ++ { ++ MAC1_MAC0_PVID_REG &= (~(0x0fff << 16)); ++ MAC1_MAC0_PVID_REG |= (pvid << 16); ++ break; ++ } ++ case 2: ++ { ++ MAC2_CPU_PVID_REG &= (~(0x0fff << 16)); ++ MAC2_CPU_PVID_REG |= (pvid << 16); ++ break; ++ } ++ case 3: // cpu port ++ { ++ MAC2_CPU_PVID_REG &= (~0x0fff); ++ MAC2_CPU_PVID_REG |= pvid; ++ break; ++ } ++ } ++ ++ ++} ++ ++static inline u16 cns3xxx_get_pvid(u8 port) ++{ ++ // 0, 1, 2, cpu port ++ u16 port_offset[]={0x9c, 0x9c, 0xa0, 0xa0}; ++ // 0, 1, 2, cpu port ++ u16 port_shift[]={0, 16, 16, 0}; ++ ++ return ((SWITCH_REG_VALUE(port_offset[port]) >> port_shift[port]) & 0xfff); ++} ++ ++// which : 0 or 1 ++// enable: 0 or 1 ++static inline int enable_rx_dma(u8 which, u8 enable) ++{ ++ if (which == 0 ) { ++ FS_DMA_CTRL0_REG = enable; ++ } else if (which == 1 ) { ++ FS_DMA_CTRL1_REG = enable; ++ } else { ++ return CAVM_ERR; ++ } ++ return CAVM_OK; ++} ++ ++ ++// which : 0 or 1 ++// enable: 0 or 1 ++static inline int enable_tx_dma(u8 which, u8 enable) ++{ ++ if (which == 0 ) { ++ TS_DMA_CTRL0_REG = enable; ++ } else if (which == 1 ) { ++ TS_DMA_CTRL1_REG = enable; ++ } else { ++ return CAVM_ERR; ++ } ++ return CAVM_OK; ++} ++ ++#define DUMP_TX_DESC_PROC(tx_desc, page, num) \ ++{ \ ++ num += sprintf(page + num,"sdp: %x\n", tx_desc->sdp); \ ++ num += sprintf(page + num,"sdl: %d\n", tx_desc->sdl); \ ++ num += sprintf(page + num,"tco: %d\n", tx_desc->tco); \ ++ num += sprintf(page + num,"uco: %d\n", tx_desc->uco); \ ++ num += sprintf(page + num,"ico: %d\n", tx_desc->ico); \ ++ num += sprintf(page + num,"pri: %d\n", tx_desc->pri); \ ++ num += sprintf(page + num,"fp: %d\n", tx_desc->fp); \ ++ num += sprintf(page + num,"fr: %d\n", tx_desc->fr); \ ++ num += sprintf(page + num,"interrupt: %d\n", tx_desc->interrupt); \ ++ num += sprintf(page + num,"lsd: %d\n", tx_desc->lsd); \ ++ num += sprintf(page + num,"fsd: %d\n", tx_desc->fsd); \ ++ num += sprintf(page + num,"eor: %d\n", tx_desc->eor); \ ++ num += sprintf(page + num,"cown: %d\n", tx_desc->cown); \ ++ \ ++ num += sprintf(page + num,"ctv: %d\n", tx_desc->ctv); \ ++ num += sprintf(page + num,"stv: %d\n", tx_desc->stv); \ ++ num += sprintf(page + num,"sid: %d\n", tx_desc->sid); \ ++ num += sprintf(page + num,"inss: %d\n", tx_desc->inss); \ ++ num += sprintf(page + num,"dels: %d\n", tx_desc->dels); \ ++ num += sprintf(page + num,"pmap: %d\n", tx_desc->pmap); \ ++ num += sprintf(page + num,"mark: %d\n", tx_desc->mark); \ ++ num += sprintf(page + num,"ewan: %d\n", tx_desc->ewan); \ ++ num += sprintf(page + num,"fewan: %d\n", tx_desc->fewan); \ ++ \ ++ num += sprintf(page + num,"c_vid: %d\n", tx_desc->c_vid); \ ++ num += sprintf(page + num,"c_cfs: %d\n", tx_desc->c_cfs); \ ++ num += sprintf(page + num,"c_pri: %d\n", tx_desc->c_pri); \ ++ num += sprintf(page + num,"s_vid: %d\n", tx_desc->s_vid); \ ++ num += sprintf(page + num,"s_dei: %d\n", tx_desc->s_dei); \ ++ num += sprintf(page + num,"s_pri: %d\n", tx_desc->s_pri); \ ++} ++ ++static inline void dump_tx_desc(TXDesc volatile *tx_desc) ++{ ++ printk("sdp: %x\n", tx_desc->sdp); ++ printk("sdl: %d\n", tx_desc->sdl); ++ printk("tco: %d\n", tx_desc->tco); ++ printk("uco: %d\n", tx_desc->uco); ++ printk("ico: %d\n", tx_desc->ico); ++ printk("pri: %d\n", tx_desc->pri); ++ printk("fp: %d\n", tx_desc->fp); ++ printk("fr: %d\n", tx_desc->fr); ++ printk("interrupt: %d\n", tx_desc->interrupt); ++ printk("lsd: %d\n", tx_desc->lsd); ++ printk("fsd: %d\n", tx_desc->fsd); ++ printk("eor: %d\n", tx_desc->eor); ++ printk("cown: %d\n", tx_desc->cown); ++ ++ printk("ctv: %d\n", tx_desc->ctv); ++ printk("stv: %d\n", tx_desc->stv); ++ printk("sid: %d\n", tx_desc->sid); ++ printk("inss: %d\n", tx_desc->inss); ++ printk("dels: %d\n", tx_desc->dels); ++ printk("pmap: %d\n", tx_desc->pmap); ++ printk("mark: %d\n", tx_desc->mark); ++ printk("ewan: %d\n", tx_desc->ewan); ++ printk("fewan: %d\n", tx_desc->fewan); ++ ++ printk("c_vid: %d\n", tx_desc->c_vid); ++ printk("c_cfs: %d\n", tx_desc->c_cfs); ++ printk("c_pri: %d\n", tx_desc->c_pri); ++ printk("s_vid: %d\n", tx_desc->s_vid); ++ printk("s_dei: %d\n", tx_desc->s_dei); ++ printk("s_pri: %d\n", tx_desc->s_pri); ++} ++ ++static inline void dump_rx_desc(RXDesc volatile *rx_desc) ++{ ++ ++ printk("rx_desc: %p\n", rx_desc); ++ //printk("rx_desc: %p ## cown: %d\n", rx_desc, rx_desc->cown); ++ //printk("rx_desc phy addr : %x\n", (u32)page_to_dma(NULL, rx_desc) ); ++#if 0 ++ int i=0; ++ for (i=0; i < 8 ; ++4) { ++ u32 rx_desc_data = *((u32 *)(rx_desc+i)); ++ printk("%d: %#x\n", i, rx_desc_data); ++ } ++#endif ++ ++ printk("sdp: %x\n", rx_desc->sdp); ++ ++ printk("sdl: %d\n", rx_desc->sdl); ++#if 1 ++ printk("l4f: %d\n", rx_desc->l4f); ++ printk("ipf: %d\n", rx_desc->ipf); ++ printk("prot: %d\n", rx_desc->prot); ++ printk("hr: %d\n", rx_desc->hr); ++ printk("lsd: %d\n", rx_desc->lsd); ++ printk("fsd: %d\n", rx_desc->fsd); ++ printk("eor: %d\n", rx_desc->eor); ++#endif ++ printk("cown: %d\n", rx_desc->cown); ++ ++#if 1 ++ printk("ctv: %d\n", rx_desc->ctv); ++ printk("stv: %d\n", rx_desc->stv); ++ printk("unv: %d\n", rx_desc->unv); ++ printk("iwan: %d\n", rx_desc->iwan); ++ printk("exdv: %d\n", rx_desc->exdv); ++ printk("sp: %d\n", rx_desc->sp); ++ printk("crc_err: %d\n", rx_desc->crc_err); ++ printk("un_eth: %d\n", rx_desc->un_eth); ++ printk("tc: %d\n", rx_desc->tc); ++ printk("ip_offset: %d\n", rx_desc->ip_offset); ++ ++ printk("c_vid: %d\n", rx_desc->c_vid); ++ printk("c_cfs: %d\n", rx_desc->c_cfs); ++ printk("c_pri: %d\n", rx_desc->c_pri); ++ printk("s_vid: %d\n", rx_desc->s_vid); ++ printk("s_dei: %d\n", rx_desc->s_dei); ++ printk("s_pri: %d\n", rx_desc->s_pri); ++#endif ++} ++ ++static inline void dump_all_rx_ring(const RXRing *rx_ring, u8 r_index) ++{ ++ int i=0; ++ ++ RXBuffer volatile *rx_buf = get_rx_ring_head(rx_ring); ++ ++ printk("all rx ring: %d\n", r_index); ++ for (i=0 ; i < get_rx_ring_size(rx_ring) ; ++i) { ++ printk("%d ## rx_buf: %p ## rx_buf->rx_desc: %p\n", i, rx_buf, rx_buf->rx_desc); ++ dump_rx_desc(rx_buf->rx_desc); ++ ++rx_buf; ++ } ++} ++ ++static inline void rx_dma_suspend(u8 enable) ++{ ++#if 1 ++ DMA_AUTO_POLL_CFG_REG &= (~0x00000001); ++ if (enable == 1) ++ DMA_AUTO_POLL_CFG_REG |= 1; ++#endif ++} ++ ++ ++// clear: 0 normal ++// clear: 1 clear ++static inline void clear_fs_dma_state(u8 clear) ++{ ++ DMA_RING_CTRL_REG &= (~(1 << 31)); ++ if (clear==1) { ++ DMA_RING_CTRL_REG |= (1 << 31); ++ } ++} ++ ++// enable: 1 -> IVL ++// enable: 0 -> SVL ++static inline void cns3xxx_ivl(u8 enable) ++{ ++ // SVL ++ MAC_GLOB_CFG_REG &= (~(0x1 << 7)); ++ if (enable == 1) ++ MAC_GLOB_CFG_REG |= (0x1 << 7); ++} ++ ++static inline void cns3xxx_nic_mode(u8 enable) ++{ ++ VLAN_CFG &= (~(1<<15)); ++ if (enable == 1) ++ VLAN_CFG |= (1<<15); ++} ++ ++ ++void gic_mask_irq(unsigned int irq); ++void gic_unmask_irq(unsigned int irq); ++extern void __iomem *gic_cpu_base_addr; ++ ++ ++static inline void cns3xxx_disable_irq(u32 irq) ++{ ++#ifdef CONFIG_SMP ++ disable_irq_nosync(irq); ++#else ++ disable_irq(irq); ++#endif ++ //gic_mask_irq(irq); ++} ++ ++static inline void cns3xxx_enable_irq(u32 irq) ++{ ++ enable_irq(irq); ++ //gic_unmask_irq(irq); ++} ++ ++static inline int cns3xxx_get_tx_hw_index(u8 ring_index) ++{ ++ if (ring_index == 0) { ++ return (TS_DESC_PTR0_REG - TS_DESC_BASE_ADDR0_REG) / sizeof (TXDesc); ++ } else if (ring_index == 1) { ++ return (TS_DESC_PTR1_REG - TS_DESC_BASE_ADDR1_REG) / sizeof (TXDesc); ++ } else { ++ return CAVM_ERR; ++ } ++} ++ ++static inline TXBuffer* get_tx_buffer_by_index(TXRing *tx_ring, int i) ++{ ++ int index = i; ++ ++ index = ((index + get_tx_ring_size(tx_ring) )% get_tx_ring_size(tx_ring)); ++ ++ return tx_ring->head + index; ++} ++ ++static inline int cns3xxx_is_untag_packet(const RXDesc *rx_desc) ++{ ++ return rx_desc->crc_err; ++} ++ ++ ++#ifdef CONFIG_SWITCH_BIG_ENDIAN ++static inline void swap_rx_desc(RXDesc *org_desc, RXDesc *new_desc) ++{ ++ int i=0; ++ void *org_p = org_desc; ++ void *new_p = new_desc; ++ ++ for (i=0; i < 16 ; i+=4) { ++ u32 rx_desc_data = 0; ++ u32 swab_rx_desc_data = 0; ++ ++ rx_desc_data = *((volatile u32 *)(org_p+i)); ++ swab_rx_desc_data = ___swab32(rx_desc_data); ++ ++ *((volatile u32 *)(new_p+i)) = swab_rx_desc_data; ++ } ++} ++ ++static inline void swap_tx_desc(TXDesc *org_desc, TXDesc *new_desc) ++{ ++ int i=0; ++ void *org_p = org_desc; ++ void *new_p = new_desc; ++ ++ for (i=0; i < 16 ; i+=4) { ++ u32 desc_data = *((volatile u32 *)(org_p+i)); ++ u32 swab_desc_data = ___swab32(desc_data); ++ ++ *((volatile u32 *)(new_p+i)) = swab_desc_data; ++ } ++} ++ ++#endif ++ ++ ++static inline int cns3xxx_min_mtu(void) ++{ ++ return 64; ++} ++ ++static inline int cns3xxx_max_mtu(void) ++{ ++ int max_len[]={1518, 1522, 1536, 9600}; ++ ++ return max_len[((PHY_AUTO_ADDR_REG >> 30) & 0x3)]; ++} ++ ++#endif // CNS3XXX_TOOL_H +--- /dev/null ++++ b/drivers/net/cns3xxx/fpga.h +@@ -0,0 +1,306 @@ ++/******************************************************************************* ++ * ++ * Copyright (c) 2009 Cavium Networks ++ * ++ * 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. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ ********************************************************************************/ ++ ++// This macro or function divide two part, ++// one is initial state, another is in netdev open (ifconfig up) function. ++ ++#ifndef FPGA_H ++#define FPGA_H ++ ++#include <linux/types.h> ++ ++#include "cns3xxx_config.h" ++#include "cns3xxx_phy.h" ++ ++//#define FGPA ++ ++ ++#ifdef CONFIG_FPGA ++// init phy or switch chip ++#define INIT_PORT0_PHY cns3xxx_config_VSC8601(0,0); ++#define INIT_PORT1_PHY cns3xxx_config_VSC8601(1,1); ++#define INIT_PORT2_PHY icp_101a_init(2, 2); ++//#define INIT_PORT1_PHY ++ ++// configure mac0/mac1 register ++#define INIT_PORT0_MAC ++#define INIT_PORT1_MAC ++#define INIT_PORT2_MAC ++//#define INIT_PORT1_MAC ++ ++#define PORT0_LINK_DOWN vsc8601_power_down(0, 1); ++#define PORT0_LINK_UP vsc8601_power_down(0, 0); ++ ++#define PORT1_LINK_DOWN vsc8601_power_down(1, 1); ++#define PORT1_LINK_UP vsc8601_power_down(1, 0); ++ ++#define PORT2_LINK_DOWN cns3xxx_std_phy_power_down(2, 1); ++#define PORT2_LINK_UP cns3xxx_std_phy_power_down(2, 0); ++ ++ ++ ++#define MODEL "VEGA FPGA" ++ ++static int rc_port0 = 0; // rc means reference counting, determine port open/close. ++ ++ ++// enable port ++// link down ++static inline void open_port0(void) ++{ ++ if (rc_port0 == 0) { ++ enable_port(0, 1); ++ PRINT_INFO("open mac port 0\n"); ++ // link up ++ PORT0_LINK_UP ++ } else { ++ PRINT_INFO("port 0 already open\n");\ ++ } ++ ++rc_port0; ++} ++ ++static inline void close_port0(void) ++{ ++ --rc_port0; ++ if (rc_port0 == 0) { ++ // link down ++ PORT0_LINK_DOWN ++ enable_port(0, 0); ++ PRINT_INFO("close mac port 0\n");\ ++ } ++} ++ ++static inline void open_port1(void) ++{ ++ ++ enable_port(1, 1); ++ PRINT_INFO("open mac port 1\n"); ++ // link up ++ PORT1_LINK_UP ++} ++ ++static inline void close_port1(void) ++{ ++ enable_port(1, 0); ++ PRINT_INFO("close mac port 1\n"); ++ // link down ++ PORT1_LINK_DOWN ++} ++ ++static inline void open_port2(void) ++{ ++ ++ enable_port(2, 1); ++ PRINT_INFO("open mac port 2\n"); ++ // link up ++ PORT2_LINK_UP ++} ++ ++static inline void close_port2(void) ++{ ++ enable_port(2, 0); ++ PRINT_INFO("close mac port 2\n"); ++ // link down ++ PORT2_LINK_DOWN ++} ++ ++static u8 my_vlan0_mac[] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x00}; ++static u8 my_vlan1_mac[] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x11}; ++static u8 my_vlan2_mac[] = {0x00, 0x11, 0xbb, 0xcc, 0xdd, 0x70}; ++static u8 my_vlan3_mac[] = {0x00, 0x11, 0xbb, 0xcc, 0xdd, 0x80}; ++ ++ ++ ++ ++// CNS3XXX_NIC_MODE_8021Q, CNS3XXX_NON_NIC_MODE_8021Q, CNS3XXX_VLAN_BASE_MODE and ++// CNS3XXX_PORT_BASE_MODE, only one macro can be defined ++ ++#ifdef CNS3XXX_VLAN_8021Q ++ #ifndef CNS3XXX_NIC_MODE_8021Q ++ #define CNS3XXX_NON_NIC_MODE_8021Q ++ #endif ++#else ++ //#define CNS3XXX_VLAN_BASE_MODE ++ #define CNS3XXX_PORT_BASE_MODE ++#endif ++ ++#ifdef CNS3XXX_PORT_BASE_MODE ++ ++#define PORT0_PVID 0x1 ++#define PORT1_PVID 0x2 ++#define PORT2_PVID 3 ++#define CPU_PVID 5 ++ ++#define CONFIG_CNS3XXX_PORT_BASE ++ ++static VLANTableEntry cpu_vlan_table_entry = {0, 1, CPU_PVID, 0, 0, MAC_PORT0_PMAP | MAC_PORT1_PMAP | MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan3_mac}; ++ ++static VLANTableEntry vlan_table_entry[] = ++{ ++ // vlan_index; valid; vid; wan_side; etag_pmap; mb_pmap; *my_mac; ++ //{0, 1, 1, 0, 0, MAC_PORT0_PMAP | MAC_PORT1_PMAP | MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan0_mac}, ++ {1, 1, PORT0_PVID, 0, 0, MAC_PORT0_PMAP | CPU_PORT_PMAP, my_vlan0_mac}, ++ {2, 1, PORT1_PVID, 0, 0, MAC_PORT1_PMAP | CPU_PORT_PMAP, my_vlan1_mac}, ++ {3, 1, PORT2_PVID, 1, 0, MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan2_mac}, ++ //{2, 1, 4, 0, 0, MAC_PORT0_PMAP | MAC_PORT1_PMAP | MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan3_mac}, // for cpu ++}; ++ ++static ARLTableEntry arl_table_entry[] = ++{ ++ // vid; pmap; *mac; age_field; vlan_mac ; filter ++ {PORT0_PVID, CPU_PORT_PMAP, my_vlan0_mac, 7, 1, 0}, ++ //{CPU_PVID, CPU_PORT_PMAP, my_vlan0_mac, 7, 1, 0}, ++ {PORT1_PVID, CPU_PORT_PMAP, my_vlan1_mac, 7, 1, 0}, ++ {PORT2_PVID, CPU_PORT_PMAP, my_vlan2_mac, 7, 1, 0}, ++ //{PORT0_PVID, MAC_PORT0_PMAP, my_vlan8_mac, 7, 0, 0}, ++ //{PORT0_PVID, MAC_PORT0_PMAP, my_vlan9_mac, 7, 0, 0}, ++ //{CPU_PVID, 0x4, my_vlan2_mac, 7, 1, 0}, ++ //{CPU_PVID, MAC_PORT2_PMAP, my_vlan2_mac, 7, 1, 0}, ++}; ++ ++static NetDevicePriv net_device_prive[]= { ++ /* pmap, is_wan, s-tag, vlan_tag or pvid, rx_func_ptr, tx_func_ptr, open_ptr, close_ptr, which port, mac, VLANTableEntry, ARLTableEntry, NICSetting, netdev s-tag, name */ ++ {MAC_PORT0_PMAP, 0, 1, PORT0_NETDEV_INDEX, rx_port_base, tx_port_base, open_port0, close_port0, MAC_PORT0, my_vlan0_mac, &vlan_table_entry[0], &arl_table_entry[0], 0, 0}, // eth0 ++ {MAC_PORT1_PMAP, 0, 2, PORT1_NETDEV_INDEX, rx_port_base, tx_port_base, open_port1, close_port1, MAC_PORT1, my_vlan1_mac, &vlan_table_entry[1], &arl_table_entry[1], 0, 0}, // eth1 ++ {MAC_PORT2_PMAP, 1, 3, PORT2_NETDEV_INDEX, rx_port_base, tx_port_base, open_port2, close_port2, MAC_PORT2, my_vlan2_mac, &vlan_table_entry[2], &arl_table_entry[2], 0, 0} // eth2 ++ }; ++ ++#endif ++ ++#ifdef CNS3XXX_NON_NIC_MODE_8021Q ++//#error "8021Q" ++#define PORT0_PVID 50 ++#define PORT1_PVID 60 ++#define PORT2_PVID 70 ++#define CPU_PVID 80 ++ ++#define CONFIG_CNS3XXX_PORT_BASE ++//#define CONFIG_CNS3XXX_VLAN_BASE ++//#define CONFIG_HAVE_VLAN_TAG ++ ++static VLANTableEntry cpu_vlan_table_entry = {0, 1, CPU_PVID, 0, 0, MAC_PORT0_PMAP | MAC_PORT1_PMAP | MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan3_mac}; // for cpu ++ ++static VLANTableEntry vlan_table_entry[] = ++{ ++ // vlan_index; valid; vid; wan_side; etag_pmap; mb_pmap; *my_mac;C_PORT2_PMAP ++ {1, 1, PORT0_PVID, 0, CPU_PORT_PMAP, MAC_PORT0_PMAP | CPU_PORT_PMAP, my_vlan0_mac}, ++ {2, 1, PORT1_PVID, 0, CPU_PORT_PMAP, MAC_PORT1_PMAP | CPU_PORT_PMAP, my_vlan1_mac}, ++ {3, 1, PORT2_PVID, 0, CPU_PORT_PMAP, MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan2_mac}, ++}; ++ ++static ARLTableEntry arl_table_entry[] = ++{ ++ // vid; pmap; *mac; age_field; vlan_mac ; filter ++ {PORT0_PVID, CPU_PORT_PMAP, my_vlan0_mac, 7, 1, 0}, ++ {PORT1_PVID, CPU_PORT_PMAP, my_vlan1_mac, 7, 1, 0}, ++ {PORT2_PVID, CPU_PORT_PMAP, my_vlan2_mac, 7, 1, 0}, ++}; ++ ++ ++// if used 8021Q, use PORT0_NETDEV_INDEX, don't use VID ++static NetDevicePriv net_device_prive[]= { ++ {MAC_PORT0_PMAP, 0, 1, PORT0_NETDEV_INDEX, rx_port_base, tx_port_base, open_port0, close_port0, MAC_PORT0, my_vlan0_mac, &vlan_table_entry[0], &arl_table_entry[0], 0, 0}, // eth0 ++ {MAC_PORT1_PMAP, 0, 0, PORT1_NETDEV_INDEX, rx_port_base, tx_port_base, open_port1, close_port1, MAC_PORT1, my_vlan1_mac, &vlan_table_entry[1], &arl_table_entry[1], 0, 0}, // eth1 ++ {MAC_PORT2_PMAP, 1, 3, PORT2_NETDEV_INDEX, rx_port_base, tx_port_base, open_port2, close_port2, MAC_PORT2, my_vlan2_mac, &vlan_table_entry[2], &arl_table_entry[2], 0, 0} // eth2 ++ }; ++#endif ++ ++ ++ ++#ifdef CNS3XXX_NIC_MODE_8021Q ++//#error "8021Q" ++#define PORT0_PVID 1 ++#define PORT1_PVID 2 ++#define PORT2_PVID 9 ++#define CPU_PVID 5 ++ ++#define CONFIG_CNS3XXX_PORT_BASE ++//#define CONFIG_CNS3XXX_VLAN_BASE ++//#define CONFIG_HAVE_VLAN_TAG ++ ++static VLANTableEntry cpu_vlan_table_entry = {0, 1, CPU_PVID, 0, 0, MAC_PORT0_PMAP | MAC_PORT1_PMAP | MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan3_mac}; // for cpu ++ ++static VLANTableEntry vlan_table_entry[] = ++{ ++ // vlan_index; valid; vid; wan_side; etag_pmap; mb_pmap; *my_mac;C_PORT2_PMAP ++ {1, 1, PORT0_PVID, 1, MAC_PORT0_PMAP|CPU_PORT_PMAP, MAC_PORT0_PMAP | CPU_PORT_PMAP, my_vlan0_mac}, ++ {2, 1, PORT1_PVID, 0, MAC_PORT1_PMAP|CPU_PORT_PMAP, MAC_PORT1_PMAP | CPU_PORT_PMAP, my_vlan1_mac}, ++ {3, 1, PORT2_PVID, 1, MAC_PORT2_PMAP|CPU_PORT_PMAP, MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan2_mac}, ++}; ++ ++static ARLTableEntry arl_table_entry[] = ++{ ++ // vid; pmap; *mac; age_field; vlan_mac ; filter ++ {PORT0_PVID, CPU_PORT_PMAP, my_vlan0_mac, 7, 1, 0}, ++ {PORT1_PVID, CPU_PORT_PMAP, my_vlan1_mac, 7, 1, 0}, ++ {PORT2_PVID, CPU_PORT_PMAP, my_vlan2_mac, 7, 1, 0}, ++}; ++ ++ ++// if used 8021Q, use PORT0_NETDEV_INDEX, don't use VID ++static NetDevicePriv net_device_prive[]= { ++ {MAC_PORT0_PMAP, 0, 1, PORT0_NETDEV_INDEX, rx_port_base, tx_port_base, open_port0, close_port0, MAC_PORT0, my_vlan0_mac, &vlan_table_entry[0], &arl_table_entry[0], 0, 0}, // eth0 ++ {MAC_PORT1_PMAP, 0, 0, PORT1_NETDEV_INDEX, rx_port_base, tx_port_base, open_port1, close_port1, MAC_PORT1, my_vlan1_mac, &vlan_table_entry[1], &arl_table_entry[1], 0, 0}, // eth1 ++ {MAC_PORT2_PMAP, 1, 3, PORT2_NETDEV_INDEX, rx_port_base, tx_port_base, open_port2, close_port2, MAC_PORT2, my_vlan2_mac, &vlan_table_entry[2], &arl_table_entry[2], 0, 0} // eth2 ++ }; ++#endif ++ ++#ifdef CNS3XXX_VLAN_BASE_MODE ++//#error "vlan_base" ++// vlan configuration ++ ++#define PORT0_PVID 1 ++#define PORT1_PVID 2 ++#define PORT2_PVID 3 ++#define CPU_PVID 5 ++#define CONFIG_CNS3XXX_VLAN_BASE ++#define CONFIG_HAVE_VLAN_TAG ++ ++static VLANTableEntry cpu_vlan_table_entry = {0, 1, CPU_PVID, 0, MAC_PORT0_PMAP | MAC_PORT1_PMAP | MAC_PORT2_PMAP | CPU_PORT_PMAP, MAC_PORT0_PMAP | MAC_PORT1_PMAP | MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan3_mac}; // for cpu ++ ++static VLANTableEntry vlan_table_entry[] = ++{ ++ // vlan_index; valid; vid; wan_side; etag_pmap; mb_pmap; *my_mac; ++ {1, 1, PORT0_PVID, 0, MAC_PORT0_PMAP | CPU_PORT_PMAP, MAC_PORT0_PMAP | CPU_PORT_PMAP, my_vlan0_mac}, ++ {2, 1, PORT1_PVID, 0, MAC_PORT1_PMAP | CPU_PORT_PMAP, MAC_PORT1_PMAP | CPU_PORT_PMAP, my_vlan1_mac}, ++ {3, 1, PORT2_PVID, 1, MAC_PORT2_PMAP | CPU_PORT_PMAP, MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan2_mac}, ++}; ++ ++static ARLTableEntry arl_table_entry[] = ++{ ++ // vid; pmap; *mac; age_field; vlan_mac ; filter ++ {PORT0_PVID, CPU_PORT_PMAP, my_vlan0_mac, 7, 1, 0}, ++ {PORT1_PVID, CPU_PORT_PMAP, my_vlan1_mac, 7, 1, 0}, ++ {PORT2_PVID, CPU_PORT_PMAP, my_vlan2_mac, 7, 1, 0}, ++}; ++ ++static NetDevicePriv net_device_prive[]= { ++ /* pmap, is_wan, gid, vlan_tag or pvid, rx_func_ptr, tx_func_ptr, open_ptr, close_ptr, which port, mac, VLANTableEntry, ARLTableEntry, NICSetting, netdev name */ ++ {MAC_PORT0_PMAP, 0, 1, PORT0_PVID, rx_port_base, tx_vlan_base, open_port0, close_port0, MAC_PORT0, my_vlan0_mac, &vlan_table_entry[0], &arl_table_entry[0], 0, 0}, // eth0 ++ {MAC_PORT1_PMAP, 0, 0, PORT1_PVID, rx_port_base, tx_vlan_base, open_port1, close_port1, MAC_PORT1, my_vlan1_mac, &vlan_table_entry[1], &arl_table_entry[1], 0, 0}, // eth1 ++ {MAC_PORT2_PMAP, 1, 3, PORT2_PVID, rx_port_base, tx_vlan_base, open_port2, close_port2, MAC_PORT2, my_vlan2_mac, &vlan_table_entry[2], &arl_table_entry[2], 0, 0} // eth2 ++ }; ++#endif ++ ++#endif // CONFIG_FPGA ++#endif // FPGA_H +--- /dev/null ++++ b/drivers/net/cns3xxx/Kconfig +@@ -0,0 +1,58 @@ ++menu "CNS3XXX Gigabit Switch Support" ++ depends on ARCH_CNS3XXX ++ ++config CNS3XXX_GSW ++ tristate "CNS3XXX Gigabit Switch Driver Support" ++ help ++ CNS3XXX Gigabit Switch. ++ ++config CNS3XXX_SPPE ++ bool "CNS3XXX Smart PPE(Packet Processing Engine) Support" ++ depends on CNS3XXX_GSW ++ help ++ PPE(Packet Processing Engine) is a hardware accelerator hook on a port of ++ CNS3XXX Gigabit Switch. ++ ++ This option is used for Smart PPE hook. ++ ++ Say Y if you want to enable Smart PPE function. ++ ++config CNS3XXX_HCIE_TEST ++ bool "CNS3XXX HCIE(Hardware Content Inspection Engine) Support" ++# depends on CNS3XXX_GSW ++ help ++ HCIE is patent-protected layer-7 packet processing engine. ++ ++ This option is used for fundamental HCIE functional test . ++ Say Y if you want to do HCIE functional test. ++ ++ ++#config CNS3XXX_SHNAT_PCI_FASTPATH ++# bool "FastPath(From PCI to WAN) Support" ++# depends on CNS3XXX_SHNAT ++# help ++# Add FastPath Support for Smart HNAT. ++ ++comment "NOTE: 'Validation Board' depends on" ++comment "GPIO_CNS3XXX and SPI_CNS3XXX" ++choice ++ prompt "CNS3XXX Board" ++ depends on CNS3XXX_GSW ++ default FPGA ++ ++config FPGA ++ bool "Fpga" ++ ++config VB ++ bool "Validation Board" ++ help ++ MAC0 and MAC1 connect to BCM53115M. It need enable CNS3XXX SPI and CNS3XXX GPIO option. ++ MAC2 use ICPLUS IP1001 phy. ++ ++#config LEO ++# bool "Leo" ++ ++endchoice ++ ++endmenu ++ +--- /dev/null ++++ b/drivers/net/cns3xxx/Makefile +@@ -0,0 +1,41 @@ ++################################################################################ ++# ++# ++# Copyright (c) 2008 Cavium Networks ++# ++# 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. ++# ++# The full GNU General Public License is included in this distribution in the ++# file called LICENSE. ++# ++# Contact Information: ++# Star semiconduction Linux Support <support@starsemi.com> ++# ++################################################################################ ++ ++# ++# Makefile for the Star GSW ethernet driver ++# ++ ++#obj-y := ++#obj-m := ++ ++obj-$(CONFIG_CNS3XXX_GSW) += cns3xxx.o ++cns3xxx-objs := cns3xxx_phy.o cns3xxx_main.o cns3xxx_ethtool.o ++obj-$(CONFIG_CNS3XXX_SPPE) += cns3xxx_sppe_hook.o ++#endif ++#vega_main.o ++ ++#include $(TOPDIR)/Rules.make +--- /dev/null ++++ b/drivers/net/cns3xxx/vb.h +@@ -0,0 +1,328 @@ ++/******************************************************************************* ++ * ++ * Copyright (c) 2009 Cavium Networks ++ * ++ * 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. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ ********************************************************************************/ ++ ++// This macro or function divide two part, ++// one is initial state, another is in netdev open (ifconfig up) function. ++ ++#ifndef VB_H ++#define VB_H ++ ++#include <linux/types.h> ++ ++#include "cns3xxx_config.h" ++#include "cns3xxx_phy.h" ++ ++#ifdef CONFIG_VB ++// init phy or switch chip ++#define INIT_PORT0_PHY cns3xxx_config_VSC8601(0, 0); ++#define INIT_PORT1_PHY cns3xxx_config_VSC8601(1, 1); ++#define INIT_PORT2_PHY ++//#define INIT_PORT1_PHY ++ ++// configure mac0/mac1 register ++#define INIT_PORT0_MAC ++#define INIT_PORT1_MAC ++#define INIT_PORT2_MAC ++//#define INIT_PORT1_MAC ++ ++#define PORT0_LINK_DOWN cns3xxx_std_phy_power_down(0, 1); ++#define PORT0_LINK_UP cns3xxx_std_phy_power_down(0, 0); ++ ++#define PORT1_LINK_DOWN cns3xxx_std_phy_power_down(1, 1); ++#define PORT1_LINK_UP cns3xxx_std_phy_power_down(1, 0); ++ ++#define PORT2_LINK_DOWN ++#define PORT2_LINK_UP ++ ++#define MODEL "CNS3XXX validation board" ++ ++static int rc_port0 = 0; // rc means reference counting, determine port open/close. ++ ++#define PRINT_INFO printk ++ ++// enable port ++// link down ++static inline void open_port0(void) ++{ ++ if (rc_port0 == 0) { ++ enable_port(0, 1); ++ // link up ++ PORT0_LINK_UP ++ } ++ ++rc_port0; ++} ++ ++static inline void close_port0(void) ++{ ++ --rc_port0; ++ if (rc_port0 == 0) { ++ // link down ++ PORT0_LINK_DOWN ++ enable_port(0, 0); ++ } ++} ++ ++static inline void open_port1(void) ++{ ++ ++ enable_port(1, 1); ++ // link up ++ PORT1_LINK_UP ++} ++ ++static inline void close_port1(void) ++{ ++ enable_port(1, 0); ++ // link down ++ PORT1_LINK_DOWN ++} ++ ++static inline void open_port2(void) ++{ ++ ++ enable_port(2, 1); ++ // link up ++ PORT2_LINK_UP ++} ++ ++static inline void close_port2(void) ++{ ++ enable_port(2, 0); ++ // link down ++ PORT2_LINK_DOWN ++} ++ ++#if defined (CONFIG_CNS3XXX_SPPE) ++/* only for PPE PCI-to-WAN fast path */ ++static int fp_ref_cnt = 0; ++static inline void open_fp(void) ++{ ++ if (!fp_ref_cnt) { ++ fp_ref_cnt++; ++ } ++} ++ ++static inline void close_fp(void) ++{ ++ if (fp_ref_cnt) { ++ fp_ref_cnt--; ++ } ++} ++#endif ++ ++static u8 my_vlan0_mac[] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x00}; ++static u8 my_vlan1_mac[] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x11}; ++static u8 my_vlan2_mac[] = {0x00, 0x11, 0xbb, 0xcc, 0xdd, 0x70}; ++static u8 my_vlan3_mac[] = {0x00, 0x11, 0xbb, 0xcc, 0xdd, 0x80}; ++ ++ ++ ++ ++// CNS3XXX_NIC_MODE_8021Q, CNS3XXX_NON_NIC_MODE_8021Q, CNS3XXX_VLAN_BASE_MODE and ++// CNS3XXX_PORT_BASE_MODE, only one macro can be defined ++ ++#ifdef CNS3XXX_VLAN_8021Q ++ #define CNS3XXX_NIC_MODE_8021Q ++ #ifndef CNS3XXX_NIC_MODE_8021Q ++ #define CNS3XXX_NON_NIC_MODE_8021Q ++ #endif ++#else ++ //#define CNS3XXX_VLAN_BASE_MODE ++ #define CNS3XXX_PORT_BASE_MODE ++#endif ++ ++//#define CNS3XXX_PORT_BASE_MODE ++// ++#ifdef CNS3XXX_NON_NIC_MODE_8021Q ++ ++#define PORT0_PVID 50 ++#define PORT1_PVID 60 ++#define PORT2_PVID 70 ++#define CPU_PVID 80 ++ ++#define CONFIG_CNS3XXX_PORT_BASE ++ ++static VLANTableEntry cpu_vlan_table_entry = {0, 1, CPU_PVID, 0, 0, MAC_PORT0_PMAP | MAC_PORT1_PMAP | MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan3_mac}; ++ ++static VLANTableEntry vlan_table_entry[] = ++{ ++ // vlan_index; valid; vid; wan_side; etag_pmap; mb_pmap; *my_mac; ++ #if 0 ++ {1, 1, PORT0_PVID, 0, 0, MAC_PORT0_PMAP | CPU_PORT_PMAP, my_vlan0_mac}, ++ {2, 1, PORT1_PVID, 0, 0, MAC_PORT1_PMAP | CPU_PORT_PMAP, my_vlan1_mac}, ++ {3, 1, PORT2_PVID, 1, 0, MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan2_mac}, ++ #endif ++ ++ {1, 1, PORT0_PVID, 0, CPU_PORT_PMAP, MAC_PORT0_PMAP | CPU_PORT_PMAP, my_vlan0_mac}, ++ {2, 1, PORT1_PVID, 0, CPU_PORT_PMAP, MAC_PORT1_PMAP | CPU_PORT_PMAP, my_vlan1_mac}, ++ {3, 1, PORT2_PVID, 0, CPU_PORT_PMAP, MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan2_mac}, ++ //{2, 1, 4, 0, 0, MAC_PORT0_PMAP | MAC_PORT1_PMAP | MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan3_mac}, // for cpu ++}; ++ ++static ARLTableEntry arl_table_entry[] = ++{ ++ // vid; pmap; *mac; age_field; vlan_mac ; filter ++ {PORT0_PVID, CPU_PORT_PMAP, my_vlan0_mac, 7, 1, 0}, ++ //{CPU_PVID, CPU_PORT_PMAP, my_vlan0_mac, 7, 1, 0}, ++ {PORT1_PVID, CPU_PORT_PMAP, my_vlan1_mac, 7, 1, 0}, ++ {PORT2_PVID, CPU_PORT_PMAP, my_vlan2_mac, 7, 1, 0}, ++ //{PORT0_PVID, MAC_PORT0_PMAP, my_vlan8_mac, 7, 0, 0}, ++ //{PORT0_PVID, MAC_PORT0_PMAP, my_vlan9_mac, 7, 0, 0}, ++ //{CPU_PVID, 0x4, my_vlan2_mac, 7, 1, 0}, ++ //{CPU_PVID, MAC_PORT2_PMAP, my_vlan2_mac, 7, 1, 0}, ++}; ++ ++static NetDevicePriv net_device_prive[]= { ++ /* pmap, is_wan, s-tag, vlan_tag or pvid, rx_func_ptr, tx_func_ptr, open_ptr, close_ptr, which port, mac, VLANTableEntry, ARLTableEntry, NICSetting, netdev s-tag, name */ ++ {MAC_PORT0_PMAP, 0, 1, PORT0_NETDEV_INDEX, rx_port_base, tx_port_base, open_port0, close_port0, MAC_PORT0, my_vlan0_mac, &vlan_table_entry[0], &arl_table_entry[0], 0, 0}, // eth0 ++ {MAC_PORT1_PMAP, 0, 2, PORT1_NETDEV_INDEX, rx_port_base, tx_port_base, open_port1, close_port1, MAC_PORT1, my_vlan1_mac, &vlan_table_entry[1], &arl_table_entry[1], 0, 0}, // eth1 ++ {MAC_PORT2_PMAP, 1, 3, PORT2_NETDEV_INDEX, rx_port_base, tx_port_base, open_port2, close_port2, MAC_PORT2, my_vlan2_mac, &vlan_table_entry[2], &arl_table_entry[2], 0, 0} // eth2 ++#if defined (CONFIG_CNS3XXX_SPPE) ++ ,{CPU_PORT_PMAP, 0, 1, FP_NETDEV_INDEX, NULL, fp_port_base, ++ open_fp, close_fp, CPU_PORT, my_vlan3_mac, &cpu_vlan_table_entry, ++ 0, 0, "fp"} ++#endif ++ }; ++ ++#endif // CNS3XXX_PORT_BASE_MODE ++ ++#ifdef CNS3XXX_PORT_BASE_MODE ++ ++#define PORT0_PVID 0x1 ++#define PORT1_PVID 0x2 ++#define PORT2_PVID 3 ++#define CPU_PVID 5 ++ ++#define CONFIG_CNS3XXX_PORT_BASE ++ ++static VLANTableEntry cpu_vlan_table_entry = {0, 1, CPU_PVID, 0, 0, MAC_PORT0_PMAP | MAC_PORT1_PMAP | MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan3_mac}; ++ ++static VLANTableEntry vlan_table_entry[] = ++{ ++ // vlan_index; valid; vid; wan_side; etag_pmap; mb_pmap; *my_mac; ++ //{0, 1, 1, 0, 0, MAC_PORT0_PMAP | MAC_PORT1_PMAP | MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan0_mac}, ++ {1, 1, PORT0_PVID, 0, 0, MAC_PORT0_PMAP | CPU_PORT_PMAP, my_vlan0_mac}, ++ {2, 1, PORT1_PVID, 0, 0, MAC_PORT1_PMAP | CPU_PORT_PMAP, my_vlan1_mac}, ++ {3, 1, PORT2_PVID, 1, 0, MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan2_mac}, ++ //{2, 1, 4, 0, 0, MAC_PORT0_PMAP | MAC_PORT1_PMAP | MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan3_mac}, // for cpu ++}; ++ ++static ARLTableEntry arl_table_entry[] = ++{ ++ // vid; pmap; *mac; age_field; vlan_mac ; filter ++ {PORT0_PVID, CPU_PORT_PMAP, my_vlan0_mac, 7, 1, 0}, ++ //{CPU_PVID, CPU_PORT_PMAP, my_vlan0_mac, 7, 1, 0}, ++ {PORT1_PVID, CPU_PORT_PMAP, my_vlan1_mac, 7, 1, 0}, ++ {PORT2_PVID, CPU_PORT_PMAP, my_vlan2_mac, 7, 1, 0}, ++ //{PORT0_PVID, MAC_PORT0_PMAP, my_vlan8_mac, 7, 0, 0}, ++ //{PORT0_PVID, MAC_PORT0_PMAP, my_vlan9_mac, 7, 0, 0}, ++ //{CPU_PVID, 0x4, my_vlan2_mac, 7, 1, 0}, ++ //{CPU_PVID, MAC_PORT2_PMAP, my_vlan2_mac, 7, 1, 0}, ++}; ++ ++static NetDevicePriv net_device_prive[]= { ++ /* pmap, is_wan, s-tag, vlan_tag or pvid, rx_func_ptr, tx_func_ptr, open_ptr, close_ptr, which port, mac, VLANTableEntry, ARLTableEntry, NICSetting, netdev s-tag, name */ ++ {MAC_PORT0_PMAP, 0, 1, PORT0_NETDEV_INDEX, rx_port_base, tx_port_base, open_port0, close_port0, MAC_PORT0, my_vlan0_mac, &vlan_table_entry[0], &arl_table_entry[0], 0, 0}, // eth0 ++ {MAC_PORT1_PMAP, 0, 2, PORT1_NETDEV_INDEX, rx_port_base, tx_port_base, open_port1, close_port1, MAC_PORT1, my_vlan1_mac, &vlan_table_entry[1], &arl_table_entry[1], 0, 0}, // eth1 ++ {MAC_PORT2_PMAP, 1, 3, PORT2_NETDEV_INDEX, rx_port_base, tx_port_base, open_port2, close_port2, MAC_PORT2, my_vlan2_mac, &vlan_table_entry[2], &arl_table_entry[2], 0, 0} // eth2 ++ }; ++ ++#endif // CNS3XXX_PORT_BASE_MODE ++ ++#ifdef CNS3XXX_NIC_MODE_8021Q ++//#error "8021Q" ++#define PORT0_PVID 1 ++#define PORT1_PVID 2 ++#define PORT2_PVID 9 ++#define CPU_PVID 5 ++ ++#define CONFIG_CNS3XXX_PORT_BASE ++//#define CONFIG_CNS3XXX_VLAN_BASE ++//#define CONFIG_HAVE_VLAN_TAG ++ ++static VLANTableEntry cpu_vlan_table_entry = {0, 1, CPU_PVID, 0, 0, MAC_PORT0_PMAP | MAC_PORT1_PMAP | MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan3_mac}; // for cpu ++ ++static VLANTableEntry vlan_table_entry[] = ++{ ++ // vlan_index; valid; vid; wan_side; etag_pmap; mb_pmap; *my_mac;C_PORT2_PMAP ++ {1, 1, PORT0_PVID, 1, MAC_PORT0_PMAP|CPU_PORT_PMAP, MAC_PORT0_PMAP | CPU_PORT_PMAP, my_vlan0_mac}, ++ {2, 1, PORT1_PVID, 0, MAC_PORT1_PMAP|CPU_PORT_PMAP, MAC_PORT1_PMAP | CPU_PORT_PMAP, my_vlan1_mac}, ++ {3, 1, PORT2_PVID, 1, MAC_PORT2_PMAP|CPU_PORT_PMAP, MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan2_mac}, ++}; ++ ++static ARLTableEntry arl_table_entry[] = ++{ ++ // vid; pmap; *mac; age_field; vlan_mac ; filter ++ {PORT0_PVID, CPU_PORT_PMAP, my_vlan0_mac, 7, 1, 0}, ++ {PORT1_PVID, CPU_PORT_PMAP, my_vlan1_mac, 7, 1, 0}, ++ {PORT2_PVID, CPU_PORT_PMAP, my_vlan2_mac, 7, 1, 0}, ++}; ++ ++ ++// if used 8021Q, use PORT0_NETDEV_INDEX, don't use VID ++static NetDevicePriv net_device_prive[]= { ++ {MAC_PORT0_PMAP, 0, 1, PORT0_NETDEV_INDEX, rx_port_base, tx_port_base, open_port0, close_port0, MAC_PORT0, my_vlan0_mac, &vlan_table_entry[0], &arl_table_entry[0], 0, 0}, // eth0 ++ {MAC_PORT1_PMAP, 0, 0, PORT1_NETDEV_INDEX, rx_port_base, tx_port_base, open_port1, close_port1, MAC_PORT1, my_vlan1_mac, &vlan_table_entry[1], &arl_table_entry[1], 0, 0}, // eth1 ++ {MAC_PORT2_PMAP, 1, 3, PORT2_NETDEV_INDEX, rx_port_base, tx_port_base, open_port2, close_port2, MAC_PORT2, my_vlan2_mac, &vlan_table_entry[2], &arl_table_entry[2], 0, 0} // eth2 ++ }; ++#endif // CNS3XXX_NIC_MODE_8021Q ++ ++#ifdef CNS3XXX_VLAN_BASE_MODE ++//#error "vlan_base" ++// vlan configuration ++ ++#define PORT0_PVID 1 ++#define PORT1_PVID 2 ++#define PORT2_PVID 3 ++#define CPU_PVID 5 ++#define CONFIG_CNS3XXX_VLAN_BASE ++#define CONFIG_HAVE_VLAN_TAG ++ ++static VLANTableEntry cpu_vlan_table_entry = {0, 1, CPU_PVID, 0, MAC_PORT0_PMAP | MAC_PORT1_PMAP | MAC_PORT2_PMAP | CPU_PORT_PMAP, MAC_PORT0_PMAP | MAC_PORT1_PMAP | MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan3_mac}; // for cpu ++ ++static VLANTableEntry vlan_table_entry[] = ++{ ++ // vlan_index; valid; vid; wan_side; etag_pmap; mb_pmap; *my_mac; ++ {1, 1, PORT0_PVID, 0, MAC_PORT0_PMAP | CPU_PORT_PMAP, MAC_PORT0_PMAP | CPU_PORT_PMAP, my_vlan0_mac}, ++ {2, 1, PORT1_PVID, 0, MAC_PORT1_PMAP | CPU_PORT_PMAP, MAC_PORT1_PMAP | CPU_PORT_PMAP, my_vlan1_mac}, ++ {3, 1, PORT2_PVID, 1, MAC_PORT2_PMAP | CPU_PORT_PMAP, MAC_PORT2_PMAP | CPU_PORT_PMAP, my_vlan2_mac}, ++}; ++ ++static ARLTableEntry arl_table_entry[] = ++{ ++ // vid; pmap; *mac; age_field; vlan_mac ; filter ++ {PORT0_PVID, CPU_PORT_PMAP, my_vlan0_mac, 7, 1, 0}, ++ {PORT1_PVID, CPU_PORT_PMAP, my_vlan1_mac, 7, 1, 0}, ++ {PORT2_PVID, CPU_PORT_PMAP, my_vlan2_mac, 7, 1, 0}, ++}; ++ ++static NetDevicePriv net_device_prive[]= { ++ /* pmap, is_wan, gid, vlan_tag or pvid, rx_func_ptr, tx_func_ptr, open_ptr, close_ptr, which port, mac, VLANTableEntry, ARLTableEntry, NICSetting, netdev name */ ++ {MAC_PORT0_PMAP, 0, 1, PORT0_PVID, rx_port_base, tx_vlan_base, open_port0, close_port0, MAC_PORT0, my_vlan0_mac, &vlan_table_entry[0], &arl_table_entry[0], 0, 0}, // eth0 ++ {MAC_PORT1_PMAP, 0, 0, PORT1_PVID, rx_port_base, tx_vlan_base, open_port1, close_port1, MAC_PORT1, my_vlan1_mac, &vlan_table_entry[1], &arl_table_entry[1], 0, 0}, // eth1 ++ {MAC_PORT2_PMAP, 1, 3, PORT2_PVID, rx_port_base, tx_vlan_base, open_port2, close_port2, MAC_PORT2, my_vlan2_mac, &vlan_table_entry[2], &arl_table_entry[2], 0, 0} // eth2 ++ }; ++#endif // CNS3XXX_VLAN_BASE_MODE ++ ++#endif // CONFIG_VB ++#endif // VB_H +--- a/drivers/net/Kconfig ++++ b/drivers/net/Kconfig +@@ -2076,6 +2076,8 @@ menuconfig NETDEV_1000 + + if NETDEV_1000 + ++source "drivers/net/cns3xxx/Kconfig" ++ + config ACENIC + tristate "Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support" + depends on PCI +--- a/drivers/net/Makefile ++++ b/drivers/net/Makefile +@@ -6,6 +6,11 @@ obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci + + obj-$(CONFIG_E1000) += e1000/ + obj-$(CONFIG_E1000E) += e1000e/ ++obj-$(CONFIG_CNS3XXX_GSW) += cns3xxx/ ++ifeq ($(CONFIG_CNS3XXX_GSW),m) ++ obj-y += cns3xxx/cns3xxx_sppe_hook.o ++endif ++ + obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/ + obj-$(CONFIG_IGB) += igb/ + obj-$(CONFIG_IGBVF) += igbvf/ +--- /dev/null ++++ b/include/linux/cns3xxx/sppe.h +@@ -0,0 +1,1579 @@ ++/* ++ * PROJECT CODE: CNS3XXX Smart Packet Processing Engine ++ * MODULE NAME: sppe.h ++ * DESCRIPTION: ++ * ++ * Change Log ++ * ++ * 1.0.0 25-Dec-2008 ++ * o ++ * ++ */ ++ ++#ifndef _SPPE_H_ ++#define _SPPE_H_ ++ ++#if defined(CONFIG_CNS3XXX_SPPE) ++ ++ ++/* PPE Table Size Def. */ ++#define PPE_TABLE_SIZE_2K (0x0) ++#define PPE_TABLE_SIZE_4K (0x1) ++#define PPE_TABLE_SIZE_8K (0x2) ++#define PPE_TABLE_SIZE_16K (0x3) ++#define PPE_TABLE_SIZE_32K (0x4) ++#define PPE_TABLE_SIZE_64K (0x5) ++#define PPE_TABLE_SIZE_128K (0x6) ++#define PPE_TABLE_SIZE_256K (0x7) ++ ++typedef enum _sppe_cmd { ++ SPPE_CMD_INIT = 0, ++ SPPE_CMD_VERSION, ++ ++ SPPE_CMD_ENABLE, ++ SPPE_CMD_FIREWALL, ++ SPPE_CMD_RULE_CHECK, ++ SPPE_CMD_GRL_CHECK, ++ SPPE_CMD_FLOW_CHECK, ++ SPPE_CMD_RATE_LIMIT_EN, ++ SPPE_CMD_POLICE_EN, ++ SPPE_CMD_RLCFG, ++ SPPE_CMD_FC, /* flow control */ ++ SPPE_CMD_MIRROR_TO_CPU, ++ ++ SPPE_CMD_TCP_SNA_TH, ++ SPPE_CMD_PRDA, ++ SPPE_CMD_AGING, ++ SPPE_CMD_MAX_LENGTH, ++ ++ SPPE_CMD_LANIPV4, ++ SPPE_CMD_WANIPV4, ++ ++ SPPE_CMD_RULE_PPPOE_RELAY, ++ SPPE_CMD_RULE_BRIDGE, ++ SPPE_CMD_RULE_ACL, ++ SPPE_CMD_RULE_ROUTE, ++#if 0 ++ SPPE_CMD_RULE_VSERVER, ++#else ++ SPPE_CMD_RULE_SNAT, ++ SPPE_CMD_RULE_DNAT, ++#endif ++ SPPE_CMD_RULE_GRL, ++ ++ SPPE_CMD_ARP, ++ SPPE_CMD_ARL, ++ SPPE_CMD_PPPOE_SID, ++ ++ SPPE_CMD_FLOW_BRIDGE_IPV4, ++ SPPE_CMD_FLOW_BRIDGE_IPV6, ++ SPPE_CMD_FLOW_ROUTE_IPV4, ++ SPPE_CMD_FLOW_ROUTE_IPV6, ++ SPPE_CMD_FLOW_NAT_IPV4, ++ SPPE_CMD_FLOW_NAT_IPV6, ++ //SPPE_CMD_FLOW_TWICE_NAT, ++ SPPE_CMD_FLOW_MCAST_IPV4, ++ SPPE_CMD_FLOW_MCAST_IPV6, ++ SPPE_CMD_FLOW_BRIDGE_L2, ++ ++ SPPE_CMD_CHGDSCP, ++ SPPE_CMD_CHGPRI, ++ SPPE_CMD_RL_FLOW, ++ SPPE_CMD_RL_RULE, ++ ++ SPPE_CMD_DEBUG, ++ SPPE_CMD_REG, ++ SPPE_CMD_SRAM, ++ SPPE_CMD_DUMP, ++ ++ /* accounting group and drop packet count */ ++ SPPE_CMD_ACCOUNTING_GROUP, ++ SPPE_CMD_DROP_IPCS_ERR, ++ SPPE_CMD_DROP_RATE_LIMIT, ++ SPPE_CMD_DROP_OTHERS, ++ ++ SPPE_CMD_PCI_FP_DEV, ++ ++} SPPE_CMD; ++ ++typedef enum _sppe_op { ++ SPPE_OP_GET = 0, ++ SPPE_OP_SET, ++ SPPE_OP_DELETE, ++ SPPE_OP_DELETE_OUTDATED, /* flow only */ ++ SPPE_OP_UPDATE_COUNTER, /* ACL rule only */ ++ SPPE_OP_CLEAN, ++ SPPE_OP_UNKNOWN ++} SPPE_OP; ++ ++typedef enum _sppe_boolean { ++ SPPE_BOOL_FALSE = 0, ++ SPPE_BOOL_TRUE = 1 ++} SPPE_BOOL; ++ ++ ++typedef enum _sppe_result { ++ SPPE_RESULT_SUCCESS = 0, ++ SPPE_RESULT_FAIL, ++ SPPE_RESULT_UNSUPPORT_CMD, ++ SPPE_RESULT_UNSUPPORT_OP, ++ SPPE_RESULT_INVALID_INDEX, ++ SPPE_RESULT_INVALID_TYPE, ++ SPPE_RESULT_FLOW_NOT_FOUND, ++} SPPE_RESULT; ++ ++typedef enum _sppe_prot { ++ SPPE_PROT_UDP = 0, ++ SPPE_PROT_TCP = 1, ++ SPPE_PROT_PPTP_GRE = 2, ++ SPPE_PROT_OTHERS = 3, ++} SPPE_PROT; ++ ++ ++typedef enum _sppe_l2_select { ++ SPPE_L2S_ARP_TABLE = 0, ++ SPPE_L2S_POLICY_ROUTE = 1, ++ SPPE_L2S_IN_FLOW = 2, ++ SPPE_L2S_RESERVED = 3, ++} SPPE_L2_SELECT; ++ ++typedef enum _sppe_dump_type { ++ SPPE_DUMP_TYPE_FLOW = 0, ++ SPPE_DUMP_TYPE_ARP, ++ SPPE_DUMP_TYPE_RULE ++} SPPE_DUMP_TYPE; ++ ++/* Data Structure */ ++typedef struct _sppe_pppoe_relay { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int valid:1; ++ unsigned int unused:31; ++#else ++ unsigned int unused:31; ++ unsigned int valid:1; ++#endif ++ unsigned short lsid; /* PPPoE session ID in LAN side */ ++ unsigned short wsid; /* PPPoE session ID in WAN side */ ++ unsigned char lmac[6]; /* MAC address of PPPoE client */ ++ unsigned char wmac[6]; /* MAC address of PPPoE server */ ++} SPPE_PPPOE_RELAY; ++ ++typedef struct _sppe_bridge { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int valid:1; ++ unsigned int wan:1; ++ unsigned int ppp:1; /* enable PPPoE sessoion ID comparison*/ ++ unsigned int psidx:4; /* PPPoE session ID index */ ++ unsigned int kv:1; ++ unsigned int sws:1; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int fp:1; /* force VLAN priority */ ++ unsigned int pri:3; ++ unsigned int ag:2; ++ unsigned int unused:15; ++#else ++ unsigned int unused:15; ++ unsigned int ag:2; ++ unsigned int pri:3; ++ unsigned int fp:1; /* force VLAN priority */ ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int sws:1; ++ unsigned int kv:1; ++ unsigned int psidx:4; /* PPPoE session ID index */ ++ unsigned int ppp:1; /* enable PPPoE sessoion ID comparison*/ ++ unsigned int wan:1; ++ unsigned int valid:1; ++#endif ++ ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int svid:12; ++ unsigned int cvid:12; ++ unsigned int loc:8; ++#else ++ unsigned int loc:8; ++ unsigned int cvid:12; ++ unsigned int svid:12; ++#endif ++ ++ unsigned char smac[6]; /* source MAC address */ ++ unsigned char dmac[6]; /* destination MAC address */ ++ unsigned int pkt_cnt; ++} SPPE_BRIDGE; ++ ++typedef struct _sppe_acl { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int valid:1; ++ unsigned int ipv6:1; ++ unsigned int wan:1; ++ unsigned int tcp:1; ++ unsigned int udp:1; ++ unsigned int to:4; ++ unsigned int from:4; ++ unsigned int rr:4; ++ unsigned int kv:1; ++ unsigned int sws:1; ++ unsigned int loc:8; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int unused:3; ++#else ++ unsigned int unused:3; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int loc:8; ++ unsigned int sws:1; ++ unsigned int kv:1; ++ unsigned int rr:4; ++ unsigned int from:4; ++ unsigned int to:4; ++ unsigned int udp:1; ++ unsigned int tcp:1; ++ unsigned int wan:1; ++ unsigned int ipv6:1; ++ unsigned int valid:1; ++#endif ++ ++ unsigned int sip[4]; ++ unsigned int dip[4]; ++ unsigned short sip_mask; ++ unsigned short dip_mask; ++ ++ unsigned short sport_start; ++ unsigned short sport_end; ++ unsigned short dport_start; ++ unsigned short dport_end; ++ unsigned int pkt_cnt; ++} SPPE_ACL; ++ ++typedef struct _sppe_route { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int valid:1; ++ unsigned int ipv6:1; ++ unsigned int wan:1; ++ unsigned int rd:1; /* replace dscp */ ++ unsigned int dscp:6; ++ unsigned int pr:1; /* policy route */ ++ unsigned int prs:2; /* policy route select */ ++ unsigned int kv:1; ++ unsigned int sws:1; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int fp:1; /* force VLAN priority */ ++ unsigned int pri:3; ++ unsigned int pd:1; ++ unsigned int pi:1; ++ unsigned int psidx:4; ++ unsigned int ag:2; ++ unsigned int unused:3; ++#else ++ unsigned int unused:3; ++ unsigned int ag:2; ++ unsigned int psidx:4; ++ unsigned int pi:1; ++ unsigned int pd:1; ++ unsigned int pri:3; ++ unsigned int fp:1; /* force VLAN priority */ ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int sws:1; ++ unsigned int kv:1; ++ unsigned int prs:2; /* policy route select */ ++ unsigned int pr:1; /* policy route */ ++ unsigned int dscp:6; ++ unsigned int rd:1; /* replace dscp */ ++ unsigned int wan:1; ++ unsigned int ipv6:1; ++ unsigned int valid:1; ++#endif ++ ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int unused_1:24; ++ unsigned int loc:8; ++#else ++ unsigned int loc:8; ++ unsigned int unused_1:24; ++#endif ++ ++ unsigned int dip[4]; ++ unsigned int sip[4]; ++ unsigned short dip_mask; ++ unsigned short sip_mask; ++ unsigned int pkt_cnt; ++} SPPE_ROUTE; ++ ++#if 0 ++typedef struct _sppe_vserver { ++ unsigned int valid:1; ++ unsigned int tcp:1; ++ unsigned int udp:1; ++ unsigned int dscp_lan:6; ++ unsigned int dscp_wan:6; ++ unsigned int pri_lan:3; ++ unsigned int pri_wan:3; ++ unsigned int unused:11; ++ ++ unsigned int wanip; ++ unsigned int lanip; ++ unsigned short port_start; ++ unsigned short port_end; ++ unsigned int pkt_cnt; ++} SPPE_VSERVER; ++#else ++typedef struct _sppe_snat { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int valid:1; ++ unsigned int tcp:1; ++ unsigned int udp:1; ++ unsigned int rd:1; ++ unsigned int dscp:6; ++ unsigned int fp:1; ++ unsigned int pri:3; ++ unsigned int kv:1; ++ unsigned int sws:1; ++ unsigned int max_len:2; ++ unsigned int pd:1; ++ unsigned int pi:1; ++ unsigned int psidx:4; ++ unsigned int pr:1; /* policy route */ ++ unsigned int prs:2; /* policy route select */ ++ unsigned int ag:2; ++ unsigned int unused:3; ++#else ++ unsigned int unused:3; ++ unsigned int ag:2; ++ unsigned int prs:2; /* policy route select */ ++ unsigned int pr:1; /* policy route */ ++ unsigned int psidx:4; ++ unsigned int pi:1; ++ unsigned int pd:1; ++ unsigned int max_len:2; ++ unsigned int sws:1; ++ unsigned int kv:1; ++ unsigned int pri:3; ++ unsigned int fp:1; ++ unsigned int dscp:6; ++ unsigned int rd:1; ++ unsigned int udp:1; ++ unsigned int tcp:1; ++ unsigned int valid:1; ++#endif ++ ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int unused_1:24; ++ unsigned int loc:8; ++#else ++ unsigned int loc:8; ++ unsigned int unused_1:24; ++#endif ++ ++ unsigned int wanip; ++ unsigned int lanip; ++ unsigned short port_start; ++ unsigned short port_end; ++ unsigned int pkt_cnt; ++} SPPE_SNAT; ++ ++typedef struct _sppe_dnat { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int valid:1; ++ unsigned int tcp:1; ++ unsigned int udp:1; ++ unsigned int rd:1; ++ unsigned int dscp:6; ++ unsigned int fp:1; ++ unsigned int pri:3; ++ unsigned int kv:1; ++ unsigned int sws:1; ++ unsigned int max_len:2; ++ unsigned int pd:1; ++ unsigned int pi:1; ++ unsigned int psidx:4; ++ unsigned int pr:1; /* policy route */ ++ unsigned int prs:2; /* policy route select */ ++ unsigned int ag:2; ++ unsigned int unused:3; ++#else ++ unsigned int unused:3; ++ unsigned int ag:2; ++ unsigned int prs:2; /* policy route select */ ++ unsigned int pr:1; /* policy route */ ++ unsigned int psidx:4; ++ unsigned int pi:1; ++ unsigned int pd:1; ++ unsigned int max_len:2; ++ unsigned int sws:1; ++ unsigned int kv:1; ++ unsigned int pri:3; ++ unsigned int fp:1; ++ unsigned int dscp:6; ++ unsigned int rd:1; ++ unsigned int udp:1; ++ unsigned int tcp:1; ++ unsigned int valid:1; ++#endif ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int unused_1:24; ++ unsigned int loc:8; ++#else ++ unsigned int loc:8; ++ unsigned int unused_1:24; ++#endif ++ ++ unsigned int wanip; ++ unsigned int lanip; ++ unsigned short port_start; ++ unsigned short port_end; ++ unsigned int pkt_cnt; ++} SPPE_DNAT; ++#endif ++typedef struct _sppe_limit { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int drop_red:1; ++ unsigned int pass_green:1; ++ unsigned int force_color:1; ++ unsigned int color_select:2; ++ unsigned int time_stamp:21; ++ unsigned int reserved:6; ++#else ++ unsigned int reserved:6; ++ unsigned int time_stamp:21; ++ unsigned int color_select:2; ++ unsigned int force_color:1; ++ unsigned int pass_green:1; ++ unsigned int drop_red:1; ++#endif ++ unsigned short min_rate; ++ unsigned short max_rate; ++} SPPE_LIMIT; ++ ++typedef struct _sppe_global_rate_limit { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int valid:1; ++ unsigned int wan:1; ++ unsigned int ipv6:1; ++ unsigned int tcp:1; ++ unsigned int udp:1; ++ unsigned int unused:17; ++#else ++ unsigned int unused:17; ++ unsigned int udp:1; ++ unsigned int tcp:1; ++ unsigned int ipv6:1; ++ unsigned int wan:1; ++ unsigned int valid:1; ++#endif ++ ++ unsigned int sip[4]; ++ unsigned int dip[4]; ++ unsigned short sip_mask; ++ unsigned short dip_mask; ++ unsigned short sport_start; ++ unsigned short sport_end; ++ unsigned short dport_start; ++ unsigned short dport_end; ++ SPPE_LIMIT limit; ++} SPPE_GLOBAL_RATE_LIMIT; ++ ++/* ++ * SPPE_CMD_FLOW_BRIDGE_IPV4 ++ * type = 1 , as = 3 ++ */ ++typedef struct _sppe_flow_bridge_ipv4 { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int fw:1; ++ unsigned int s:1; ++ unsigned int sws:1; ++ unsigned int ag:2; ++ unsigned int rl:1; ++ unsigned int l4_prot:2; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int prs:2; ++ unsigned int kv:1; ++ unsigned int fp:1; ++ unsigned int pri:3; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int reserved:13; ++#else ++ unsigned int reserved:13; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int pri:3; ++ unsigned int fp:1; ++ unsigned int kv:1; ++ unsigned int prs:2; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int l4_prot:2; ++ unsigned int rl:1; ++ unsigned int ag:2; ++ unsigned int sws:1; ++ unsigned int s:1; ++ unsigned int fw:1; ++#endif ++ ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int unused:16; ++ unsigned int mac4732:16; ++#else ++ unsigned int mac4732:16; ++ unsigned int unused:16; ++#endif ++ ++ unsigned int mac3100; ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int lp:1; ++ unsigned int fr:1; ++ unsigned int pm:4; ++ unsigned int sv:1; ++ unsigned int svid:12; ++ unsigned int cv:1; ++ unsigned int cvid:12; ++#else ++ unsigned int cvid:12; ++ unsigned int cv:1; ++ unsigned int svid:12; ++ unsigned int sv:1; ++ unsigned int pm:4; ++ unsigned int fr:1; ++ unsigned int lp:1; ++#endif ++ unsigned int sip; ++ unsigned int dip; ++ ++ union { ++ struct { ++ unsigned short src; ++ unsigned short dst; ++ } port; ++ struct { ++ unsigned short call_id; ++ } gre; ++ struct { ++ unsigned char protocol; ++ } others; ++ } l4; ++ ++ SPPE_LIMIT limit; ++ unsigned int pkt_cnt; ++} SPPE_FLOW_BRIDGE_IPV4; ++ ++/* ++ * SPPE_CMD_FLOW_BRIDGE_IPV6 ++ * type = 2 , as = 3 ++ */ ++typedef struct _sppe_flow_bridge_ipv6 { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int fw:1; ++ unsigned int s:1; ++ unsigned int sws:1; ++ unsigned int ag:2; ++ unsigned int rl:1; ++ unsigned int l4_prot:2; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int prs:2; ++ unsigned int kv:1; ++ unsigned int fp:1; ++ unsigned int pri:3; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int reserved:13; ++#else ++ unsigned int reserved:13; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int pri:3; ++ unsigned int fp:1; ++ unsigned int kv:1; ++ unsigned int prs:2; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int l4_prot:2; ++ unsigned int rl:1; ++ unsigned int ag:2; ++ unsigned int sws:1; ++ unsigned int s:1; ++ unsigned int fw:1; ++#endif ++ ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int unused:16; ++ unsigned int mac4732:16; ++#else ++ unsigned int mac4732:16; ++ unsigned int unused:16; ++#endif ++ ++ unsigned int mac3100; ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int lp:1; ++ unsigned int fr:1; ++ unsigned int pm:4; ++ unsigned int sv:1; ++ unsigned int svid:12; ++ unsigned int cv:1; ++ unsigned int cvid:12; ++#else ++ unsigned int cvid:12; ++ unsigned int cv:1; ++ unsigned int svid:12; ++ unsigned int sv:1; ++ unsigned int pm:4; ++ unsigned int fr:1; ++ unsigned int lp:1; ++#endif ++ unsigned int sip[4]; ++ unsigned int dip[4]; ++ union { ++ struct { ++ unsigned short src; ++ unsigned short dst; ++ } port; ++ struct { ++ unsigned short call_id; ++ } gre; ++ struct { ++ unsigned char protocol; ++ } others; ++ } l4; ++ SPPE_LIMIT limit; ++ unsigned int pkt_cnt; ++} SPPE_FLOW_BRIDGE_IPV6; ++ ++/* ++ * SPPE_CMD_FLOW_ROUTE_IPV4 ++ * type = 1, as = 0 ++ */ ++typedef struct _sppe_flow_route_ipv4 { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int fw:1; ++ unsigned int s:1; ++ unsigned int sws:1; ++ unsigned int ag:2; ++ unsigned int rl:1; ++ unsigned int l4_prot:2; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int prs:2; ++ unsigned int kv:1; ++ unsigned int rd:1; ++ unsigned int dscp:6; ++ unsigned int fp:1; ++ unsigned int pri:3; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int pd:1; ++ unsigned int pi:1; ++ unsigned int psidx:4; ++#else ++ unsigned int psidx:4; ++ unsigned int pi:1; ++ unsigned int pd:1; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int pri:3; ++ unsigned int fp:1; ++ unsigned int dscp:6; ++ unsigned int rd:1; ++ unsigned int kv:1; ++ unsigned int prs:2; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int l4_prot:2; ++ unsigned int rl:1; ++ unsigned int ag:2; ++ unsigned int sws:1; ++ unsigned int s:1; ++ unsigned int fw:1; ++#endif ++ ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int unused:16; ++ unsigned int mac4732:16; ++#else ++ unsigned int mac4732:16; ++ unsigned int unused:16; ++#endif ++ unsigned int mac3100; ++ ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int lp:1; ++ unsigned int fr:1; ++ unsigned int pm:4; ++ unsigned int sv:1; ++ unsigned int svid:12; ++ unsigned int cv:1; ++ unsigned int cvid:12; ++#else ++ unsigned int cvid:12; ++ unsigned int cv:1; ++ unsigned int svid:12; ++ unsigned int sv:1; ++ unsigned int pm:4; ++ unsigned int fr:1; ++ unsigned int lp:1; ++#endif ++ ++ unsigned int sip; ++ unsigned int dip; ++ union { ++ struct { ++ unsigned short src; ++ unsigned short dst; ++ } port; ++ struct { ++ unsigned short call_id; ++ } gre; ++ struct { ++ unsigned char protocol; ++ } others; ++ } l4; ++ SPPE_LIMIT limit; ++ unsigned int pkt_cnt; ++} SPPE_FLOW_ROUTE_IPV4; ++ ++/* ++ * SPPE_CMD_FLOW_ROUTE_IPV6 ++ * type = 2, as = 0 ++ */ ++typedef struct _sppe_flow_route_ipv6 { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int fw:1; ++ unsigned int s:1; ++ unsigned int sws:1; ++ unsigned int ag:2; ++ unsigned int rl:1; ++ unsigned int l4_prot:2; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int prs:2; ++ unsigned int kv:1; ++ unsigned int rd:1; ++ unsigned int dscp:6; ++ unsigned int fp:1; ++ unsigned int pri:3; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int pd:1; ++ unsigned int pi:1; ++ unsigned int psidx:4; ++#else ++ unsigned int psidx:4; ++ unsigned int pi:1; ++ unsigned int pd:1; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int pri:3; ++ unsigned int fp:1; ++ unsigned int dscp:6; ++ unsigned int rd:1; ++ unsigned int kv:1; ++ unsigned int prs:2; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int l4_prot:2; ++ unsigned int rl:1; ++ unsigned int ag:2; ++ unsigned int sws:1; ++ unsigned int s:1; ++ unsigned int fw:1; ++#endif ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int unused:16; ++ unsigned int mac4732:16; ++#else ++ unsigned int mac4732:16; ++ unsigned int unused:16; ++#endif ++ unsigned int mac3100; ++ ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int lp:1; ++ unsigned int fr:1; ++ unsigned int pm:4; ++ unsigned int sv:1; ++ unsigned int svid:12; ++ unsigned int cv:1; ++ unsigned int cvid:12; ++#else ++ unsigned int cvid:12; ++ unsigned int cv:1; ++ unsigned int svid:12; ++ unsigned int sv:1; ++ unsigned int pm:4; ++ unsigned int fr:1; ++ unsigned int lp:1; ++#endif ++ unsigned int sip[4]; ++ unsigned int dip[4]; ++ union { ++ struct { ++ unsigned short src; ++ unsigned short dst; ++ } port; ++ struct { ++ unsigned short call_id; ++ } gre; ++ struct { ++ unsigned char protocol; ++ } others; ++ } l4; ++ SPPE_LIMIT limit; ++ unsigned int pkt_cnt; ++} SPPE_FLOW_ROUTE_IPV6; ++ ++/* ++ * SPPE_CMD_FLOW_NAT_IPV4 ++ * type = 0, as = 1 ++ */ ++typedef struct _sppe_flow_nat_ipv4 { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int fw:1; ++ unsigned int s:1; ++ unsigned int sws:1; ++ unsigned int ag:2; ++ unsigned int rl:1; ++ unsigned int l4_prot:2; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int prs:2; ++ unsigned int kv:1; ++ unsigned int rd:1; ++ unsigned int dscp:6; ++ unsigned int fp:1; ++ unsigned int pri:3; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int pd:1; ++ unsigned int pi:1; ++ unsigned int psidx:4; ++#else ++ unsigned int psidx:4; ++ unsigned int pi:1; ++ unsigned int pd:1; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int pri:3; ++ unsigned int fp:1; ++ unsigned int dscp:6; ++ unsigned int rd:1; ++ unsigned int kv:1; ++ unsigned int prs:2; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int l4_prot:2; ++ unsigned int rl:1; ++ unsigned int ag:2; ++ unsigned int sws:1; ++ unsigned int s:1; ++ unsigned int fw:1; ++#endif ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int unused:16; ++ unsigned int mac4732:16; ++#else ++ unsigned int mac4732:16; ++ unsigned int unused:16; ++#endif ++ ++ unsigned int mac3100; ++ ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int lp:1; ++ unsigned int fr:1; ++ unsigned int pm:4; ++ unsigned int sv:1; ++ unsigned int svid:12; ++ unsigned int cv:1; ++ unsigned int cvid:12; ++#else ++ unsigned int cvid:12; ++ unsigned int cv:1; ++ unsigned int svid:12; ++ unsigned int sv:1; ++ unsigned int pm:4; ++ unsigned int fr:1; ++ unsigned int lp:1; ++#endif ++ ++ unsigned int sip; ++ unsigned int dip; ++ union { ++ struct { ++ unsigned short src; ++ unsigned short dst; ++ } port; ++ struct { ++ unsigned short call_id; ++ unsigned short nat_call_id; ++ } gre; ++ struct { ++ unsigned char protocol; ++ } others; ++ } l4; ++ unsigned int nat_ip; ++ unsigned short nat_port; ++ SPPE_LIMIT limit; ++ unsigned int pkt_cnt; ++} SPPE_FLOW_NAT_IPV4; ++ ++/* ++ * SPPE_CMD_FLOW_NAT_IPV6 ++ * type = 1, as = 1 ++ */ ++typedef struct _sppe_flow_nat_ipv6 { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int fw:1; ++ unsigned int s:1; ++ unsigned int sws:1; ++ unsigned int ag:2; ++ unsigned int rl:1; ++ unsigned int l4_prot:2; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int prs:2; ++ unsigned int kv:1; ++ unsigned int rd:1; ++ unsigned int dscp:6; ++ unsigned int fp:1; ++ unsigned int pri:3; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int pd:1; ++ unsigned int pi:1; ++ unsigned int psidx:4; ++#else ++ unsigned int psidx:4; ++ unsigned int pi:1; ++ unsigned int pd:1; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int pri:3; ++ unsigned int fp:1; ++ unsigned int dscp:6; ++ unsigned int rd:1; ++ unsigned int kv:1; ++ unsigned int prs:2; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int l4_prot:2; ++ unsigned int rl:1; ++ unsigned int ag:2; ++ unsigned int sws:1; ++ unsigned int s:1; ++ unsigned int fw:1; ++#endif ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int unused:16; ++ unsigned int mac4732:16; ++#else ++ unsigned int mac4732:16; ++ unsigned int unused:16; ++#endif ++ unsigned int mac3100; ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int lp:1; ++ unsigned int fr:1; ++ unsigned int pm:4; ++ unsigned int sv:1; ++ unsigned int svid:12; ++ unsigned int cv:1; ++ unsigned int cvid:12; ++#else ++ unsigned int cvid:12; ++ unsigned int cv:1; ++ unsigned int svid:12; ++ unsigned int sv:1; ++ unsigned int pm:4; ++ unsigned int fr:1; ++ unsigned int lp:1; ++#endif ++ unsigned int sip[4]; ++ unsigned int dip[4]; ++ union { ++ struct { ++ unsigned short src; ++ unsigned short dst; ++ } port; ++ struct { ++ unsigned short call_id; ++ unsigned short nat_call_id; ++ } gre; ++ struct { ++ unsigned char protocol; ++ } others; ++ } l4; ++ unsigned int nat_ip[4]; ++ unsigned short nat_port; ++ SPPE_LIMIT limit; ++ unsigned int pkt_cnt; ++} SPPE_FLOW_NAT_IPV6; ++ ++/* ++ * SPPE_CMD_FLOW_TWICE_NAT ++ * type = 0, as = 2 ++ */ ++typedef struct _sppe_flow_twice_nat { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int fw:1; ++ unsigned int s:1; ++ unsigned int sws:1; ++ unsigned int ag:2; ++ unsigned int rl:1; ++ unsigned int l4_prot:2; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int prs:2; ++ unsigned int kv:1; ++ unsigned int rd:1; ++ unsigned int dscp:6; ++ unsigned int fp:1; ++ unsigned int pri:3; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int psidx:4; ++ unsigned int reserved:2; ++#else ++ unsigned int reserved:2; ++ unsigned int psidx:4; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int pri:3; ++ unsigned int fp:1; ++ unsigned int dscp:6; ++ unsigned int rd:1; ++ unsigned int kv:1; ++ unsigned int prs:2; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int l4_prot:2; ++ unsigned int rl:1; ++ unsigned int ag:2; ++ unsigned int sws:1; ++ unsigned int s:1; ++ unsigned int fw:1; ++#endif ++ ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int unused:16; ++ unsigned int mac4732:16; ++#else ++ unsigned int mac4732:16; ++ unsigned int unused:16; ++#endif ++ unsigned int mac3100; ++ ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int lp:1; ++ unsigned int fr:1; ++ unsigned int pm:4; ++ unsigned int sv:1; ++ unsigned int svid:12; ++ unsigned int cv:1; ++ unsigned int cvid:12; ++#else ++ unsigned int cvid:12; ++ unsigned int cv:1; ++ unsigned int svid:12; ++ unsigned int sv:1; ++ unsigned int pm:4; ++ unsigned int fr:1; ++ unsigned int lp:1; ++#endif ++ unsigned int sip; ++ unsigned int dip; ++ unsigned short sport; ++ unsigned short dport; ++ unsigned int natsip; ++ unsigned int natdip; ++ unsigned short natsport; ++ unsigned short natdport; ++ SPPE_LIMIT limit; ++ unsigned int pkt_cnt; ++} SPPE_FLOW_TWICE_NAT; ++ ++/* ++ * SPPE_CMD_FLOW_MULTICAST_IPV4 ++ * type = 0, as = 0 or 3 ++ */ ++typedef struct _sppe_flow_multicast_ipv4 { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int fw:1; ++ unsigned int s:1; ++ unsigned int sws:1; ++ unsigned int ag:2; ++ unsigned int rl:1; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int prs:2; ++ unsigned int kv:1; ++ unsigned int rd:1; ++ unsigned int dscp:6; ++ unsigned int fp:1; ++ unsigned int pri:3; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int bridge:1; ++ unsigned int reserved:7; ++#else ++ unsigned int reserved:7; ++ unsigned int bridge:1; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int pri:3; ++ unsigned int fp:1; ++ unsigned int dscp:6; ++ unsigned int rd:1; ++ unsigned int kv:1; ++ unsigned int prs:2; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int rl:1; ++ unsigned int ag:2; ++ unsigned int sws:1; ++ unsigned int s:1; ++ unsigned int fw:1; ++#endif ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int unused:16; ++ unsigned int mac4732:16; ++#else ++ unsigned int mac4732:16; ++ unsigned int unused:16; ++#endif ++ unsigned int mac3100; ++ ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int lp:1; ++ unsigned int fr:1; ++ unsigned int pm:4; ++ unsigned int sv:1; ++ unsigned int svid:12; ++ unsigned int cv:1; ++ unsigned int cvid:12; ++#else ++ unsigned int cvid:12; ++ unsigned int cv:1; ++ unsigned int svid:12; ++ unsigned int sv:1; ++ unsigned int pm:4; ++ unsigned int fr:1; ++ unsigned int lp:1; ++#endif ++ ++ unsigned int sip; ++ unsigned int dip; ++ SPPE_LIMIT limit; ++ unsigned int pkt_cnt; ++} SPPE_FLOW_MCAST_IPV4; ++ ++/* ++ * SPPE_CMD_FLOW_MULTICAST_IPV6 ++ * type = 1, as = 0 or 3 ++ */ ++typedef struct _sppe_flow_multicast_ipv6 { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int fw:1; ++ unsigned int s:1; ++ unsigned int sws:1; ++ unsigned int ag:2; ++ unsigned int rl:1; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int prs:2; ++ unsigned int kv:1; ++ unsigned int rd:1; ++ unsigned int dscp:6; ++ unsigned int fp:1; ++ unsigned int pri:3; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int bridge:1; ++ unsigned int reserved:7; ++#else ++ unsigned int reserved:7; ++ unsigned int bridge:1; ++ unsigned int max_len:2; /* Max. length select */ ++ unsigned int pri:3; ++ unsigned int fp:1; ++ unsigned int dscp:6; ++ unsigned int rd:1; ++ unsigned int kv:1; ++ unsigned int prs:2; ++ unsigned int l2s:2; /* L2 select */ ++ unsigned int rl:1; ++ unsigned int ag:2; ++ unsigned int sws:1; ++ unsigned int s:1; ++ unsigned int fw:1; ++#endif ++ ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int unused:16; ++ unsigned int mac4732:16; ++#else ++ unsigned int mac4732:16; ++ unsigned int unused:16; ++#endif ++ unsigned int mac3100; ++ ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int lp:1; ++ unsigned int fr:1; ++ unsigned int pm:4; ++ unsigned int sv:1; ++ unsigned int svid:12; ++ unsigned int cv:1; ++ unsigned int cvid:12; ++#else ++ unsigned int cvid:12; ++ unsigned int cv:1; ++ unsigned int svid:12; ++ unsigned int sv:1; ++ unsigned int pm:4; ++ unsigned int fr:1; ++ unsigned int lp:1; ++#endif ++ ++ unsigned int sip[4]; ++ unsigned int dip[4]; ++ SPPE_LIMIT limit; ++ unsigned int pkt_cnt; ++} SPPE_FLOW_MCAST_IPV6; ++ ++/* ++ * SPPE_CMD_FLOW_LAYER_TWO ++ * type = 2 ++ */ ++typedef struct _sppe_flow_bridge_l2 { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int fw:1; ++ unsigned int s:1; ++ unsigned int sws:1; ++ unsigned int ag:2; ++ unsigned int rl:1; ++ unsigned int l2_prot:2; ++ unsigned int kv:1; ++ unsigned int fp:1; ++ unsigned int pri:3; ++ unsigned int psidx:4; ++ unsigned int reserved:15; ++#else ++ unsigned int reserved:15; ++ unsigned int psidx:4; ++ unsigned int pri:3; ++ unsigned int fp:1; ++ unsigned int kv:1; ++ unsigned int l2_prot:2; ++ unsigned int rl:1; ++ unsigned int ag:2; ++ unsigned int sws:1; ++ unsigned int s:1; ++ unsigned int fw:1; ++#endif ++ ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int lp:1; ++ unsigned int fr:1; ++ unsigned int pm:4; ++ unsigned int sv:1; ++ unsigned int svid:12; ++ unsigned int cv:1; ++ unsigned int cvid:12; ++#else ++ unsigned int cvid:12; ++ unsigned int cv:1; ++ unsigned int svid:12; ++ unsigned int sv:1; ++ unsigned int pm:4; ++ unsigned int fr:1; ++ unsigned int lp:1; ++#endif ++ ++ unsigned short smac[3]; ++ unsigned short dmac[3]; ++ ++ SPPE_LIMIT limit; ++ unsigned int pkt_cnt; ++} SPPE_FLOW_BRIDGE_L2; ++ ++typedef struct _sppe_arl { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int vid:12; ++ unsigned int pmap:5; ++ unsigned int age:3; ++ unsigned int mymac:1; ++ unsigned int filter:1; ++ unsigned int reserved:10; ++#else ++ unsigned int reserved:10; ++ unsigned int filter:1; ++ unsigned int mymac:1; ++ unsigned int age:3; ++ unsigned int pmap:5; ++ unsigned int vid:12; ++#endif ++ unsigned char mac[6]; ++} SPPE_ARL; ++ ++typedef struct _sppe_init { ++ unsigned int flow_pre_match_paddr; ++ unsigned int flow_pre_match_vaddr; ++ unsigned int flow_body_paddr; ++ unsigned int flow_body_vaddr; ++ unsigned int flow_ext_paddr; ++ unsigned int flow_ext_vaddr; ++ unsigned int flow_size; ++ unsigned int arp_pre_match_paddr; ++ unsigned int arp_pre_match_vaddr; ++ unsigned int arp_body_paddr; ++ unsigned int arp_body_vaddr; ++ unsigned int arp_size; ++ unsigned int ipv6_napt; ++} SPPE_INIT; ++ ++typedef struct _sppe_param_t { ++ SPPE_CMD cmd; ++ SPPE_OP op; ++ ++ union { ++ struct { ++ unsigned char major; ++ unsigned char minor; ++ unsigned char very_minor; ++ unsigned char pre; ++ } sppe_version; ++ ++ SPPE_BOOL sppe_enable; ++ unsigned int sppe_lanip; ++ ++ struct { ++ unsigned int index; ++ unsigned int ip; ++ unsigned int session_id; ++ } sppe_wanip; ++ ++ struct { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int index:2; ++ unsigned int to:4; ++ unsigned int sv:1; ++ unsigned int stag_vid:12; ++ unsigned int cv:1; ++ unsigned int ctag_vid:12; ++#else ++ unsigned int ctag_vid:12; ++ unsigned int cv:1; ++ unsigned int stag_vid:12; ++ unsigned int sv:1; ++ unsigned int to:4; ++ unsigned int index:2; ++#endif ++ unsigned char mac[6]; /* MAC address */ ++ } sppe_prda; ++ ++ struct { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int interval:2; ++ unsigned int mfactor:1; ++ unsigned int ununsed:29; ++#else ++ unsigned int ununsed:29; ++ unsigned int mfactor:1; ++ unsigned int interval:2; ++#endif ++ } sppe_rlcfg; ++ ++ struct { ++ unsigned int index; ++ SPPE_PPPOE_RELAY rule; ++ } sppe_pppoe_relay; ++ ++ struct { ++ unsigned int index; ++ SPPE_BRIDGE rule; ++ } sppe_bridge; ++ ++ struct { ++ unsigned int index; ++ SPPE_ACL rule; ++ } sppe_acl; ++ ++ struct { ++ unsigned int index; ++ SPPE_ROUTE rule; ++ } sppe_route; ++#if 0 ++ struct { ++ unsigned int index; ++ SPPE_VSERVER rule; ++ } sppe_vserver; ++#else ++ struct { ++ unsigned int index; ++ SPPE_SNAT rule; ++ } sppe_snat; ++ ++ struct { ++ unsigned int index; ++ SPPE_DNAT rule; ++ } sppe_dnat; ++#endif ++ struct { ++ unsigned int index; ++ SPPE_GLOBAL_RATE_LIMIT rule; ++ } sppe_grl; ++ ++ struct { ++ unsigned char unit; ++ unsigned char arp; ++ unsigned char bridge; ++ unsigned char tcp; ++ unsigned char udp; ++ unsigned char pptp; ++ unsigned char other; ++ } sppe_agingout; ++ ++ struct { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int index:2; ++ unsigned int reserved:20; ++ unsigned int max:10; ++#else ++ unsigned int max:10; ++ unsigned int reserved:20; ++ unsigned int index:2; ++#endif ++ } sppe_max_length; ++ ++ struct { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int v6:1; ++ unsigned int s:1; ++ unsigned int r:1; ++ unsigned int fr:1; ++ unsigned int to:4; ++ unsigned int unused:24; ++#else ++ unsigned int unused:24; ++ unsigned int to:4; ++ unsigned int fr:1; ++ unsigned int r:1; ++ unsigned int s:1; ++ unsigned int v6:1; ++#endif ++ ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int sv:1; ++ unsigned int stag_vid:12; ++ unsigned int cv:1; ++ unsigned int ctag_vid:12; ++ unsigned int unused_1:6; ++#else ++ unsigned int unused_1:6; ++ unsigned int ctag_vid:12; ++ unsigned int cv:1; ++ unsigned int stag_vid:12; ++ unsigned int sv:1; ++#endif ++ unsigned int ip[4]; ++ unsigned char mac[6]; ++ } sppe_arp; ++ ++ SPPE_ARL sppe_arl; ++ ++ struct { ++ unsigned int sid; ++ unsigned int index; ++ } sppe_pppoe_sid; ++ ++ SPPE_FLOW_BRIDGE_IPV4 flow_bridge_ipv4; ++ SPPE_FLOW_BRIDGE_IPV6 flow_bridge_ipv6; ++ SPPE_FLOW_ROUTE_IPV4 flow_route_ipv4; ++ SPPE_FLOW_ROUTE_IPV6 flow_route_ipv6; ++ SPPE_FLOW_NAT_IPV4 flow_nat_ipv4; ++ SPPE_FLOW_NAT_IPV6 flow_nat_ipv6; ++ SPPE_FLOW_TWICE_NAT flow_twice_nat; ++ SPPE_FLOW_MCAST_IPV4 flow_mcast_ipv4; ++ SPPE_FLOW_MCAST_IPV6 flow_mcast_ipv6; ++ SPPE_FLOW_BRIDGE_L2 flow_bridge_l2; ++ ++ struct { ++ SPPE_DUMP_TYPE type; ++ unsigned short key; ++ unsigned short way; ++ unsigned int raw[23]; ++ } sppe_dump; ++ ++ unsigned int sppe_sna_th; ++ ++ struct { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int enable:1; ++ unsigned int lan:6; ++ unsigned int wan:6; ++ unsigned int reserved:19; ++#else ++ unsigned int reserved:19; ++ unsigned int wan:6; ++ unsigned int lan:6; ++ unsigned int enable:1; ++#endif ++ } sppe_chgdscp; ++ ++ struct { ++#ifndef CONFIG_SWITCH_BIG_ENDIAN ++ unsigned int enable:1; ++ unsigned int lan:3; ++ unsigned int wan:3; ++ unsigned int reserved:25; ++#else ++ unsigned int reserved:25; ++ unsigned int wan:3; ++ unsigned int lan:3; ++ unsigned int enable:1; ++#endif ++ } sppe_chgpri; ++ ++ struct { ++ int enable; ++ int module; ++ int level; ++ } sppe_debug; ++ ++ struct { ++ unsigned int offset; ++ unsigned int data; ++ } sppe_reg; ++ ++ struct { ++ unsigned int offset; ++ unsigned int data; ++ } sppe_sram; ++ ++ struct { ++ char enable; ++ unsigned int max; ++ unsigned int min; ++ char drop_red; ++ char pass_green; ++ } sppe_rl_flow; ++ ++ struct { ++ char enable; ++ unsigned int max; ++ unsigned int min; ++ char drop_red; ++ char pass_green; ++ } sppe_rl_rule; ++ ++ struct { ++ unsigned int index; ++ unsigned short start; ++ unsigned short end; ++ SPPE_LIMIT limit; ++ } sppe_bm_flow; ++ ++ struct { ++ unsigned int index; ++ unsigned int pkt_cnt; ++ unsigned int byte_cnt; ++ } sppe_accounting_group; ++ ++ struct { ++ unsigned int pkt_cnt; ++ } sppe_drop_ipcs_err; /* IP checksum error */ ++ ++ struct { ++ unsigned int pkt_cnt; ++ } sppe_drop_rate_limit; ++ ++ struct { ++ unsigned int pkt_cnt; ++ } sppe_drop_others; ++ ++ struct { ++ unsigned int index; ++ unsigned char name[16]; ++ struct net_device *dev; ++ unsigned int vid; ++ } sppe_pci_fp_dev; ++ ++ SPPE_INIT sppe_init; ++ ++ } data; ++} SPPE_PARAM; ++ ++extern int sppe_hook_ready; ++extern int (*sppe_func_hook)(SPPE_PARAM *param); ++ ++extern int sppe_pci_fp_ready; ++extern int (*sppe_pci_fp_hook)(SPPE_PARAM *param); ++ ++#endif /* CONFIG_CNS3XXX_SPPE */ ++ ++#endif /* _SPPE_H_ */ +--- /dev/null ++++ b/include/linux/cns3xxx/switch_api.h +@@ -0,0 +1,366 @@ ++/******************************************************************************* ++ * ++ * Copyright (c) 2008 Cavium Networks ++ * ++ * 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. ++ * ++ * The full GNU General Public License is included in this distribution in the ++ * file called LICENSE. ++ * ++ * Contact Information: ++ * Technology Support <tech@starsemi.com> ++ * Star Semiconductor 4F, No.1, Chin-Shan 8th St, Hsin-Chu,300 Taiwan, R.O.C ++ * ++ ********************************************************************************/ ++ ++#ifndef SWITCH_API_H_K ++#define SWITCH_API_H_K ++ ++ ++#ifndef __KERNEL__ ++typedef unsigned int u32; ++typedef unsigned short int u16; ++typedef unsigned char u8; ++typedef int s32; ++#else ++ ++#include <linux/types.h> ++ ++#endif ++ ++ ++#define CAVM_OK 0 ++#define CAVM_ERR 1 ++#define CAVM_NOT_FOUND 2 ++#define CAVM_FOUND 3 ++#define CAVM_FAIL -1 // use minus ++ ++#define MAC_PORT0 0 ++#define MAC_PORT1 1 ++#define MAC_PORT2 2 ++#define CPU_PORT 3 ++ ++typedef enum ++{ ++ ++ ++ CNS3XXX_ARL_TABLE_LOOKUP, ++ CNS3XXX_ARL_TABLE_ADD, ++ CNS3XXX_ARL_TABLE_DEL, ++ CNS3XXX_ARL_TABLE_SEARCH, ++ CNS3XXX_ARL_TABLE_SEARCH_AGAIN, ++ CNS3XXX_ARL_IS_TABLE_END, ++ CNS3XXX_ARL_TABLE_FLUSH, ++ ++ CNS3XXX_VLAN_TABLE_LOOKUP, ++ CNS3XXX_VLAN_TABLE_ADD, ++ CNS3XXX_VLAN_TABLE_DEL, ++ CNS3XXX_VLAN_TABLE_READ, ++ ++ CNS3XXX_SKEW_SET, ++ CNS3XXX_SKEW_GET, ++ ++ CNS3XXX_BRIDGE_SET, ++ CNS3XXX_BRIDGE_GET, ++ ++ CNS3XXX_PORT_NEIGHBOR_SET, ++ CNS3XXX_PORT_NEIGHBOR_GET, ++ ++ CNS3XXX_HOL_PREVENT_SET, ++ CNS3XXX_HOL_PREVENT_GET, ++ ++ CNS3XXX_TC_SET, // traffic class, for 1, 2, 4, traffic class ++ CNS3XXX_TC_GET, ++ ++ CNS3XXX_PRI_CTRL_SET, ++ CNS3XXX_PRI_CTRL_GET, ++ ++ CNS3XXX_DMA_RING_CTRL_SET, ++ CNS3XXX_DMA_RING_CTRL_GET, ++ ++ CNS3XXX_PRI_IP_DSCP_SET, ++ CNS3XXX_PRI_IP_DSCP_GET, ++ ++ CNS3XXX_ETYPE_SET, ++ CNS3XXX_ETYPE_GET, ++ ++ CNS3XXX_UDP_RANGE_SET, ++ CNS3XXX_UDP_RANGE_GET, ++ ++ CNS3XXX_ARP_REQUEST_SET, ++ CNS3XXX_ARP_REQUEST_GET, ++ ++ CNS3XXX_RATE_LIMIT_SET, ++ CNS3XXX_RATE_LIMIT_GET, ++ ++ CNS3XXX_QUEUE_WEIGHT_SET, ++ CNS3XXX_QUEUE_WEIGHT_GET, ++ ++ CNS3XXX_FC_RLS_SET, ++ CNS3XXX_FC_RLS_GET, ++ ++ CNS3XXX_FC_SET_SET, ++ CNS3XXX_FC_SET_GET, ++ ++ CNS3XXX_SARL_RLS_SET, ++ CNS3XXX_SARL_RLS_GET, ++ ++ CNS3XXX_SARL_SET_SET, ++ CNS3XXX_SARL_SET_GET, ++ ++ CNS3XXX_SARL_OQ_SET, ++ CNS3XXX_SARL_OQ_GET, ++ ++ CNS3XXX_SARL_ENABLE_SET, ++ CNS3XXX_SARL_ENABLE_GET, ++ ++ CNS3XXX_FC_SET, ++ CNS3XXX_FC_GET, ++ ++ CNS3XXX_IVL_SET, ++ CNS3XXX_IVL_GET, ++ ++ CNS3XXX_WAN_PORT_SET, ++ CNS3XXX_WAN_PORT_GET, ++ ++ CNS3XXX_PVID_GET, ++ CNS3XXX_PVID_SET, ++ ++ CNS3XXX_QA_GET, // queue allocate ++ CNS3XXX_QA_SET, ++ ++ CNS3XXX_PACKET_MAX_LEN_GET, // set maximun frame length. ++ CNS3XXX_PACKET_MAX_LEN_SET, ++ ++ CNS3XXX_BCM53115M_REG_READ, ++ CNS3XXX_BCM53115M_REG_WRITE, ++ ++ CNS3XXX_RXRING_STATUS, ++ CNS3XXX_TXRING_STATUS, ++ ++ CNS3XXX_DUMP_MIB_COUNTER, ++ ++ CNS3XXX_REG_READ, ++ CNS3XXX_REG_WRITE, ++ ++}CNS3XXXIoctlCmd; ++ ++typedef struct ++{ ++ u8 vlan_index; ++ u8 valid; ++ u16 vid; ++ u8 wan_side; ++ u8 etag_pmap; ++ u8 mb_pmap; ++ //u8 my_mac[6]; ++ u8 *my_mac; ++}VLANTableEntry; // for vlan table function ++ ++typedef struct ++{ ++ u16 vid; ++ u8 pmap; ++ //u8 mac[6]; ++ u8 *mac; ++ u8 age_field; ++ u8 vlan_mac; ++ u8 filter; ++}ARLTableEntry; // for arl table function ++ ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ ARLTableEntry entry; ++}CNS3XXXARLTableEntry; // for ioctl arl ... ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ VLANTableEntry entry; ++}CNS3XXXVLANTableEntry; // for ioctl VLAN table ... ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ u8 enable; ++}CNS3XXXHOLPreventControl; ++ ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned char which_port; // 0, 1, 2, 3 (cpu port) ++ unsigned char type; // 0: C-Neighbor, 1: S-Neighbor ++}CNS3XXXPortNeighborControl; ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned char type; // 0: C-Component, 1: S-Component ++}CNS3XXXBridgeControl; ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned char tc; // traffic class, for 1, 2, 4, traffic class ++}CNS3XXXTrafficClassControl; ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned char which_port; // 0, 1, 2, 3 (cpu port) ++ unsigned int val; ++ unsigned char port_pri; ++ unsigned char udp_pri_en; ++ unsigned char dscp_pri_en; ++ unsigned char vlan_pri_en; ++ unsigned char ether_pri_en; ++}CNS3XXXPriCtrlControl; ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned char ts_double_ring_en; ++ unsigned char fs_double_ring_en; ++ unsigned char fs_pkt_allocate; ++}CNS3XXXDmaRingCtrlControl; ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned int ip_dscp_num; // 0 ~ 63 ++ unsigned char pri; // 3 bits ++}CNS3XXXPriIpDscpControl; ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned int etype_num; ++ unsigned int val; ++ unsigned int pri; ++}CNS3XXXEtypeControl; ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned int udp_range_num; ++ unsigned short int port_start; ++ unsigned short int port_end; ++}CNS3XXXUdpRangeEtypeControl; ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned char val; // 0: boradcast forward, 1: redirect to the CPU ++}CNS3XXXArpRequestControl; ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned char which_port; // 0, 1, 2, 3 (port 0 extra dma) ++ unsigned char band_width; ++ unsigned char base_rate; ++ ++}CNS3XXXRateLimitEntry; // for ioctl arl ... ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned char which_port; // 0, 1, 2, 3 (port 0 extra dma) ++ unsigned char sch_mode; ++ unsigned char q0_w; ++ unsigned char q1_w; ++ unsigned char q2_w; ++ unsigned char q3_w; ++}CNS3XXXQueueWeightEntry; // for ioctl arl ... ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned int val; ++ unsigned char tc; // 0-3 ++ unsigned char gyr; // 0 (green), 1(yellow), 2(red) ++}CNS3XXXSARLEntry; // for ioctl arl ... ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned char port; // 0, 1, 2, 3 (cpu port) ++ unsigned char fc_en; // 0(rx/tx disable), 1(rx enable), 2(tx enable), 3(rx/tx enable) ++}CNS3XXXFCEntry; // for ioctl arl ... ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned char enable; // enable: 1 -> IVL, enable: 0 -> SVL ++}CNS3XXXIVLEntry; // for ioctl arl ... ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned char wan_port; ++}CNS3XXXWANPortEntry; // for ioctl arl ... ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned char which_port; ++ unsigned int pvid; ++}CNS3XXXPVIDEntry; // for ioctl arl ... ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned char qa; // queue allocate ++}CNS3XXXQAEntry; // for ioctl arl ... ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ unsigned char max_len; // maximum frame length ++}CNS3XXXMaxLenEntry; // for ioctl arl ... ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ u8 page; ++ u8 offset; ++ u32 u32_val; ++ u16 u16_val; ++ u8 u8_val; ++ u8 data_len; ++ ++}CNS3XXXBCM53115M; ++ ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ u32 mib[52]; ++ u16 mib_len; ++}CNS3XXXMIBCounter; ++ ++#if 0 ++typedef struct ++{ ++ CNS3XXXIoctlCmd cmd; ++ TXRing *tx_ring; ++ RXRing *rx_ring; ++}CNS3XXXRingStatus; ++#endif ++ ++ ++#endif +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -133,6 +133,10 @@ + + #include "net-sysfs.h" + ++#if defined (CONFIG_CNS3XXX_SPPE) ++#include <linux/cns3xxx/sppe.h> ++#endif ++ + /* Instead of increasing this, you should create a hash table. */ + #define MAX_GRO_SKBS 8 + +@@ -1944,6 +1948,197 @@ int weight_p __read_mostly = 64; + + DEFINE_PER_CPU(struct netif_rx_stats, netdev_rx_stat) = { 0, }; + ++#if defined (CONFIG_CNS3XXX_SPPE) ++static struct net_device *tun_netdev = NULL; ++ ++int sppe_pci_fp(struct sk_buff *skb) ++{ ++ SPPE_PARAM param; ++ struct iphdr *iph; ++#if defined (CONFIG_IPV6) ++ struct ipv6hdr *ipv6h; ++#endif ++ struct tcphdr *th; ++ struct udphdr *uh; ++ int pci_dev_index; ++ ++ if (!sppe_hook_ready) { ++ goto NOT_IN_FP; ++ } ++ ++ if (!sppe_pci_fp_ready) { ++ goto NOT_IN_FP; ++ } ++ ++ /* check device packet comes from, is a registed device? */ ++ memset(¶m, 0, sizeof(SPPE_PARAM)); ++ param.cmd = SPPE_CMD_PCI_FP_DEV; ++ param.op = SPPE_OP_GET; ++ param.data.sppe_pci_fp_dev.dev = skb->dev; ++ sppe_pci_fp_hook(¶m); ++ ++ pci_dev_index = param.data.sppe_pci_fp_dev.index; ++ ++ if ((-1) == pci_dev_index) { ++ goto NOT_IN_FP; ++ } ++ ++ if (!tun_netdev) { ++ tun_netdev = dev_get_by_name(&init_net, "fp"); ++ ++ if (!tun_netdev) { ++ goto NOT_IN_FP; ++ } ++ } ++ ++ /* check PPE status */ ++ memset(¶m, 0, sizeof(SPPE_PARAM)); ++ param.cmd = SPPE_CMD_ENABLE; ++ param.op = SPPE_OP_GET; ++ ++ if (sppe_func_hook(¶m)) { ++ printk("<0><%s> fail to get PPE status!!\n", __FUNCTION__); ++ goto NOT_IN_FP; ++ } ++ ++ if (!param.data.sppe_enable) { ++ goto NOT_IN_FP; ++ } ++ ++ memset(¶m, 0, sizeof(SPPE_PARAM)); ++ ++ switch (htons(skb->protocol)) { ++ case ETH_P_IP: ++ iph = (struct iphdr *)skb->data; ++ ++ if (5 != iph->ihl) { goto NOT_IN_FP; } ++ ++ if (iph->frag_off & 0x20) { goto NOT_IN_FP; } ++ ++ param.cmd = SPPE_CMD_FLOW_NAT_IPV4; ++ param.op = SPPE_OP_GET; ++ ++ param.data.flow_nat_ipv4.sip = ntohl(iph->saddr); ++ param.data.flow_nat_ipv4.dip = ntohl(iph->daddr); ++ ++ switch (iph->protocol) { ++ case IPPROTO_TCP: ++ th = (struct tcphdr *) ((int *)iph + 5); /* IP header length is 20 */ ++ ++ if ((th->syn) || (th->fin) || (th->rst)) { goto NOT_IN_FP; } ++ ++ param.data.flow_nat_ipv4.l4_prot = SPPE_PROT_TCP; ++ param.data.flow_nat_ipv4.l4.port.src = ntohs(th->source); ++ param.data.flow_nat_ipv4.l4.port.dst = ntohs(th->dest); ++ break; ++ case IPPROTO_UDP: ++ uh = (struct udphdr *) ((int *)iph + 5); /* IP header length is 20 */ ++ param.data.flow_nat_ipv4.l4_prot = SPPE_PROT_UDP; ++ param.data.flow_nat_ipv4.l4.port.src = ntohs(uh->source); ++ param.data.flow_nat_ipv4.l4.port.dst = ntohs(uh->dest); ++ break; ++ default: ++ goto NOT_IN_FP; ++ } ++ ++ if (SPPE_RESULT_SUCCESS != sppe_func_hook(¶m)) { ++ goto NOT_IN_FP; ++ } else { ++ struct ethhdr *eth; ++ ++ eth = (struct ethhdr *)skb->mac_header; ++ ++ memset(¶m, 0, sizeof(SPPE_PARAM)); ++ param.cmd = SPPE_CMD_ARP; ++ param.op = SPPE_OP_SET; ++ param.data.sppe_arp.s = 1; ++ param.data.sppe_arp.ip[0] = iph->saddr; ++ param.data.sppe_arp.mac[0] = eth->h_source[0]; ++ param.data.sppe_arp.mac[1] = eth->h_source[1]; ++ param.data.sppe_arp.mac[2] = eth->h_source[2]; ++ param.data.sppe_arp.mac[3] = eth->h_source[3]; ++ param.data.sppe_arp.mac[4] = eth->h_source[4]; ++ param.data.sppe_arp.mac[5] = eth->h_source[5]; ++ param.data.sppe_arp.unused_1 = pci_dev_index; ++ ++ if (SPPE_RESULT_SUCCESS != sppe_func_hook(¶m)) { ++ printk("add ARP fail\n"); ++ #if 0 ++ } else { ++ param.data.sppe_arp.unused_1 = 0xf; ++ param.op = SPPE_OP_GET; ++ if (SPPE_RESULT_SUCCESS != sppe_func_hook(¶m)) { ++ printk("read ARP fail\n"); ++ } else { ++ printk("param.data.sppe_arp.unused_1 %d\n", param.data.sppe_arp.unused_1); ++ } ++ #endif ++ } ++ } ++ break; /* case ETH_P_IP: */ ++#if defined (CONFIG_IPV6) ++ case ETH_P_IPV6: ++ ipv6h = (struct ipv6hdr *)skb->data; ++ switch (ipv6h->nexthdr) { ++ case IPPROTO_TCP: ++ th = (struct tcphdr *) ((int *)ipv6h + 10); /* IPv6 header length is 40 bytes */ ++ ++ if ((th->syn) || (th->fin) || (th->rst)) { goto NOT_IN_FP; } ++ ++ param.data.flow_route_ipv6.l4_prot = SPPE_PROT_TCP; ++ param.data.flow_route_ipv6.l4.port.src = ntohs(th->source); ++ param.data.flow_route_ipv6.l4.port.dst = ntohs(th->dest); ++ param.data.flow_route_ipv6.l4_prot = SPPE_PROT_TCP; ++ break; ++ case IPPROTO_UDP: ++ uh = (struct udphdr *) ((int *)ipv6h + 10); /* IPv6 header length is 40 byte */ ++ param.data.flow_route_ipv6.l4_prot = SPPE_PROT_UDP; ++ param.data.flow_route_ipv6.l4.port.src = ntohs(uh->source); ++ param.data.flow_route_ipv6.l4.port.dst = ntohs(uh->dest); ++ break; ++ default: ++ goto NOT_IN_FP; ++ } ++ ++ param.data.flow_route_ipv6.sip[0] = ntohl(ipv6h->saddr.s6_addr32[0]); ++ param.data.flow_route_ipv6.sip[1] = ntohl(ipv6h->saddr.s6_addr32[1]); ++ param.data.flow_route_ipv6.sip[2] = ntohl(ipv6h->saddr.s6_addr32[2]); ++ param.data.flow_route_ipv6.sip[3] = ntohl(ipv6h->saddr.s6_addr32[3]); ++ param.data.flow_route_ipv6.dip[0] = ntohl(ipv6h->daddr.s6_addr32[0]); ++ param.data.flow_route_ipv6.dip[1] = ntohl(ipv6h->daddr.s6_addr32[1]); ++ param.data.flow_route_ipv6.dip[2] = ntohl(ipv6h->daddr.s6_addr32[2]); ++ param.data.flow_route_ipv6.dip[3] = ntohl(ipv6h->daddr.s6_addr32[3]); ++ ++ param.cmd = SPPE_CMD_FLOW_ROUTE_IPV6; ++ param.op = SPPE_OP_GET; ++ ++ if (SPPE_RESULT_SUCCESS != sppe_func_hook(¶m)) { ++ goto NOT_IN_FP; ++ } ++ ++ break; /* case ETH_P_IPV6: */ ++#endif ++ case ETH_P_PPP_SES: ++ break; ++ default: /* unsupport protocol */ ++ goto NOT_IN_FP; ++ } ++ /* Update counter */ ++ skb->dev = tun_netdev; ++ skb->ip_summed = CHECKSUM_NONE; ++ skb_push(skb, ETH_HLEN); ++ ++ dev_queue_xmit(skb); ++ ++return 0; ++ ++NOT_IN_FP: ++ return (-1); ++} ++#endif ++ ++ ++ + + /** + * netif_rx - post buffer to the network code +@@ -1965,6 +2160,12 @@ int netif_rx(struct sk_buff *skb) + struct softnet_data *queue; + unsigned long flags; + ++#if defined (CONFIG_CNS3XXX_SPPE) ++ if (0 == sppe_pci_fp(skb)) { ++ return NET_RX_SUCCESS; ++ } ++#endif ++ + /* if netpoll wants it, pretend we never saw it */ + if (netpoll_rx(skb)) + return NET_RX_DROP; +@@ -2259,6 +2460,12 @@ int netif_receive_skb(struct sk_buff *sk + if (!skb->tstamp.tv64) + net_timestamp(skb); + ++#if defined (CONFIG_CNS3XXX_SPPE) ++ if (0 == sppe_pci_fp(skb)) { ++ return NET_RX_SUCCESS; ++ } ++#endif ++ + if (skb->vlan_tci && vlan_hwaccel_do_receive(skb)) + return NET_RX_SUCCESS; + +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -42,6 +42,9 @@ + #include <net/netfilter/nf_conntrack_ecache.h> + #include <net/netfilter/nf_nat.h> + #include <net/netfilter/nf_nat_core.h> ++#if defined (CONFIG_CNS3XXX_SPPE) ++#include <linux/cns3xxx/sppe.h> ++#endif + + #define NF_CONNTRACK_VERSION "0.5.0" + +@@ -275,6 +278,92 @@ void nf_ct_insert_dying_list(struct nf_c + } + EXPORT_SYMBOL_GPL(nf_ct_insert_dying_list); + ++#if defined (CONFIG_CNS3XXX_SPPE) ++static int sppe_flow_del(struct nf_conn *ct) ++{ ++ if (sppe_hook_ready) { ++ SPPE_PARAM param; ++ ++ struct nf_conntrack_tuple *orig, *reply; ++ ++ orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; ++ reply = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; ++ ++ if (PF_INET == orig->src.l3num) { ++ param.cmd = SPPE_CMD_FLOW_NAT_IPV4; ++ } else if (PF_INET6 == orig->src.l3num) { ++ param.cmd = SPPE_CMD_FLOW_ROUTE_IPV6; ++ } else { ++ goto SPPE_FLOW_DEL_FINI; ++ } ++ ++ if (IPPROTO_TCP == orig->dst.protonum) { ++ param.data.flow_nat_ipv4.l4_prot = SPPE_PROT_TCP; ++ } else if (IPPROTO_UDP == orig->dst.protonum) { ++ param.data.flow_nat_ipv4.l4_prot = SPPE_PROT_UDP; ++ } else if (IPPROTO_GRE == orig->dst.protonum) { ++ param.data.flow_nat_ipv4.l4_prot = SPPE_PROT_PPTP_GRE; ++ } else { ++ goto SPPE_FLOW_DEL_FINI; ++ } ++ ++ param.op = SPPE_OP_DELETE_OUTDATED; ++ ++ param.data.flow_nat_ipv4.fw = 0; ++ if (SPPE_CMD_FLOW_ROUTE_IPV6 == param.cmd) { ++ param.data.flow_route_ipv6.sip[0] = htonl(orig->src.u3.ip6[0]); ++ param.data.flow_route_ipv6.sip[1] = htonl(orig->src.u3.ip6[1]); ++ param.data.flow_route_ipv6.sip[2] = htonl(orig->src.u3.ip6[2]); ++ param.data.flow_route_ipv6.sip[3] = htonl(orig->src.u3.ip6[3]); ++ param.data.flow_route_ipv6.dip[0] = htonl(orig->dst.u3.ip6[0]); ++ param.data.flow_route_ipv6.dip[1] = htonl(orig->dst.u3.ip6[1]); ++ param.data.flow_route_ipv6.dip[2] = htonl(orig->dst.u3.ip6[2]); ++ param.data.flow_route_ipv6.dip[3] = htonl(orig->dst.u3.ip6[3]); ++ param.data.flow_route_ipv6.l4.port.src = htons(orig->src.u.tcp.port); ++ param.data.flow_route_ipv6.l4.port.dst = htons(orig->dst.u.tcp.port); ++ } else { ++ param.data.flow_nat_ipv4.sip = htonl(orig->src.u3.ip); ++ param.data.flow_nat_ipv4.dip = htonl(orig->dst.u3.ip); ++ param.data.flow_nat_ipv4.l4.port.src = htons(orig->src.u.tcp.port); ++ param.data.flow_nat_ipv4.l4.port.dst = htons(orig->dst.u.tcp.port); ++ } ++ ++ if (SPPE_RESULT_FAIL == sppe_func_hook(¶m)) { ++ return (-1); ++ } ++ ++ param.data.flow_nat_ipv4.fw = 1; ++ ++ if (SPPE_CMD_FLOW_ROUTE_IPV6 == param.cmd) { ++ param.data.flow_route_ipv6.sip[0] = htonl(reply->src.u3.ip6[0]); ++ param.data.flow_route_ipv6.sip[1] = htonl(reply->src.u3.ip6[1]); ++ param.data.flow_route_ipv6.sip[2] = htonl(reply->src.u3.ip6[2]); ++ param.data.flow_route_ipv6.sip[3] = htonl(reply->src.u3.ip6[3]); ++ param.data.flow_route_ipv6.dip[0] = htonl(reply->dst.u3.ip6[0]); ++ param.data.flow_route_ipv6.dip[1] = htonl(reply->dst.u3.ip6[1]); ++ param.data.flow_route_ipv6.dip[2] = htonl(reply->dst.u3.ip6[2]); ++ param.data.flow_route_ipv6.dip[3] = htonl(reply->dst.u3.ip6[3]); ++ ++ param.data.flow_route_ipv6.l4.port.src = htons(reply->src.u.tcp.port); ++ param.data.flow_route_ipv6.l4.port.dst = htons(reply->dst.u.tcp.port); ++ } else { ++ param.data.flow_nat_ipv4.sip = htonl(reply->src.u3.ip); ++ param.data.flow_nat_ipv4.dip = htonl(reply->dst.u3.ip); ++ param.data.flow_nat_ipv4.l4.port.src = htons(reply->src.u.tcp.port); ++ param.data.flow_nat_ipv4.l4.port.dst = htons(reply->dst.u.tcp.port); ++ } ++ ++ if (SPPE_RESULT_FAIL == sppe_func_hook(¶m)) { ++ return (-1); ++ } ++ } ++ ++SPPE_FLOW_DEL_FINI: ++ return 0; ++} ++#endif ++ ++ + static void death_by_timeout(unsigned long ul_conntrack) + { + struct nf_conn *ct = (void *)ul_conntrack; +@@ -289,6 +378,16 @@ static void death_by_timeout(unsigned lo + set_bit(IPS_DYING_BIT, &ct->status); + nf_ct_delete_from_lists(ct); + nf_ct_put(ct); ++ ++#if defined (CONFIG_CNS3XXX_SPPE) ++ if (sppe_flow_del(ct)) { ++ #if 0 ++ ct->timeout.expires = jiffies + (120*HZ); ++ add_timer(&ct->timeout); ++ #endif ++ } ++#endif ++ + } + + /* +--- a/net/netfilter/nf_conntrack_proto_gre.c ++++ b/net/netfilter/nf_conntrack_proto_gre.c +@@ -40,6 +40,10 @@ + #include <linux/netfilter/nf_conntrack_proto_gre.h> + #include <linux/netfilter/nf_conntrack_pptp.h> + ++#if defined (CONFIG_CNS3XXX_SPPE) ++#include <linux/cns3xxx/sppe.h> ++#endif ++ + #define GRE_TIMEOUT (30 * HZ) + #define GRE_STREAM_TIMEOUT (180 * HZ) + +@@ -226,6 +230,57 @@ static int gre_print_conntrack(struct se + (ct->proto.gre.stream_timeout / HZ)); + } + ++#if defined (CONFIG_CNS3XXX_SPPE) ++static int sppe_gre_flow_add(struct nf_conn *ct) ++{ ++ SPPE_PARAM param; ++ struct nf_conntrack_tuple *orig, *reply; ++ ++ if (0 == sppe_hook_ready) { ++ return 0; ++ } ++ ++ memset(¶m, 0, sizeof(SPPE_PARAM)); ++ ++ orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; ++ reply = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; ++ ++ param.cmd = SPPE_CMD_FLOW_NAT_IPV4; ++ param.op = SPPE_OP_SET; ++ ++ param.data.flow_nat_ipv4.fw = 0; ++ param.data.flow_nat_ipv4.sip = htonl(orig->src.u3.ip); ++ param.data.flow_nat_ipv4.dip = htonl(orig->dst.u3.ip); ++ ++ param.data.flow_nat_ipv4.l4_prot = SPPE_PROT_PPTP_GRE; ++ param.data.flow_nat_ipv4.l4.gre.call_id = htons(orig->dst.u.gre.key); ++ ++ param.data.flow_nat_ipv4.nat_ip = htonl(reply->dst.u3.ip); ++ param.data.flow_nat_ipv4.l4.gre.nat_call_id = htons(reply->src.u.gre.key); ++ ++ if (sppe_func_hook(¶m)) { ++ printk("<0><%s> fail to add IPv4 from-LAN flow!!\n", __FUNCTION__); ++ } ++ ++ param.data.flow_nat_ipv4.fw = 1; ++ ++ param.data.flow_nat_ipv4.sip = htonl(reply->src.u3.ip); ++ param.data.flow_nat_ipv4.dip = htonl(reply->dst.u3.ip); ++ param.data.flow_nat_ipv4.l4.gre.call_id = htons(reply->dst.u.gre.key); ++ ++ param.data.flow_nat_ipv4.nat_ip = htonl(orig->src.u3.ip); ++ param.data.flow_nat_ipv4.l4.gre.nat_call_id = htons(orig->src.u.gre.key); ++ ++ if (sppe_func_hook(¶m)) { ++ printk("<0><%s> fail to add IPv4 from-WAN flow!!\n", __FUNCTION__); ++ } ++ ++ return 0; ++} ++#endif ++ ++ ++ + /* Returns verdict for packet, and may modify conntrack */ + static int gre_packet(struct nf_conn *ct, + const struct sk_buff *skb, +@@ -242,6 +297,10 @@ static int gre_packet(struct nf_conn *ct + /* Also, more likely to be important, and not a probe. */ + set_bit(IPS_ASSURED_BIT, &ct->status); + nf_conntrack_event_cache(IPCT_STATUS, ct); ++#if defined (CONFIG_CNS3XXX_SPPE) ++ sppe_gre_flow_add(ct); ++#endif ++ + } else + nf_ct_refresh_acct(ct, ctinfo, skb, + ct->proto.gre.timeout); +--- a/net/netfilter/nf_conntrack_proto_tcp.c ++++ b/net/netfilter/nf_conntrack_proto_tcp.c +@@ -29,6 +29,10 @@ + #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> + #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> + ++#if defined (CONFIG_CNS3XXX_SPPE) ++#include <linux/cns3xxx/sppe.h> ++#endif ++ + /* "Be conservative in what you do, + be liberal in what you accept from others." + If it's non-zero, we mark only out of window RST segments as INVALID. */ +@@ -814,6 +818,141 @@ static int tcp_error(struct net *net, + return NF_ACCEPT; + } + ++#if defined (CONFIG_CNS3XXX_SPPE) ++static int sppe_tcp_flow_add_ipv4(struct nf_conn *ct) ++{ ++ SPPE_PARAM param; ++ struct nf_conntrack_tuple *orig, *reply; ++ ++ orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; ++ reply = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; ++ ++#if defined (CONFIG_NF_CONNTRACK_PPTP) ++ if (1723 == htons(orig->dst.u.tcp.port)) { ++ /* PPTP Control Protocol, PPTP GRE tunneling need this kind of packet */ ++ return 0; ++ } ++#endif ++#if defined (CONFIG_NF_CONNTRACK_FTP) ++ if (21 == htons(orig->dst.u.tcp.port)) { ++ /* PPTP Control Protocol, PPTP GRE tunneling need this kind of packet */ ++ return 0; ++ } ++#endif ++ ++ memset(¶m, 0, sizeof(SPPE_PARAM)); ++ ++ param.cmd = SPPE_CMD_FLOW_NAT_IPV4; ++ param.op = SPPE_OP_SET; ++ ++ param.data.flow_nat_ipv4.fw = 0; ++ param.data.flow_nat_ipv4.sip = htonl(orig->src.u3.ip); ++ param.data.flow_nat_ipv4.dip = htonl(orig->dst.u3.ip); ++ ++ param.data.flow_nat_ipv4.l4_prot = SPPE_PROT_TCP; ++ param.data.flow_nat_ipv4.l4.port.src = htons(orig->src.u.tcp.port); ++ param.data.flow_nat_ipv4.l4.port.dst = htons(orig->dst.u.tcp.port); ++ ++ param.data.flow_nat_ipv4.nat_ip = htonl(reply->dst.u3.ip); ++ param.data.flow_nat_ipv4.nat_port = htons(reply->dst.u.tcp.port); ++ param.data.flow_nat_ipv4.max_len = 0x3; ++ ++ if (sppe_func_hook(¶m)) { ++ printk("<0><%s> fail to add IPv4 from-LAN flow!!\n", __FUNCTION__); ++ } ++ ++ param.data.flow_nat_ipv4.fw = 1; ++ param.data.flow_nat_ipv4.sip = htonl(reply->src.u3.ip); ++ param.data.flow_nat_ipv4.dip = htonl(reply->dst.u3.ip); ++ param.data.flow_nat_ipv4.l4.port.src = htons(reply->src.u.tcp.port); ++ param.data.flow_nat_ipv4.l4.port.dst = htons(reply->dst.u.tcp.port); ++ ++ param.data.flow_nat_ipv4.nat_ip = htonl(orig->src.u3.ip); ++ param.data.flow_nat_ipv4.nat_port = htons(orig->src.u.tcp.port); ++ ++ if (sppe_func_hook(¶m)) { ++ printk("<0><%s> fail to add IPv4 from-WAN flow!!\n", __FUNCTION__); ++ } ++ ++ return 0; ++} ++ ++static int sppe_tcp_flow_add_ipv6(struct nf_conn *ct) ++{ ++ SPPE_PARAM param; ++ struct nf_conntrack_tuple *orig, *reply; ++ ++ orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; ++ reply = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; ++ ++ if (1723 == htons(orig->dst.u.tcp.port)) { ++ /* PPTP Control Protocol, PPTP GRE tunneling need this kind of packet */ ++ return 0; ++ } ++ ++ memset(¶m, 0, sizeof(SPPE_PARAM)); ++ ++ param.cmd = SPPE_CMD_FLOW_ROUTE_IPV6; ++ param.op = SPPE_OP_SET; ++ ++ /* from-LAN flow */ ++ param.data.flow_route_ipv6.fw = 0; ++ param.data.flow_route_ipv6.sip[0] = htonl(orig->src.u3.ip6[0]); ++ param.data.flow_route_ipv6.sip[1] = htonl(orig->src.u3.ip6[1]); ++ param.data.flow_route_ipv6.sip[2] = htonl(orig->src.u3.ip6[2]); ++ param.data.flow_route_ipv6.sip[3] = htonl(orig->src.u3.ip6[3]); ++ param.data.flow_route_ipv6.dip[0] = htonl(orig->dst.u3.ip6[0]); ++ param.data.flow_route_ipv6.dip[1] = htonl(orig->dst.u3.ip6[1]); ++ param.data.flow_route_ipv6.dip[2] = htonl(orig->dst.u3.ip6[2]); ++ param.data.flow_route_ipv6.dip[3] = htonl(orig->dst.u3.ip6[3]); ++ param.data.flow_route_ipv6.l4_prot = SPPE_PROT_TCP; ++ param.data.flow_route_ipv6.l4.port.src = htons(orig->src.u.tcp.port); ++ param.data.flow_route_ipv6.l4.port.dst = htons(orig->dst.u.tcp.port); ++ param.data.flow_route_ipv6.max_len = 0x3; ++ ++ if (sppe_func_hook(¶m)) { ++ printk("<0><%s> fail to add IPv6 from-LAN flow!!\n", __FUNCTION__); ++ } ++ ++ /* from-WAN flow */ ++ param.data.flow_route_ipv6.fw = 1; ++ param.data.flow_route_ipv6.sip[0] = htonl(reply->src.u3.ip6[0]); ++ param.data.flow_route_ipv6.sip[1] = htonl(reply->src.u3.ip6[1]); ++ param.data.flow_route_ipv6.sip[2] = htonl(reply->src.u3.ip6[2]); ++ param.data.flow_route_ipv6.sip[3] = htonl(reply->src.u3.ip6[3]); ++ param.data.flow_route_ipv6.dip[0] = htonl(reply->dst.u3.ip6[0]); ++ param.data.flow_route_ipv6.dip[1] = htonl(reply->dst.u3.ip6[1]); ++ param.data.flow_route_ipv6.dip[2] = htonl(reply->dst.u3.ip6[2]); ++ param.data.flow_route_ipv6.dip[3] = htonl(reply->dst.u3.ip6[3]); ++ param.data.flow_route_ipv6.l4.port.src = htons(reply->src.u.tcp.port); ++ param.data.flow_route_ipv6.l4.port.dst = htons(reply->dst.u.tcp.port); ++ ++ if (sppe_func_hook(¶m)) { ++ printk("<0><%s> fail to add IPv6 from-LAN flow!!\n", __FUNCTION__); ++ } ++ ++ return 0; ++} ++ ++static int sppe_tcp_flow_add(struct nf_conn *ct) ++{ ++ if (0 == sppe_hook_ready) { ++ return 0; ++ } ++ ++ if (AF_INET == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num) { ++ sppe_tcp_flow_add_ipv4(ct); ++ return 0; ++ } else if (AF_INET6 == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num) { ++ sppe_tcp_flow_add_ipv6(ct); ++ return 0; ++ } ++ ++ /* return fail */ ++ return (-1); ++} ++#endif ++ + /* Returns verdict for packet, or -1 for invalid. */ + static int tcp_packet(struct nf_conn *ct, + const struct sk_buff *skb, +@@ -961,11 +1100,18 @@ static int tcp_packet(struct nf_conn *ct + break; + } + ++#if defined (CONFIG_CNS3XXX_SPPE) ++ if(!(th->rst == 1 || th->fin == 1)) { ++#endif + if (!tcp_in_window(ct, &ct->proto.tcp, dir, index, + skb, dataoff, th, pf)) { + spin_unlock_bh(&ct->lock); + return -NF_ACCEPT; + } ++#if defined (CONFIG_CNS3XXX_SPPE) ++ } ++#endif ++ + in_window: + /* From now on we have got in-window packets */ + ct->proto.tcp.last_index = index; +@@ -1015,6 +1161,10 @@ static int tcp_packet(struct nf_conn *ct + connection. */ + set_bit(IPS_ASSURED_BIT, &ct->status); + nf_conntrack_event_cache(IPCT_STATUS, ct); ++#if defined (CONFIG_CNS3XXX_SPPE) ++ /* Add SPPE hardware flow */ ++ sppe_tcp_flow_add(ct); ++#endif + } + nf_ct_refresh_acct(ct, ctinfo, skb, timeout); + +--- a/net/netfilter/nf_conntrack_proto_udp.c ++++ b/net/netfilter/nf_conntrack_proto_udp.c +@@ -24,6 +24,9 @@ + #include <net/netfilter/nf_log.h> + #include <net/netfilter/ipv4/nf_conntrack_ipv4.h> + #include <net/netfilter/ipv6/nf_conntrack_ipv6.h> ++#if defined (CONFIG_CNS3XXX_SPPE) ++#include <linux/cns3xxx/sppe.h> ++#endif + + static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ; + static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ; +@@ -63,6 +66,122 @@ static int udp_print_tuple(struct seq_fi + ntohs(tuple->dst.u.udp.port)); + } + ++#if defined (CONFIG_CNS3XXX_SPPE) ++static int sppe_udp_flow_add_ipv4(struct nf_conn *ct) ++{ ++ SPPE_PARAM param; ++ struct nf_conntrack_tuple *orig, *reply; ++ ++ orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; ++ reply = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; ++ ++ memset(¶m, 0, sizeof(SPPE_PARAM)); ++ ++ param.cmd = SPPE_CMD_FLOW_NAT_IPV4; ++ param.op = SPPE_OP_SET; ++ ++ param.data.flow_nat_ipv4.fw = 0; ++ param.data.flow_nat_ipv4.sip = htonl(orig->src.u3.ip); ++ param.data.flow_nat_ipv4.dip = htonl(orig->dst.u3.ip); ++ param.data.flow_nat_ipv4.l4_prot = SPPE_PROT_UDP; ++ ++ param.data.flow_nat_ipv4.l4.port.src = htons(orig->src.u.tcp.port); ++ param.data.flow_nat_ipv4.l4.port.dst = htons(orig->dst.u.tcp.port); ++ ++ param.data.flow_nat_ipv4.nat_ip = htonl(reply->dst.u3.ip); ++ param.data.flow_nat_ipv4.nat_port = htons(reply->dst.u.tcp.port); ++ ++ if (sppe_func_hook(¶m)) { ++ printk("<0><%s> fail to add IPv4 UDP from-LAN flow!!\n", __FUNCTION__); ++ } ++ param.data.flow_nat_ipv4.fw = 1; ++ param.data.flow_nat_ipv4.sip = htonl(reply->src.u3.ip); ++ param.data.flow_nat_ipv4.dip = htonl(reply->dst.u3.ip); ++ ++ param.data.flow_nat_ipv4.l4.port.src = htons(reply->src.u.tcp.port); ++ param.data.flow_nat_ipv4.l4.port.dst = htons(reply->dst.u.tcp.port); ++ ++ param.data.flow_nat_ipv4.nat_ip = htonl(orig->src.u3.ip); ++ param.data.flow_nat_ipv4.nat_port = htons(orig->src.u.tcp.port); ++ ++ if (sppe_func_hook(¶m)) { ++ printk("<0><%s> fail to add IPv4 from-WAN flow!!\n", __FUNCTION__); ++ } ++ ++ return 0; ++} ++ ++static int sppe_udp_flow_add_ipv6(struct nf_conn *ct) ++{ ++ SPPE_PARAM param; ++ struct nf_conntrack_tuple *orig, *reply; ++ ++ orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; ++ reply = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; ++ ++ memset(¶m, 0, sizeof(SPPE_PARAM)); ++ ++ param.cmd = SPPE_CMD_FLOW_ROUTE_IPV6; ++ param.op = SPPE_OP_SET; ++ ++ /* from-LAN flow */ ++ param.data.flow_route_ipv6.fw = 0; ++ param.data.flow_route_ipv6.sip[0] = htonl(orig->src.u3.ip6[0]); ++ param.data.flow_route_ipv6.sip[1] = htonl(orig->src.u3.ip6[1]); ++ param.data.flow_route_ipv6.sip[2] = htonl(orig->src.u3.ip6[2]); ++ param.data.flow_route_ipv6.sip[3] = htonl(orig->src.u3.ip6[3]); ++ param.data.flow_route_ipv6.dip[0] = htonl(orig->dst.u3.ip6[0]); ++ param.data.flow_route_ipv6.dip[1] = htonl(orig->dst.u3.ip6[1]); ++ param.data.flow_route_ipv6.dip[2] = htonl(orig->dst.u3.ip6[2]); ++ param.data.flow_route_ipv6.dip[3] = htonl(orig->dst.u3.ip6[3]); ++ param.data.flow_route_ipv6.l4_prot = SPPE_PROT_UDP; ++ param.data.flow_route_ipv6.l4.port.src = htons(orig->src.u.udp.port); ++ param.data.flow_route_ipv6.l4.port.dst = htons(orig->dst.u.udp.port); ++ ++ if (sppe_func_hook(¶m)) { ++ printk("<0><%s> fail to add IPv6 from-LAN flow!!\n", __FUNCTION__); ++ } ++ ++ /* from-WAN flow */ ++ param.data.flow_route_ipv6.fw = 1; ++ param.data.flow_route_ipv6.sip[0] = htonl(reply->src.u3.ip6[0]); ++ param.data.flow_route_ipv6.sip[1] = htonl(reply->src.u3.ip6[1]); ++ param.data.flow_route_ipv6.sip[2] = htonl(reply->src.u3.ip6[2]); ++ param.data.flow_route_ipv6.sip[3] = htonl(reply->src.u3.ip6[3]); ++ param.data.flow_route_ipv6.dip[0] = htonl(reply->dst.u3.ip6[0]); ++ param.data.flow_route_ipv6.dip[1] = htonl(reply->dst.u3.ip6[1]); ++ param.data.flow_route_ipv6.dip[2] = htonl(reply->dst.u3.ip6[2]); ++ param.data.flow_route_ipv6.dip[3] = htonl(reply->dst.u3.ip6[3]); ++ param.data.flow_route_ipv6.l4.port.src = htons(reply->src.u.udp.port); ++ param.data.flow_route_ipv6.l4.port.dst = htons(reply->dst.u.udp.port); ++ ++ if (sppe_func_hook(¶m)) { ++ printk("<0><%s> fail to add IPv6 from-LAN flow!!\n", __FUNCTION__); ++ } ++ ++ return 0; ++} ++ ++static int sppe_udp_flow_add(struct nf_conn *ct) ++{ ++ if (0 == sppe_hook_ready) { ++ return 0; ++ } ++ ++ if (AF_INET == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num) { ++ sppe_udp_flow_add_ipv4(ct); ++ return 0; ++ } else if (AF_INET6 == ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num) { ++ sppe_udp_flow_add_ipv6(ct); ++ return 0; ++ } ++ ++ /* return fail */ ++ return (-1); ++} ++#endif ++ ++ + /* Returns verdict for packet, and may modify conntracktype */ + static int udp_packet(struct nf_conn *ct, + const struct sk_buff *skb, +@@ -77,7 +196,15 @@ static int udp_packet(struct nf_conn *ct + nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout_stream); + /* Also, more likely to be important, and not a probe */ + if (!test_and_set_bit(IPS_ASSURED_BIT, &ct->status)) ++#if defined (CONFIG_CNS3XXX_SPPE) ++ { ++#endif + nf_conntrack_event_cache(IPCT_STATUS, ct); ++#if defined (CONFIG_CNS3XXX_SPPE) ++ /* Add SPPE hardware flow */ ++ sppe_udp_flow_add(ct); ++ } ++#endif + } else + nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_udp_timeout); + |