mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-12-29 15:35:11 +02:00
642064ae9a
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@22323 3c298f89-4303-0410-b956-a3cf2f4a3e73
11803 lines
294 KiB
Diff
11803 lines
294 KiB
Diff
--- /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);
|
|
|