/****************************************************************************** ** ** FILE NAME : amazon_s_sw.c ** PROJECT : Amazon_S ** MODULES : Switch driver ** ** DATE : 14 AUG 2007 ** AUTHOR : Reddy Mallikarjuna ** DESCRIPTION : ETH Interface (MII0/MII1) Driver ** COPYRIGHT : Copyright (c) 2006 ** Infineon Technologies AG ** Am Campeon 1-12, 85579 Neubiberg, Germany ** ** 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. ** ** HISTORY **Version $Date $Author $Comment ** 1.0.0 17 OCT 2007 Reddy Mallikarjuna Initiate Version ** 1.0.1 20 Mar 2008 Reddy Mallikarjuna Supports,interrupt handle,force to set MII1 link(speed/link/duplex)info effect on MII1 GPHY status. ** 1.0.4 29 Dec 2008 Reddy Mallikarjuna Set switch configurations: Classification: Based on 802.1q & DSCP Scheduling : Strict Priority and Rate limit is disabled *******************************************************************************/ /*! \file amazon_s_sw.c \ingroup AMAZON_S_SWITCH \brief internal switch driver */ /*! \defgroup AMAZON_S_SWITCH AMAZON_S SWITCH \ingroup AMAZON_S_BSP \brief amazon_s internal swithc driver module */ /*! \defgroup AMAZON_S_SWITCH_FUNCTIONS AMAZON_S SWITCH FUNCTIONS \ingroup AMAZON_S_SWITCH \brief amazon_s internal switch driver functions */ #include /* retrieve the CONFIG_* macros */ #if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) # define MODVERSIONS #endif #if defined(MODVERSIONS) && !defined(__GENKSYMS__) # include #endif #ifndef EXPORT_SYMTAB # define EXPORT_SYMTAB /* need this one 'cause we export symbols */ #endif #include #include #include #include /* printk() */ #include /* kmalloc() */ #include /* error codes */ #include /* size_t */ #include /* mark_bh */ #include #include #include #include /* struct device, and other headers */ #include /* eth_type_trans */ #include /* struct iphdr */ #include /* struct tcphdr */ #include #include #include #include #include #include #include #include #include #include #include #include #include /*Amazon-S platform registers */ #include #include /*struct dma_device_info */ #include #include /* gpio pins reserved for this module, ex: bsp_port_xxx functions*/ // during transition period, use macro "ENABLE_OLD_IFX_ETHSW_API" to replace "CONFIG_IFX_ETHSW_API" #ifdef ENABLE_OLD_IFX_ETHSW_API #include #include #endif /** ** Set internal switch configurations: ** Classification: 802.1q & DSCP ** Scheduling for all internal ports: Strict Priority and Rate limit is Disabled **/ #define SWITCH_STRICT_PRI_AND_CLASSIFICATION 1 /*1-enable/0-disable*/ /*! * \brief enable/disable MII 0 config */ #define CONFIG_MII0 1 /*! * \brief enable/disable MII 1 config */ #define CONFIG_MII1 1 /*! * \brief enable/disable CPU logical port during init module */ #define CONFIG_LOGICAL_PORT_ENABLE 0 /*g_logicalport*/ #ifdef CONFIG_VR9 #undef CONFIG_SW_ROUTING_MODE #define CONFIG_SW_ROUTING_MODE #endif /*--- #ifdef CONFIG_VR9 ---*/ #ifdef CONFIG_SW_ROUTING_MODE #define CONFIG_PMAC_DMA_ENABLE 1 /*g_pmac_dma */ #define CONFIG_DMA_PMAC_ENABLE 1 /*g_dma_pmac*/ #else #define CONFIG_PMAC_DMA_ENABLE 0 /*g_pmac_dma */ #define CONFIG_DMA_PMAC_ENABLE 0 /*g_dma_pmac*/ #endif /*! * \brief MII1 interrupt handle to force link speed when there is changes in * the GPHY status (i.e. link/speed/duplex), otherwise default force link based on MII1_INTERFACE mode */ #define MII1_GPHY_INT_HANDLE 1 /*@hualab 1*/ /*! * \brief enable/disable flow control for internal switch as well as externel tantos switch during module init */ #define ENABLE_SWITCH_FLOW_CONTROL 1 /*! * \brief init the externl tantos switch for MII0 interface. * incase if its handling some other module, then disable it. * Tantos external switch init for Mii0 interface */ #define TANTOS_SWITCH_INIT 0 /*! * \brief Supports NAPI features */ #ifdef CONFIG_AMAZON_S_EXTRA_CFG #ifdef CONFIG_AMAZON_S_ENABLE_NAPI #define ENABLE_NAPI 1 #else #define ENABLE_NAPI 0 #endif #else #define ENABLE_NAPI 1 #endif /* * \brief Allign with GPIO numbers with Externel interrupt */ #if defined (MII1_GPHY_INT_HANDLE) && MII1_GPHY_INT_HANDLE #define EXT_INT_GPIO 9 /*GPIO 0 (EXT0), GPIO 1 (EXT1), GPIO 2 (EXT2), GPIO 9 (EXT5), GPIO 10 (EXT4), GPIO 39 (EXT3 ) */ #define EXT_INT_NO 5/*Make sure allign with Externl interrupt no. and GPIO pin no. */ #endif /*! * \brief enable/disable during module init * Note: when port ingress direct forwarding is enabled, * then all ingress traffic from this are forwarded to queue 0 of port 2. * Here no lookup, learning, VLAN processing and queue selection are performed */ #ifdef CONFIG_SW_ROUTING_MODE #define CONFIG_PORT_INGRESS_DIRECT_FORWARD_ENABLE 1 #else #define CONFIG_PORT_INGRESS_DIRECT_FORWARD_ENABLE 0 #endif /*! * \brief enable/disable during module init * when the port redirect is enabled, the transmit packets are redirected to CPU port. * The destination port member in status header of CPU port egress packest carry the original value. */ #define CONFIG_PORT_REDIRECT_ENABLE 0 /* * \brief Support modes for MII0 and MII1 interface */ #define RGMII_MODE 0 #define MII_MODE 1 #define REV_MII_MODE 2 #define RED_MII_MODE_IC 3 /*Input clock */ #define RGMII_MODE_100MB 4 #define TURBO_REV_MII_MODE 6 /*Turbo Rev Mii mode */ #define RED_MII_MODE_OC 7 /*Output clock */ #define RGMII_MODE_10MB 8 /*! * \brief Interface mode for MII 0 during module init */ #define MII0_INTERFACE RGMII_MODE_100MB /*selected mii0 interface mode */ /*! * \brief Interface mode for MII 1 during module init, effect only when disabled MII1_GPHY_INT_HANDLE */ /*@hualab*/ #define MII1_INTERFACE RGMII_MODE_100MB /* selected mii1 interface mode*/ /* * \brief default no.of interface (eth0/eth1) */ #if defined(CONFIG_PMAC_DMA_ENABLE) && CONFIG_PMAC_DMA_ENABLE /*! * \brief default no. of interfaces is 2 (eth0 & eth1) * if pmac to dma header is enabled, then eth0 --> MII0 and eth1 -->MII1 ) */ #define AMAZON_S_SW_INT_NO 2 #else /*! * \brief default no.of interfaces is 1 (eth0 only) if pmac to dma header is disabled, then eth0 --> MII0 and MII1 ) */ #define AMAZON_S_SW_INT_NO 1 #endif /*! * \brief default dma descriptor length */ #define ETHERNET_PACKET_DMA_BUFFER_SIZE 1568 // xuliang: 8 is not working for Taipei board #define DMA_TX_BURST_LEN 4 /*should be 2/4/8 */ #define DMA_RX_BURST_LEN 4 /*should be be 2/4/8 */ #define IFX_SUCCESS 1 #define IFX_ERROR -1 /*! * \brief internal switch Max Ports */ #define AMAZON_S_SWITCH_MAX_PORT 3 /*! * \brief max ip tos in internal switch */ #define SWTCH_MAX_IPTOS 0x40 /* 6 bits, 2^7 - 1 */ #define LOOPBACK_TEST 0 #define SWITCH_INTERRUPT 0 /*! * \brief Reset GPHY chip using the RESET_GPHY gpio pin * if it is already used any other module, then disable it */ #define GPHY_RESET_ENABLE 1 #define AMAZON_S_SWITCH_DRIVER_VERSION "1.0.4" /* * \brief GPIO numbers * reserved for GPIO's to avoid conflicts between modules for same GPIO pin */ #define SWITCH_MDIO 42 /*GPIO 42 (P2.10) */ #define SWITCH_MDC 43 /*GPIO 43 (P2.11) */ #define MII0_COL 32 /*GPIO P2.0 (MII0_COL) */ #define MII0_CRS 33 /*GPIO P2.1 (MII0_CRS) */ #define MII0_TXERR 40 /*GPIO P2.8 (MII0_TXERR) */ #define MII0_RXERR 41 /*GPIO P2.9 (MII0_RXERR) */ #define MII1_COL 44 /*GPIO P2.12 (MII1_COL) */ #define MII1_CRS 47 /*GPIO P2.15 (MII1_CRS) */ #define MII1_TXERR 45 /*GPIO P2.13 (MII1_TXERR) */ #define MII1_RXERR 46 /*GPIO P2.14 (MII1_RXERR) */ #define CLOCK_OUT2 3 /*GPIO 3 (P0.3) */ #define RESET_GPHY 32 /*GPIO 32 (P2.0) */ #define AR9_RGMII0_BYPASS_DELAY_FIX 1 /*Set RGMI0 Rx clock delay DLL 1.75nSec,Tx-->0ns*/ #define AR9_RGMII1_BYPASS_DELAY_FIX 1 /*set Tx-->1.5ns, Rx-->0ns DLL delay*/ #define PMAC_RX_IPG_DELAY 1 #define MAX_PIN_PER_PORT 16 /* * brief Every port has 16 pins, up to 4 ports from 0~3 */ #define PIN2PORT(pin) ((((pin) >> 4) & 0x3)) #define PIN2PORTPIN(pin) ((pin) % (MAX_PIN_PER_PORT)) #define IFX_SWITCH_PIN_RESERVE(pin) \ bsp_port_reserve_pin((PIN2PORT(pin)), (PIN2PORTPIN(pin)), (PORT_MODULE_SWITCH)) #define IFX_SWITCH_DIR_OUT(pin) \ bsp_port_set_dir_out((PIN2PORT(pin)), (PIN2PORTPIN(pin)), (PORT_MODULE_SWITCH)) #define IFX_SWITCH_DIR_IN(pin) \ bsp_port_set_dir_in((PIN2PORT(pin)), (PIN2PORTPIN(pin)), (PORT_MODULE_SWITCH)) #define IFX_SWITCH_OUTPUT_SET(pin) \ bsp_port_set_output((PIN2PORT(pin)), (PIN2PORTPIN(pin)), (PORT_MODULE_SWITCH)) #define IFX_SWITCH_OUTPUT_CLR(pin) \ bsp_port_clear_output((PIN2PORT(pin)), (PIN2PORTPIN(pin)), (PORT_MODULE_SWITCH)) #define IFX_SWITCH_ALTSEL0_SET(pin) \ bsp_port_set_altsel0((PIN2PORT(pin)), (PIN2PORTPIN(pin)), (PORT_MODULE_SWITCH)) #define IFX_SWITCH_ALTSEL0_CLR(pin) \ bsp_port_clear_altsel0((PIN2PORT(pin)), (PIN2PORTPIN(pin)), (PORT_MODULE_SWITCH)) #define IFX_SWITCH_OD_SET(pin) \ bsp_port_set_open_drain((PIN2PORT(pin)), (PIN2PORTPIN(pin)), (PORT_MODULE_SWITCH)) #define IFX_SWITCH_OD_CLR(pin) \ bsp_port_clear_open_drain((PIN2PORT(pin)), (PIN2PORTPIN(pin)), (PORT_MODULE_SWITCH)) #define IFX_SWITCH_ALTSEL1_SET(pin) \ bsp_port_set_altsel1((PIN2PORT(pin)), (PIN2PORTPIN(pin)), (PORT_MODULE_SWITCH)) #define IFX_SWITCH_ALTSEL1_CLR(pin) \ bsp_port_clear_altsel1((PIN2PORT(pin)), (PIN2PORTPIN(pin)), (PORT_MODULE_SWITCH)) #define IFX_SWITCH_PUDSEL_SET(pin) \ bsp_port_set_pudsel((PIN2PORT(pin)), (PIN2PORTPIN(pin)), (PORT_MODULE_SWITCH)) #define IFX_SWITCH_PUDEN_SET(pin) \ bsp_port_set_puden((PIN2PORT(pin)), (PIN2PORTPIN(pin)), (PORT_MODULE_SWITCH)) #undef AMAZON_S_SW_DUMP //#define AMAZON_S_SW_DUMP #undef ENABLE_TRACE //#define ENABLE_TRACE #ifdef ENABLE_TRACE #define TRACE(fmt,args...) printk("%s: " fmt, __FUNCTION__ , ##args) #else #define TRACE(fmt,args...) #endif /***************************************** Functions Declaration *********************************/ static int switch_init(struct net_device *dev); int switch_tx(struct sk_buff *skb, struct net_device *dev); int switch_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); struct net_device_stats *switch_stats(struct net_device *dev); //int switch_change_mtu(struct net_device *dev, int new_mtu); //int switch_set_mac_address(struct net_device *dev, void *p); /*switch set mac address*/ void switch_tx_timeout (struct net_device *dev);/*switch transmit timeout*/ void open_rx_dma(void); /*open dma rx channel*/ void close_rx_dma(void); /*close the dma rx channel*/ int tantos_switch_init(void); /*init the external tantos switch*/ static int amazon_s_switch_get_logical_port_status(void); static void amazon_s_switch_set_logical_port_status(int mode); static int amazon_s_switch_get_headerstatus_pmactodma(void); static void amazon_s_switch_set_headerstatus_pmactodma(int mode); static int amazon_s_switch_get_headerstatus_dmatopmac(void); static void amazon_s_switch_set_headerstatus_dmatopmac(int mode); static int amazon_s_switch_get_portingress_directforwarding(int port); static int amazon_s_switch_set_portingress_directforwarding(int port, int mode); static int amazon_s_switch_get_portegress_redirect(int port); static int amazon_s_switch_set_portegress_redirect(int port, int mode); static int amazon_s_switch_enable_fc(int port); static int amazon_s_switch_disable_fc(int port); static unsigned long amazon_s_switch_get_rmon_counter_value(int port, int offset); static int amazon_s_switch_clr_rmon_by_port(int port); static void amazon_s_switch_clr_rmon(void); //static int amazon_s_switch_set_mac_table_entry (x_IFX_mac_table_entry *pMactable, int add); //static int amazon_s_switch_get_mac_table_entry (x_IFX_mac_table_entry *pMactable); void amazon_xon(struct net_device *dev); struct dma_device_info *g_dma_device=NULL; /***************************************** Global Data *******************************************/ static struct net_device *switch_devs[AMAZON_S_SW_INT_NO]; struct proc_dir_entry* g_amazon_s_sw_dir; static int timeout = 10*HZ; static unsigned int g_transmit=0, g_skb_headroom=0; static int g_logicalport=0, g_pmac_dma=0,g_dma_pmac=0, eth0_up=0; static int init_done = 0; #if defined(CONFIG_PMAC_DMA_ENABLE) && CONFIG_PMAC_DMA_ENABLE static int eth1_up=0; #endif /*! * \brief cpu port egress packet structure header */ x_IFX_cpu_egress_pkt_header_t eg_pkt_hdr; /*cpu port Egress packet header */ /*! * \brief cpu port ingress packet structure header */ x_IFX_cpu_ingress_pkt_header_t ig_pkt_hdr; /*************************************************************************************************/ #ifdef AMAZON_S_SW_DUMP /* * \brief dump skb data * \param[in] len length of the data buffer * \param[in] pData Pointer to data to dump * * \return void No Value */ static inline void dump_skb(u32 len, char *pData){ int i; for(i=0;i 0; i--) udelay(1000); } /** * \fn int ifx_switch_write_mdio(unsigned int uPhyAddr, unsigned int uRegAddr,unsigned int uData ) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Write data to externel switch registers using the mdio interface * \param [in] uPhyAddr external switch phy address * \param [in] uRegAddr switch register address * \param [in] uData 16-bit data to write into the phy registr * \return Success */ int ifx_switch_write_mdio(unsigned int uPhyAddr, unsigned int uRegAddr,unsigned int uData ){ unsigned int val ; while (AMAZON_S_REG32(AMAZON_S_SW_MDIO_CTL) & 0x8000 ) { udelay(100); }; val = ((uData&0xffff) <<16)| (1<<15) | (0x01<< 10) | ((uPhyAddr&0x1f)<<5) | ((uRegAddr&0x1f)); AMAZON_S_REG32(AMAZON_S_SW_MDIO_CTL) = val ; udelay(100); while (AMAZON_S_REG32(AMAZON_S_SW_MDIO_CTL) & 0x8000 ) { udelay(100); }; /*Wait command complete state */ return IFX_SUCCESS; /*could not fail*/ } EXPORT_SYMBOL(ifx_switch_write_mdio); /** * \fn unsigned short ifx_switch_read_mdio(unsigned int uPhyAddr, unsigned int uRegAddr ) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Read data from externel switch registers using the mdio interface * \param [in] uPhyAddr external phy address * \param [in] uRegAddr Reg address of the phy * \return 16-bit switch register data */ unsigned short ifx_switch_read_mdio(unsigned int uPhyAddr, unsigned int uRegAddr ){ unsigned int val; unsigned short data; while (AMAZON_S_REG32(AMAZON_S_SW_MDIO_CTL) & 0x8000 ) { udelay(100); }; /*Check busy state */ val = (1<<15) | (0x2<< 10) | ((uPhyAddr&0x1f)<<5) | ((uRegAddr&0x1f)); AMAZON_S_REG32(AMAZON_S_SW_MDIO_CTL) = val ; udelay(100); while (AMAZON_S_REG32(AMAZON_S_SW_MDIO_CTL) & 0x8000 ) { udelay(100); }; /*Wait command complete state */ data = (AMAZON_S_REG32(AMAZON_S_SW_MDIO_DATA) & 0xffff) ; return data; } EXPORT_SYMBOL(ifx_switch_read_mdio); /** * \fn static int ifx_switch_get_logical_port_status(void) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Get logical port status * \return 1 (enabled)/ 0(Disabled) */ static int amazon_s_switch_get_logical_port_status(void){ return ((AMAZON_S_REG32(AMAZON_S_SW_GCTL0)>>29)&0x1); } /** * \fn static void amazon_s_switch_set_logical_port_status(int mode) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Set switch logical port status * \param mode logical port mode enable(1)/disable(0) * \return None */ static void amazon_s_switch_set_logical_port_status(int mode){ if(mode){ AMAZON_S_REG32(AMAZON_S_SW_GCTL0) |= (1<<29); printk("Logical CPU port is enabled\n"); g_logicalport = 1; } else { AMAZON_S_REG32(AMAZON_S_SW_GCTL0) &= ~(1<<29); printk("Logical CPU port is disabled\n"); g_logicalport = 0; } } /** * \fn static int amazon_s_switch_get_headerstatus_pmactodma(void) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Get status header for packets going from PMAC to DMA * \return enabled(1)/disabled(0) */ static int amazon_s_switch_get_headerstatus_pmactodma(void){ return ((AMAZON_S_REG32(AMAZON_S_SW_PMAC_HD_CTL)>>19)&0x1); } /** * \fn static void amazon_s_switch_set_headerstatus_pmactodma(int mode) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Set status header for packets going from PMAC to DMA * This is valid when enabled the logical cpu port * \param mode set enable(1)/disable(0) * \return None */ static void amazon_s_switch_set_headerstatus_pmactodma(int mode){ if(mode){ printk("%s[%d]: Enable PMAC to DMA\n",__FUNCTION__,__LINE__); AMAZON_S_REG32(AMAZON_S_SW_PMAC_HD_CTL) |= (1<<19); g_pmac_dma = 1; } else { printk("%s[%d]: Disable PMAC to DMA\n",__FUNCTION__,__LINE__); AMAZON_S_REG32(AMAZON_S_SW_PMAC_HD_CTL) &= ~(1<<19); g_pmac_dma = 0; } } /** * \fn static int amazon_s_switch_get_headerstatus_dmatopmac(void) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Get status header for packets from DMA to PMAC * \return enabled(1)/disabled(0) */ static int amazon_s_switch_get_headerstatus_dmatopmac(void){ return ((AMAZON_S_REG32(AMAZON_S_SW_PMAC_HD_CTL)>>22)&0x1); } /** * \fn void amazon_s_switch_set_headerstatus_dmatopmac(int mode) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Set status header for packets from DMA to PMAC * \param mode set enable(1)/disable(0) * \return None */ static void amazon_s_switch_set_headerstatus_dmatopmac(int mode){ if(mode){ printk("%s[%d]: Enable DMA to PMAC\n",__FUNCTION__,__LINE__); AMAZON_S_REG32(AMAZON_S_SW_PMAC_HD_CTL) |= (1<<22); g_dma_pmac = 1; } else { printk("%s[%d]: Disable DMA to PMAC \n",__FUNCTION__,__LINE__); AMAZON_S_REG32(AMAZON_S_SW_PMAC_HD_CTL) &= ~(1<<22); g_dma_pmac = 0; } } /** * \fn static int amazon_s_switch_get_portingress_directforwarding(int port) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Get port ingress direct forwarding status * \param port port number [0~2] * \return enabled(1)/disabled(0) */ static int amazon_s_switch_get_portingress_directforwarding(int port){ if(port < 0 || port > AMAZON_S_SWITCH_MAX_PORT){ return IFX_ERROR; } return ((AMAZON_S_REG32(AMAZON_S_SW_P0_CTL+4*port)>>19)&0x1); } /** * \fn static int amazon_s_switch_set_portingress_directforwarding(int port, int mode) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Set port ingress direct forwarding status * if set, then No lookup, learning, VLAN processing and queue selection are performed. * \param port internal switch port number * \param mode internal switch port direct forwarding is enabled/disabled * \return On Success return IFX_SUCCESS otherwise IFX_ERROR */ static int amazon_s_switch_set_portingress_directforwarding(int port, int mode){ if(port < 0 || port > AMAZON_S_SWITCH_MAX_PORT){ /* printk("%s[%d], Port number Error!!!", __FUNCTION__,__LINE__); */ return IFX_ERROR; } if(mode){ /* printk("%s[%d]: Port:%d Ingress Direct forwarding enabled\n",__FUNCTION__,__LINE__,port); */ AMAZON_S_REG32(AMAZON_S_SW_P0_CTL+4*port) |= (1<<19); } else { /* printk("%s[%d]: Port:%d Ingress Direct forwarding Disabled\n",__FUNCTION__,__LINE__,port); */ AMAZON_S_REG32(AMAZON_S_SW_P0_CTL+4*port) &= ~(1<<19); } return IFX_SUCCESS; } /** * \fn static int amazon_s_switch_get_portegress_redirect(int port) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Get port redirect status * \param port internal port number * \return enabled(1)/disabled(0) */ static int amazon_s_switch_get_portegress_redirect(int port){ if(port < 0 || port > AMAZON_S_SWITCH_MAX_PORT){ printk("%s:, Line:%d, Port number Error!!!", __FUNCTION__,__LINE__); return IFX_ERROR; } return ((AMAZON_S_REG32(AMAZON_S_SW_P0_CTL+4*port)>>13)&0x1); } /** * \fn static int amazon_s_switch_set_portegress_redirect(int port, int mode) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Set port redirect status * \param port internal switch physical port number * \param mode internal switch port egress redirect forwarding is enabled/disabled * \return On Success return IFX_SUCCESS otherwise IFX_ERROR */ static int amazon_s_switch_set_portegress_redirect(int port, int mode){ if(port < 0 || port > AMAZON_S_SWITCH_MAX_PORT){ return IFX_ERROR; } if(mode){ /* printk("%s[%d]: Port:%d Port Redirect Option enabled\n",__FUNCTION__,__LINE__,port); */ AMAZON_S_REG32(AMAZON_S_SW_P0_CTL+4*port) |= (1<<13); } else { /* printk("%s[%d]: Port:%d Port Redirect Option Disabled\n",__FUNCTION__,__LINE__,port); */ AMAZON_S_REG32(AMAZON_S_SW_P0_CTL+4*port) &= ~(1<<13); } return IFX_SUCCESS; } /** * \fn static int amazon_s_switch_enable_fc(int port) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Set port flowcontrol * \param port interernal switch port number * \return On Success return IFX_SUCCESS otherwise IFX_ERROR */ static int amazon_s_switch_enable_fc(int port){ if(port < 0 || port > (AMAZON_S_SWITCH_MAX_PORT-1)) { return IFX_ERROR; } if(port) /* Port 1 */ AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= (1<<10); else /*Port 0 */ AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= (1<<0); // printk("%s[%d], Port:%d Flow Control Enabled \n",__FUNCTION__,__LINE__,port); return IFX_SUCCESS; } /** * \fn static int amazon_s_switch_disable_fc(int port) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Disable port flowcontrol * \param port internal switch port number * \return On Success return IFX_SUCCESS otherwise IFX_ERROR */ static int amazon_s_switch_disable_fc(int port){ if(port < 0 || port > (AMAZON_S_SWITCH_MAX_PORT-1)) { return IFX_ERROR; } if(port ) /*Port 1*/ AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= ~0x0400; else /*Port 0*/ AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= ~0x01; /* printk("%s[%d], Port:%d Flow Control disabled \n",__FUNCTION__,__LINE__,port); */ return IFX_SUCCESS; } /** * \fn static void amazon_s_switch_check_rmon_counter_busy(void) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Wait untill mib counter busy flag released. * If counter is release, then it's allowable to access * new command to read/write MIB counters * \return none */ static void amazon_s_switch_check_rmon_counter_busy(void){ /* wait for the busy bit */ while ( AMAZON_S_REG32(AMAZON_S_SW_RMON_CTL) & 0x800); /*Fix me*/ } /** * \fn static unsigned long amazon_s_switch_get_rmon_counter_value(int port, int offset) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Get port based MIB counters with MIB register offset * \param port internal switch port no. * \param offset MIB register offset * \return On Success return counter value otherwise 0 */ static unsigned long amazon_s_switch_get_rmon_counter_value(int port, int offset){ unsigned int val = 0; unsigned long counter; if(port < 0 || port > AMAZON_S_SWITCH_MAX_PORT){ printk("%s[%d]: Error !!! Port:%d is not in limit\n", __FUNCTION__,__LINE__,port); return 0; } amazon_s_switch_check_rmon_counter_busy(); /* read the specific port+offset counter from RMON counter */ val = (port<<6) | (0x800) | (offset); AMAZON_S_REG32(AMAZON_S_SW_RMON_CTL) = val; amazon_s_switch_check_rmon_counter_busy(); /* get counters ! */ counter = AMAZON_S_REG32(AMAZON_S_SW_RMON_ST) ; return(counter); } /** * \fn static int amazon_s_switch_clr_rmon_by_port(int port) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Clear port based MIB counters * \param port internal switch port no. * \return On Success return counter value otherwise IFX_ERROR */ static int amazon_s_switch_clr_rmon_by_port(int port){ int val; if(port < 0 || port > AMAZON_S_SWITCH_MAX_PORT){ printk("%s[%d]: Error !!! Port:%d is not in limit\n", __FUNCTION__,__LINE__,port); return IFX_ERROR; } amazon_s_switch_check_rmon_counter_busy(); /* renew the specific port RMON counter */ val = (port<<6) | (0x800)| (0x2<< 9); AMAZON_S_REG32(AMAZON_S_SW_RMON_CTL) = val; amazon_s_switch_check_rmon_counter_busy(); return IFX_SUCCESS; } /** * \fn static void amaozon_s_switch_clr_rmon(void) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Clear all port MIB counters * \return On Success return counter value otherwise IFX_ERROR */ static void amazon_s_switch_clr_rmon(void){ int val; amazon_s_switch_check_rmon_counter_busy(); /* renew ALL RMON counters */ val = (0x800)| (0x03<< 9); AMAZON_S_REG32(AMAZON_S_SW_RMON_CTL) = val; amazon_s_switch_check_rmon_counter_busy(); } #if 0 /** * \fn static int amazon_s_switch_set_mac_table_entry (x_IFX_mac_table_entry *pMactable) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Add/Delete mac address to/from mac table * \param add Add/Delete mac address to/from mac table * \param pMactable pointer to the mac table structure * \return return IFX_SUCCESS */ static int amazon_s_switch_set_mac_table_entry (x_IFX_mac_table_entry *pMactable, int add){ /* check if access engine is available */ while(AMAZON_S_REG32(AMAZON_S_SW_ADR_TB_ST2) & 0x80000000) { udelay(10); } AMAZON_S_REG32(AMAZON_S_SW_ADR_TB_CTL0) = ((pMactable->mac[2] << 24) | (pMactable->mac[3] << 16) | \ (pMactable->mac[4] << 8) | (pMactable->mac[5] << 0)); AMAZON_S_REG32(AMAZON_S_SW_ADR_TB_CTL1) = (((pMactable->Portmap & 0xff) << 20 ) | \ ((pMactable->Fidgroup && 0x3) << 16 ) | \ (pMactable->mac[0] << 8) | \ (pMactable->mac[1] << 0)); if (add) { /*add entry*/ AMAZON_S_REG32(AMAZON_S_SW_ADR_TB_CTL2) = ((0x0 << 20) | (0x7 <<16) | \ ((pMactable->staticEntry & 1) << 12) | \ (pMactable->ageTimer & 0x7ff)); } else { /* delete entry */ AMAZON_S_REG32(AMAZON_S_SW_ADR_TB_CTL2) = ((0x1 << 20) /*command*/ \ | (0xf <<16) ) /* Access control*/; } /* TODO: wait for command completion and check result */ return IFX_SUCCESS; } /** * \fn static int amazon_s_switch_get_mac_table_entry (x_IFX_mac_table_entry *pMactable) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief Get mac address from mac table based on fid value * \param pMactable pointer to the mac table structure * \return return IFX_SUCCESS */ static int amazon_s_switch_get_mac_table_entry (x_IFX_mac_table_entry *pMactable){ u32 val; u32 fid; /* check if access engine is available */ while(AMAZON_S_REG32(AMAZON_S_SW_ADR_TB_ST2) & 0x80000000) { udelay(10); } if (pMactable->initial) { AMAZON_S_REG32(AMAZON_S_SW_ADR_TB_CTL2) = ((0x3 << 20) /*initial search command*/ \ | (0x0 <<16) ) /* Access control for initial to the first address */; /* wait for command completion and check result */ do { val = AMAZON_S_REG32(AMAZON_S_SW_ADR_TB_ST2); udelay(5); } while(val & 0x80000000); val = AMAZON_S_REG32(AMAZON_S_SW_ADR_TB_ST2); if( (val << 28 ) & 0x7 ) return IFX_ERROR; } fid = (u32)pMactable->Fidgroup; do { AMAZON_S_REG32(AMAZON_S_SW_ADR_TB_CTL1) = ((fid << 16) && 0x3); AMAZON_S_REG32(AMAZON_S_SW_ADR_TB_CTL2) = ((2 << 16 ) | (0xe <<16) ); /* wait for command completion and check result */ do { val = AMAZON_S_REG32(AMAZON_S_SW_ADR_TB_ST2); } while(val & 0x80000000); if ((val & 0x70000000) || ( val & (1<<14)/*bad status*/) ) /*bits-30~28 */ return IFX_ERROR; } while ((val && (1<<13)) == 0 ); pMactable->ageTimer = 0; pMactable->staticEntry = (val && (1 <<13)); if (!pMactable->staticEntry) pMactable->ageTimer = val && 0x7ff; val = AMAZON_S_REG32(AMAZON_S_SW_ADR_TB_ST1); pMactable->Fidgroup = ((val << 16) && 0x3); pMactable->Portmap = ((val << 20) && 0xff); pMactable->mac[0] = (val >> 8) & 0xFF; pMactable->mac[1] = (val >> 0) & 0xFF; val = AMAZON_S_REG32(AMAZON_S_SW_ADR_TB_ST0); pMactable->mac[2] = (val >> 24) & 0xFF; pMactable->mac[3] = (val >> 16) & 0xFF; pMactable->mac[4] = (val >> 8) & 0xFF; pMactable->mac[5] = (val >> 0) & 0xFF; return IFX_SUCCESS; } #endif static unsigned char my_ethaddr[MAX_ADDR_LEN]; /* need to get the ether addr from u-boot */ static int __init ethaddr_setup(char *line){ char *ep; int i; memset(my_ethaddr, 0, MAX_ADDR_LEN); /* there should really be routines to do this stuff */ for (i = 0; i < 6; i++) { my_ethaddr[i] = line ? simple_strtoul(line, &ep, 16) : 0; if (line) line = (*ep) ? ep+1 : ep; } TRACE("mac address %2x-%2x-%2x-%2x-%2x-%2x \n" ,my_ethaddr[0] ,my_ethaddr[1] ,my_ethaddr[2] ,my_ethaddr[3] ,my_ethaddr[4] ,my_ethaddr[5]); return 0; } __setup("ethaddr=", ethaddr_setup); /* * \brief open RX DMA channels * \param: none * \return: none */ void open_rx_dma(void){ struct dma_device_info* dma_dev=g_dma_device; int i; /*printk("%s[%d]: Open DMA RX channels!!! \n",__FUNCTION__,__LINE__); */ for(i=0;imax_rx_chan_num;i++) { if((dma_dev->rx_chan[i])->control==AMAZON_S_DMA_CH_ON) (dma_dev->rx_chan[i])->open(dma_dev->rx_chan[i]); } } /* * \brief close RX DMA channels * \param: none * \return: none */ void close_rx_dma(){ struct dma_device_info* dma_dev=g_dma_device; int i; /*printk("%s[%d]: Closed DMA RX channels!!! \n",__FUNCTION__,__LINE__);*/ for(i=0;imax_rx_chan_num;i++) dma_dev->rx_chan[i]->close(dma_dev->rx_chan[i]); } static int index=0 ; int amazon_s_switch_open(struct net_device *dev){ if(index == 0){ open_rx_dma(); } index++; if(strcmp(dev->name, "eth0") == 0 ) { eth0_up =1; /*When eth0 is up, then p0 port force to link up */ AMAZON_S_REG32(AMAZON_S_SW_P0_CTL) &= ~(1 << 17 ); AMAZON_S_REG32(AMAZON_S_SW_P0_CTL)|= (1 << 18 ); } #if defined(CONFIG_PMAC_DMA_ENABLE) && CONFIG_PMAC_DMA_ENABLE if(strcmp(dev->name, "eth1") == 0 ) { eth1_up =1; /*When eth1 is up, then p1 port link is up */ AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) &= ~(1 << 17 ); AMAZON_S_REG32(AMAZON_S_SW_P1_CTL)|= (1 << 18 ); } #endif #if defined(LOOPBACK_TEST) && !LOOPBACK_TEST netif_start_queue(dev); /* printk("%s: start queue: %s\n",__func__,dev->name); */ #else printk("%s: LOOPBACK TEST is enabled \n",__func__); #endif /*LOOPBACK_TEST */ /* *printk("%s:, ifindex: %d, dev name:%s\n", __FUNCTION__, dev->ifindex,dev->name); */ return OK; } int switch_release(struct net_device *dev){ if(index) index--; if(index == 0){ close_rx_dma(); } /*When eth0 is down, then p0 port force to link down */ if(strcmp(dev->name, "eth0") == 0 ) { eth0_up =0; AMAZON_S_REG32(AMAZON_S_SW_P0_CTL) &= ~(1 << 18 ); AMAZON_S_REG32(AMAZON_S_SW_P0_CTL)|= (1 << 17 ); } #if defined(CONFIG_PMAC_DMA_ENABLE) && CONFIG_PMAC_DMA_ENABLE /*When eth1 is down, then p1 port force to link down */ if(strcmp(dev->name, "eth1") == 0 ) { eth1_up =0; AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) &= ~(1 << 18 ); AMAZON_S_REG32(AMAZON_S_SW_P1_CTL)|= (1 << 17 ); } #endif #if defined( LOOPBACK_TEST) && !LOOPBACK_TEST netif_stop_queue(dev); /* printk("%s: stop queue: %s\n",__func__,dev->name); */ #else printk("%s: LOOPBACK TEST is enabled \n",__func__); #endif /*LOOPBACK_TEST */ return OK; } int switch_proc_read(char *buf, char **start, off_t offset, int count, int *eof, void *data){ *eof=1; return (int)offset+4; } /* * \brief This function reads the proc entry of the DSCP COS map switch registers */ int etop_dscp_cos_proc_read(char *buf, char **start, off_t offset, int count, int *eof, void *data){ int len=0,i,j; len+=sprintf(buf+len,"DSCP COS MAP:\n"); for(j=0;j<4;j++){ for(i=0;i<16;i++){ len += sprintf(buf+len, "DSCP%d %d\n", i+j*16, (AMAZON_S_REG32(AMAZON_S_SW_DFSRV_MAP0 + j *4) >> (i*2))&0x3); } } return len; } /* * \brief This function reads the proc entry of the VLAN COS map */ int etop_vlan_cos_proc_read(char *buf, char **start, off_t offset, int count, int *eof, void *data){ int len=0, i; len+=sprintf(buf+len,"VLAN COS MAP\n"); for(i=0;i<8;i++) { len+=sprintf(buf+len,"Pri %d %d\n", i, (AMAZON_S_REG32(AMAZON_S_SW_1P_PRT)>>(i*2))&0x3); } return len; } /* * \brief This function reads interanl switch mib counters of 3 ports */ int get_all_ports_mib_proc_read (char *buf, char **start, off_t offset, int count, int *eof, void *data){ /*fix me, do I need to implement this?*/ int len=0, i; unsigned int counter; unsigned long long byteCnt; for(i=0; i<3; i++){ len += sprintf(buf+len, "\n\tPort [%d] counters\n\n", i); len += sprintf(buf+len, "Rx Unicast PckCnt :"); counter = amazon_s_switch_get_rmon_counter_value(i,RX_UNICAST_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Broadcast PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_BROADCAST_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Multicast PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_MULTICAST_PCKNT ); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx Unicase PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,TX_UNICAST_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Broadcast PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,TX_BROADCAST_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Multicase PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,TX_MULTICAST_PCKNT ); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx 64B PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_SIZE_64B_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx [65-127B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_SIZE_65_127B_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx [128~255B] PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_SIZE_128_255B_PCKNT ); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx [256~511B] PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_SIZE_256_511B_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx [512~1023B]PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_SIZE_512_1023B_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx [ >1024B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_SIZE_1024B_MAX_PCKNT ); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx [64B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,TX_SIZE_64B_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx [65~127B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,TX_SIZE_65_127B_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx [128~255B] PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (i,TX_SIZE_128_255B_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx [256~511B] PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (i,TX_SIZE_256_511B_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx [512~1023B]PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (i,TX_SIZE_512_1023B_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx [>1024B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,TX_SIZE_1024B_MAX_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx CRC err PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_CRC_ERR_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Unsize err PCkCnt:"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_UNDERSIZE_ERR_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Ovsize err PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_OVER_SIZE_ERR_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx UnsizeGood PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_UNDERSIZE_GOOD_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx OvsizeGood PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_OVER_SIZE_GOOD_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Good Pause PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_GOOD_PAUSE_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx Align err PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_ALLIGN_ERR_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx filterd errPckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_FILTERED_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Single col Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,TX_SINGLE_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx Multiple col Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,TX_MULTIPLE_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Late col Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,TX_LATE_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Excessive col Cnt:"); counter =amazon_s_switch_get_rmon_counter_value (i,TX_EXCESSIVE_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx collision Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,TX_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Pause Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,TX_PAUSE_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx Drop PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,TX_DROP_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Drop PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (i,RX_DROP_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx Good Byte Cnt :"); byteCnt =amazon_s_switch_get_rmon_counter_value (i,RX_GOOD_BYTE_CNT_HIGH); byteCnt <<=32; byteCnt +=amazon_s_switch_get_rmon_counter_value (i,RX_GOOD_BYTE_CNT_LOW); len += sprintf(buf+len, "0x%llx \t",byteCnt); len += sprintf(buf+len, "Tx Good Byte Cnt :"); byteCnt =amazon_s_switch_get_rmon_counter_value (i,TX_GOOD_BYTE_CNT_HIGH); byteCnt <<=32; byteCnt +=amazon_s_switch_get_rmon_counter_value (i,TX_GOOD_BYTE_CNT_LOW); len += sprintf(buf+len, "0x%llx \n",byteCnt); len += sprintf(buf+len, "Rx Bad Byte Cnt :"); byteCnt =amazon_s_switch_get_rmon_counter_value (i,RX_BAD_BYTE_CNT_HIGH); byteCnt <<=32; byteCnt +=amazon_s_switch_get_rmon_counter_value (i,RX_BAD_BYTE_CNT_LOW); len += sprintf(buf+len, "0x%llx \n",byteCnt); } return len; } /* * \brief This function reads interanl switch mib counters of port0 */ int get_port0_mib_proc_read (char *buf, char **start, off_t offset, int count, int *eof, void *data){ /*fix me, do I need to implement this?*/ int len=0; unsigned int counter; unsigned long long byteCnt; len += sprintf(buf+len, "\n\tPort 0 counters\n\n"); len += sprintf(buf+len, "Rx Unicast PckCnt :"); counter = amazon_s_switch_get_rmon_counter_value(0,RX_UNICAST_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Broadcast PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_BROADCAST_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Multicast PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_MULTICAST_PCKNT ); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx Unicase PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,TX_UNICAST_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Broadcast PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,TX_BROADCAST_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Multicase PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,TX_MULTICAST_PCKNT ); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx 64B PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_SIZE_64B_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx [65-127B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_SIZE_65_127B_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx [128~255B] PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_SIZE_128_255B_PCKNT ); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx [256~511B] PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_SIZE_256_511B_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx [512~1023B]PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_SIZE_512_1023B_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx [ >1024B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_SIZE_1024B_MAX_PCKNT ); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx [64B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,TX_SIZE_64B_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx [65~127B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,TX_SIZE_65_127B_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx [128~255B] PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (0,TX_SIZE_128_255B_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx [256~511B] PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (0,TX_SIZE_256_511B_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx [512~1023B]PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (0,TX_SIZE_512_1023B_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx [>1024B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,TX_SIZE_1024B_MAX_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx CRC err PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_CRC_ERR_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Unsize err PCkCnt:"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_UNDERSIZE_ERR_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Ovsize err PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_OVER_SIZE_ERR_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx UnsizeGood PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_UNDERSIZE_GOOD_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx OvsizeGood PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_OVER_SIZE_GOOD_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Good Pause PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_GOOD_PAUSE_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx Align err PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_ALLIGN_ERR_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx filterd errPckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_FILTERED_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Single col Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,TX_SINGLE_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx Multiple col Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,TX_MULTIPLE_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Late col Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,TX_LATE_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Excessive col Cnt:"); counter =amazon_s_switch_get_rmon_counter_value (0,TX_EXCESSIVE_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx collision Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,TX_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Pause Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,TX_PAUSE_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx Drop PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,TX_DROP_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Drop PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (0,RX_DROP_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx Good Byte Cnt :"); byteCnt =amazon_s_switch_get_rmon_counter_value (0,RX_GOOD_BYTE_CNT_HIGH); byteCnt <<=32; byteCnt +=amazon_s_switch_get_rmon_counter_value (0,RX_GOOD_BYTE_CNT_LOW); len += sprintf(buf+len, "0x%llx \t",byteCnt); len += sprintf(buf+len, "Tx Good Byte Cnt :"); byteCnt =amazon_s_switch_get_rmon_counter_value (0,TX_GOOD_BYTE_CNT_HIGH); byteCnt <<=32; byteCnt +=amazon_s_switch_get_rmon_counter_value (0,TX_GOOD_BYTE_CNT_LOW); len += sprintf(buf+len, "0x%llx \n",byteCnt); len += sprintf(buf+len, "Rx Bad Byte Cnt :"); byteCnt =amazon_s_switch_get_rmon_counter_value (0,RX_BAD_BYTE_CNT_HIGH); byteCnt <<=32; byteCnt +=amazon_s_switch_get_rmon_counter_value (0,RX_BAD_BYTE_CNT_LOW); len += sprintf(buf+len, "0x%llx \n",byteCnt); return len; } /* * \brief This function reads interanl switch mib counters of port1 */ int get_port1_mib_proc_read (char *buf, char **start, off_t offset, int count, int *eof, void *data){ /*fix me, do I need to implement this?*/ int len=0; unsigned int counter; unsigned long long byteCnt; len += sprintf(buf+len, "\n\tPort 1 counters\n\n"); len += sprintf(buf+len, "Rx Unicast PckCnt :"); counter = amazon_s_switch_get_rmon_counter_value(1,RX_UNICAST_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Broadcast PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_BROADCAST_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Multicast PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_MULTICAST_PCKNT ); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx Unicase PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,TX_UNICAST_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Broadcast PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,TX_BROADCAST_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Multicase PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,TX_MULTICAST_PCKNT ); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx 64B PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_SIZE_64B_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx [65-127B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_SIZE_65_127B_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx [128~255B] PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_SIZE_128_255B_PCKNT ); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx [256~511B] PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_SIZE_256_511B_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx [512~1023B]PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_SIZE_512_1023B_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx [ >1024B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_SIZE_1024B_MAX_PCKNT ); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx [64B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,TX_SIZE_64B_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx [65~127B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,TX_SIZE_65_127B_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx [128~255B] PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (1,TX_SIZE_128_255B_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx [256~511B] PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (1,TX_SIZE_256_511B_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx [512~1023B]PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (1,TX_SIZE_512_1023B_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx [>1024B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,TX_SIZE_1024B_MAX_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx CRC err PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_CRC_ERR_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Unsize err PCkCnt:"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_UNDERSIZE_ERR_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Ovsize err PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_OVER_SIZE_ERR_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx UnsizeGood PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_UNDERSIZE_GOOD_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx OvsizeGood PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_OVER_SIZE_GOOD_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Good Pause PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_GOOD_PAUSE_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx Align err PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_ALLIGN_ERR_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx filterd errPckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_FILTERED_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Single col Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,TX_SINGLE_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx Multiple col Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,TX_MULTIPLE_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Late col Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,TX_LATE_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Excessive col Cnt:"); counter =amazon_s_switch_get_rmon_counter_value (1,TX_EXCESSIVE_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx collision Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,TX_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Pause Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,TX_PAUSE_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx Drop PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,TX_DROP_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Drop PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (1,RX_DROP_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx Good Byte Cnt :"); byteCnt =amazon_s_switch_get_rmon_counter_value (1,RX_GOOD_BYTE_CNT_HIGH); byteCnt <<=32; byteCnt +=amazon_s_switch_get_rmon_counter_value (1,RX_GOOD_BYTE_CNT_LOW); len += sprintf(buf+len, "0x%llx \t",byteCnt); len += sprintf(buf+len, "Tx Good Byte Cnt :"); byteCnt =amazon_s_switch_get_rmon_counter_value (1,TX_GOOD_BYTE_CNT_HIGH); byteCnt <<=32; byteCnt +=amazon_s_switch_get_rmon_counter_value (1,TX_GOOD_BYTE_CNT_LOW); len += sprintf(buf+len, "0x%llx \n",byteCnt); len += sprintf(buf+len, "Rx Bad Byte Cnt :"); byteCnt =amazon_s_switch_get_rmon_counter_value (1,RX_BAD_BYTE_CNT_HIGH); byteCnt <<=32; byteCnt +=amazon_s_switch_get_rmon_counter_value (1,RX_BAD_BYTE_CNT_LOW); len += sprintf(buf+len, "0x%llx \n",byteCnt); return len; } /* * \brief This function reads interanl switch mib counters of port2 */ int get_port2_mib_proc_read (char *buf, char **start, off_t offset, int count, int *eof, void *data){ /*fix me, do I need to implement this?*/ int len=0; unsigned int counter; unsigned long long byteCnt; len += sprintf(buf+len, "\n\tPort 2 counters\n\n"); len += sprintf(buf+len, "Rx Unicast PckCnt :"); counter = amazon_s_switch_get_rmon_counter_value(2,RX_UNICAST_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Broadcast PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_BROADCAST_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Multicast PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_MULTICAST_PCKNT ); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx Unicase PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,TX_UNICAST_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Broadcast PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,TX_BROADCAST_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Multicase PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,TX_MULTICAST_PCKNT ); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx 64B PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_SIZE_64B_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx [65-127B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_SIZE_65_127B_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx [128~255B] PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_SIZE_128_255B_PCKNT ); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx [256~511B] PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_SIZE_256_511B_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx [512~1023B]PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_SIZE_512_1023B_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx [ >1024B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_SIZE_1024B_MAX_PCKNT ); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx [64B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,TX_SIZE_64B_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx [65~127B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,TX_SIZE_65_127B_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx [128~255B] PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (2,TX_SIZE_128_255B_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx [256~511B] PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (2,TX_SIZE_256_511B_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx [512~1023B]PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (2,TX_SIZE_512_1023B_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx [>1024B] PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,TX_SIZE_1024B_MAX_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx CRC err PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_CRC_ERR_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Unsize err PCkCnt:"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_UNDERSIZE_ERR_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Ovsize err PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_OVER_SIZE_ERR_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx UnsizeGood PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_UNDERSIZE_GOOD_PCKNT ); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx OvsizeGood PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_OVER_SIZE_GOOD_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Good Pause PckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_GOOD_PAUSE_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx Align err PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_ALLIGN_ERR_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx filterd errPckCnt:"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_FILTERED_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Single col Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,TX_SINGLE_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx Multiple col Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,TX_MULTIPLE_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Late col Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,TX_LATE_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Excessive col Cnt:"); counter =amazon_s_switch_get_rmon_counter_value (2,TX_EXCESSIVE_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx collision Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,TX_COLLISION_CNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Tx Pause Cnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,TX_PAUSE_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Tx Drop PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,TX_DROP_PCKNT); len += sprintf(buf+len, "0x%08x\t",counter ); len += sprintf(buf+len, "Rx Drop PckCnt :"); counter =amazon_s_switch_get_rmon_counter_value (2,RX_DROP_PCKNT); len += sprintf(buf+len, "0x%08x\n",counter ); len += sprintf(buf+len, "Rx Good Byte Cnt :"); byteCnt =amazon_s_switch_get_rmon_counter_value (2,RX_GOOD_BYTE_CNT_HIGH); byteCnt <<=32; byteCnt +=amazon_s_switch_get_rmon_counter_value (2,RX_GOOD_BYTE_CNT_LOW); len += sprintf(buf+len, "0x%llx \t",byteCnt); len += sprintf(buf+len, "Tx Good Byte Cnt :"); byteCnt =amazon_s_switch_get_rmon_counter_value (2,TX_GOOD_BYTE_CNT_HIGH); byteCnt <<=32; byteCnt +=amazon_s_switch_get_rmon_counter_value (2,TX_GOOD_BYTE_CNT_LOW); len += sprintf(buf+len, "0x%llx \n",byteCnt); len += sprintf(buf+len, "Rx Bad Byte Cnt :"); byteCnt =amazon_s_switch_get_rmon_counter_value (2,RX_BAD_BYTE_CNT_HIGH); byteCnt <<=32; byteCnt +=amazon_s_switch_get_rmon_counter_value (2,RX_BAD_BYTE_CNT_LOW); len += sprintf(buf+len, "0x%llx \n",byteCnt); return len; } /* * \brief This function clear the interanl switch all mib counters */ int clr_all_ports_mib_proc_read (char *buf, char **start, off_t offset, int count, int *eof, void *data){ amazon_s_switch_clr_rmon(); return IFX_SUCCESS; } /* * \brief This function clear the interanl switch port0 mib counters */ int clr_port0_mib_proc_read (char *buf, char **start, off_t offset, int count, int *eof, void *data){ amazon_s_switch_clr_rmon_by_port(0); return IFX_SUCCESS; } /* * \brief This function clear the interanl switch port1 mib counters */ int clr_port1_mib_proc_read (char *buf, char **start, off_t offset, int count, int *eof, void *data){ amazon_s_switch_clr_rmon_by_port(1); return IFX_SUCCESS; } /* * \brief This function clear the interanl switch port2 mib counters */ int clr_port2_mib_proc_read (char *buf, char **start, off_t offset, int count, int *eof, void *data){ amazon_s_switch_clr_rmon_by_port(2); return IFX_SUCCESS; } int switch_rx(struct net_device *dev, int len,struct sk_buff* skb){ x_IFX_switch_priv_t *priv = (x_IFX_switch_priv_t *) dev->priv; skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); /* printk("%s: skb->protocol:%08x\n", __FUNCTION__, skb->protocol); */ #if defined(ENABLE_NAPI) && ENABLE_NAPI netif_receive_skb(skb); #else netif_rx(skb); #endif priv->stats.rx_packets++; priv->stats.rx_bytes+=len; /* printk("packet %d\n",priv->stats.rx_packets); */ return OK; } /* * \brief This function triggers when get the DMA RCV_INT interrupt. * \param [in] dma_dev structure dma device info * \return On Success return skb length IFX_ERROR */ int switch_hw_receive(struct dma_device_info* dma_dev){ u8* buf=NULL; int len=0 ; struct sk_buff *skb=NULL; struct net_device *dev; #if defined( LOOPBACK_TEST) && LOOPBACK_TEST struct ethhdr *eth; unsigned char temp[6]; #endif len=dma_device_read(dma_dev,&buf,(void**)&skb); //TRACE("DMA rx len:%d\n",len); if (len >= 0x600){ TRACE("packet too large %d\n",len); goto switch_hw_receive_err_exit; } if ((skb == NULL) || (len < 64)){ TRACE("cannot restore pointer or packet too small\n"); goto switch_hw_receive_err_exit; } /* remove CRC */ len -= 4; if (len > (skb->end -skb->tail)){ TRACE("BUG, len:%d end:%p tail:%p\n", (len+4), skb->end, skb->tail); printk("BUG, len:%d end:%p tail:%p\n", (len+4), skb->end, skb->tail); goto switch_hw_receive_err_exit; } skb_put(skb,len); if(g_pmac_dma){ int sourcePortId;; len -= 8; /*Remove PMAC to DMA header */ skb_pull(skb,8); eg_pkt_hdr = * ((x_IFX_cpu_egress_pkt_header_t *) (buf+2)); sourcePortId =(eg_pkt_hdr.srcPortID) & 0x7 ; if(sourcePortId < AMAZON_S_SW_INT_NO) { switch(sourcePortId) { case 0: dev=switch_devs[0]; break; case 1: dev=switch_devs[1]; break; case 2: dev=switch_devs[2]; break; case 3: dev=switch_devs[3]; break; case 4: dev=switch_devs[4]; break; case 5: dev=switch_devs[5]; break; case 6: dev=switch_devs[6]; break; case 7: dev=switch_devs[7]; break; default: /* printk("%s[%d], spid:%d ERROR!!! \n", __FUNCTION__, __LINE__,(eg_pkt_hdr.srcPortID) & 0x7); */ goto switch_hw_receive_err_exit; } } else{ /* printk("%s[%d], spid:%d Packet dropped!!! \n", __FUNCTION__, __LINE__,(eg_pkt_hdr.srcPortID) & 0x7); */ goto switch_hw_receive_err_exit; /* dev=switch_devs[0]; */ /*default */ } } /*g_pmac_dma*/ else dev=switch_devs[0]; skb->dev = dev; if (buf){ #ifdef AMAZON_S_SW_DUMP printk("rx:\n"); dump_skb(len, (char *)buf); #endif } #if defined( LOOPBACK_TEST) && LOOPBACK_TEST //swap src and des mac address #if 1 eth = (struct ethhdr *) (skb->data); memcpy (temp, eth->h_source, 6); memcpy (eth->h_source, eth->h_dest, 6); memcpy (eth->h_dest, temp, 6); #endif switch_tx (skb, dev); #else len=switch_rx(dev,len,skb); #endif //LOOPBACK_TEST return OK; switch_hw_receive_err_exit: if (buf){ #ifdef AMAZON_S_SW_DUMP dump_skb(len, (char *)buf); #endif } #if defined( LOOPBACK_TEST) && LOOPBACK_TEST unsigned long flag; local_irq_save(flag); if(skb) dev_kfree_skb (skb); local_irq_restore(flag); #else if (skb) dev_kfree_skb_any(skb); #endif return len; } int switch_hw_tx(char *buf, int len, struct net_device *dev){ int ret=0; /* unsigned long flag; */ x_IFX_switch_priv_t *priv=dev->priv; struct dma_device_info* dma_dev=g_dma_device; /* local_irq_save(flag); */ ret=dma_device_write(dma_dev,buf,len, priv->skb); /* local_irq_restore(flag); */ return ret; } int select_tx_chan(struct sk_buff *skb, struct net_device *dev){ int chan=0; /*TODO: select the channel based on some criteria*/ return chan; } int switch_tx(struct sk_buff *skb, struct net_device *dev){ int len, tx_flag =0; char *data; x_IFX_switch_priv_t *priv=dev->priv; struct dma_device_info* dma_dev=g_dma_device; /* printk("%s: Start", __FUNCTION__); */ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; if(g_dma_pmac) { memset((void *) &ig_pkt_hdr, 0, sizeof (ig_pkt_hdr)); /*if DIRECT is set 1, then packet is directly forward to the physical port based on DPID (no learning), if DIRECT is set 0, then switch will learn and decide forward the packet to which physical port */ #ifdef CONFIG_SW_ROUTING_MODE ig_pkt_hdr.DIRECT= 1; #else ig_pkt_hdr.DIRECT= 0; #endif if(!(strcmp(dev->name, "eth0"))) { #if defined( LOOPBACK_TEST) && LOOPBACK_TEST ig_pkt_hdr.SPID= 2; ig_pkt_hdr.DPID= 1; /*Packet send thorugh MII1 interface in loopback mode, valid only when DIRECT is set 1*/ #else ig_pkt_hdr.SPID= 2; /*CPU port */ ig_pkt_hdr.DPID= 0; /*Packet send through MII0 interface, valid only when DIRECT is set 1 */ #endif } else if(!(strcmp(dev->name, "eth1"))) { #if defined( LOOPBACK_TEST) && LOOPBACK_TEST ig_pkt_hdr.SPID= 2; ig_pkt_hdr.DPID= 0; /*Packet send though MII0 interface in loopback mode, valid only when DIRECT is set 1*/ #else ig_pkt_hdr.SPID= 2; /*CPU port */ ig_pkt_hdr.DPID= 1; /* Send packet through MII1 interface, valid only when DIRECT is set 1 */ #endif /* printk("%s[%d], eth1 \n",__FUNCTION__, __LINE__); */ } else { /*if eth1 interface is not there, then send through eth0 */ printk("%s[%d], Default eth0 \n",__FUNCTION__, __LINE__); ig_pkt_hdr.SPID= 2; ig_pkt_hdr.DPID= 0; /*Packet send through MII0 interface, valid only when DIRECT is set 1 */ } if(skb_headroom(skb)>=4){ /* printk("%s[%d]: [%d] \n",__FUNCTION__,__LINE__,skb_headroom(skb)); */ skb_push(skb,4); memcpy(skb->data, (void*)&ig_pkt_hdr, 4); len+=4; tx_flag=0; } else { struct sk_buff *tmp = skb; skb = skb_realloc_headroom(tmp, 4); // dev_kfree_skb(tmp); #if defined( LOOPBACK_TEST) && LOOPBACK_TEST unsigned long flag; local_irq_save(flag); if(tmp) dev_kfree_skb (tmp); local_irq_restore(flag); #else if(tmp) dev_kfree_skb_any(tmp); #endif //LOOPBACK_TEST if (skb == NULL) { printk("%s skb_realloc_headroom failed\n", __func__); return -ENOMEM; } skb_push(skb, 4); memcpy(skb->data, &ig_pkt_hdr, 4); len += 4; g_skb_headroom++; } } /*g_dma_pmac*/ data = skb->data; priv->skb = skb; dev->trans_start = jiffies; dma_dev->current_tx_chan=select_tx_chan(skb, dev);/*select the tx channel*/ //printk("switch tx\n"); g_transmit++; if ( switch_hw_tx(data, len, dev)!= len){ #if defined( LOOPBACK_TEST) && LOOPBACK_TEST unsigned long flag; local_irq_save(flag); if(skb) dev_kfree_skb (skb); local_irq_restore(flag); #else if(skb) dev_kfree_skb_any(skb); #endif //LOOPBACK_TEST priv->stats.tx_errors++; priv->stats.tx_dropped++; } else{ priv->stats.tx_packets++; priv->stats.tx_bytes+=len; } return OK; } void switch_tx_timeout (struct net_device *dev){ int i; x_IFX_switch_priv_t *priv=dev->priv; struct dma_device_info* dma_dev=g_dma_device; printk("%s[%d]:device name: %s\n",__func__,__LINE__,dev->name); //TODO:must restart the TX channels priv->stats.tx_errors++; for(i=0;imax_tx_chan_num;i++) { dma_dev->tx_chan[i]->disable_irq(dma_dev->tx_chan[i]); } #if 0 for(i=0; i < AMAZON_S_SW_INT_NO; i++) { dev = switch_devs[i]; netif_wake_queue(dev); } #else netif_wake_queue(dev); #endif return; } int dma_intr_handler(struct dma_device_info* dma_dev,int status){ struct net_device* dev; int i; //TRACE("status:%d \n", status); switch(status) { case RCV_INT: //TRACE("switch receive chan=%d\n",dma_dev->current_rx_chan); switch_hw_receive(dma_dev); break; case TX_BUF_FULL_INT: TRACE("tx buffer full\n"); //printk("tx buffer full\n"); for(i=0; i < AMAZON_S_SW_INT_NO; i++){ dev = switch_devs[i]; netif_stop_queue(dev); } for(i=0;imax_tx_chan_num;i++) { if((dma_dev->tx_chan[i])->control==AMAZON_S_DMA_CH_ON) dma_dev->tx_chan[i]->enable_irq(dma_dev->tx_chan[i]); } break; case TRANSMIT_CPT_INT: TRACE("tx buffer released\n"); //printk("tx buffer released\n"); for(i=0;imax_tx_chan_num;i++) { dma_dev->tx_chan[i]->disable_irq(dma_dev->tx_chan[i]); } for(i=0; i < AMAZON_S_SW_INT_NO; i++){ dev = switch_devs[i]; netif_wake_queue(dev); } break; } return OK; } /* reserve 2 bytes in front of data pointer*/ u8* etop_dma_buffer_alloc(int len, int* byte_offset,void** opt){ u8* buffer=NULL; struct sk_buff *skb=NULL; skb = dev_alloc_skb(ETHERNET_PACKET_DMA_BUFFER_SIZE); if (skb == NULL) { printk("%s[%d]: buffer allocation failed!!! \n",__FUNCTION__,__LINE__); return NULL; } if (DMA_RX_BURST_LEN == 8 ) { buffer=(u8*)(skb->data); if( buffer && 0x10 ) { skb->data = buffer+16; buffer=(u8*)(skb->data); } } else { buffer=(u8*)(skb->data); } skb_reserve(skb, 2); TRACE("%8p\n",skb->data); *(int*)opt=(int)skb; *byte_offset=2; return buffer; } int etop_dma_buffer_free(u8* dataptr,void* opt){ struct sk_buff *skb=NULL; if(opt==NULL){ if(dataptr) kfree(dataptr); }else { skb=(struct sk_buff*)opt; #if defined( LOOPBACK_TEST) && LOOPBACK_TEST unsigned long flag; local_irq_save(flag); if(skb) dev_kfree_skb (skb); local_irq_restore(flag); #else if(skb) dev_kfree_skb_any(skb); #endif //LOOPBACK_TEST } return OK; } static int set_mac(struct net_device *dev,u16 speed,u8 duplex,u8 autoneg){ int ret; int dev_num = (!strcmp(dev->name, "eth0") ? 0 : 1); if(autoneg==AUTONEG_ENABLE) { /*set property and start autonegotiation*/ /*have to set mdio advertisement register and restart autonegotiation*/ /*which is a very rare case, put it to future development if necessary.*/ ret=IFX_SUCCESS; } else /*autoneg==AUTONEG_DISABLE or -1*/ { #if 0 /*TO DO*/ /*set property without autonegotiation*/ /*set speed*/ /* Disable MDIO (p2.10) & MDC (p2.11) signals*/ /*p2.10 & p2.11 Normal GPIO mode*/ IFX_SWITCH_ALTSEL0_CLR(SWITCH_MDIO); IFX_SWITCH_ALTSEL1_CLR(SWITCH_MDIO); IFX_SWITCH_OD_SET(SWITCH_MDIO); IFX_SWITCH_ALTSEL0_CLR(SWITCH_MDC); IFX_SWITCH_ALTSEL1_CLR(SWITCH_MDC); IFX_SWITCH_OD_SET(SWITCH_MDC); #endif #if defined( CONFIG_MII0) && CONFIG_MII0 if(dev_num == 0) { if(speed==SPEED_10) AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= ~0xc; else if(speed==SPEED_100) { AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= ~0xc; AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= 0x4 ; } else if(speed == SPEED_1000) { AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= ~0xc; AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= 0x8 ; } /*set duplex*/ if(duplex==DUPLEX_HALF) AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= ~0x2 ; else if(duplex == DUPLEX_FULL) AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= 0x2 ; AMAZON_S_REG32(AMAZON_S_SW_P0_CTL) |= 0x40001 ; } #endif /*CONFIG_MII0*/ #if defined( CONFIG_MII1) && CONFIG_MII1 if (dev_num == 1 ) { if(speed==SPEED_10) AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= ~0x3000; else if(speed==SPEED_100) { AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= ~0x3000; AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= 0x1000 ; } else if(speed == SPEED_1000) { AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= ~0x3000; AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= 0x2000 ; } /*set duplex*/ if(duplex==DUPLEX_HALF) AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= ~0x800 ; else if(duplex == DUPLEX_FULL) AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= 0x800 ; AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) |= 0x40001 ; } #endif /*CONFIG_MII1*/ ret=IFX_SUCCESS; } return ret; } #if defined(ENABLE_NAPI) && ENABLE_NAPI static int switch_poll(struct net_device *poll_dev, int *budget){ int ret; int work_to_do, work_done; struct dma_device_info* dma_dev=g_dma_device; TRACE("%s: \n", __FUNCTION__); /* printk("%s: device name: %s \n", __FUNCTION__,poll_dev->name); */ work_to_do = min(*budget, poll_dev->quota); work_done = 0; ret = dma_device_poll(dma_dev, work_to_do, &work_done); *budget -= work_done; poll_dev->quota -= work_done; return ret; } static void switch_activate_poll(struct dma_device_info* dma_dev){ struct net_device *dev; int i; for(i=0; i < AMAZON_S_SW_INT_NO; i++) { dev = switch_devs[i]; if ( netif_rx_schedule_prep(dev) ) __netif_rx_schedule(dev); } } static void switch_inactivate_poll(struct dma_device_info* dma_dev){ struct net_device *dev; int i; for(i=0; i < AMAZON_S_SW_INT_NO; i++) { dev = switch_devs[i]; if(netif_running(dev) ) netif_rx_complete(dev); } } #endif static int switch_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr){ int ret=IFX_SUCCESS; struct ethtool_cmd ecmd; int dev_num = (!strcmp(dev->name, "eth0") ? 0 : 1); x_IFX_switch_priv_t* priv=(x_IFX_switch_priv_t*)dev->priv; if (copy_from_user(&ecmd, ifr->ifr_data, sizeof (ecmd))) return -EFAULT; switch (ecmd.cmd) { case ETHTOOL_GSET:/*get hardware information*/{ u32 ps_status; memset((void *) &ecmd, 0, sizeof (ecmd)); ecmd.supported = SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full| SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full; ecmd.port = PORT_MII; ecmd.transceiver = XCVR_EXTERNAL; // ecmd.phy_address = priv->mdio_phy_addr; ps_status= AMAZON_S_REG32(AMAZON_S_SW_PS); #if defined( CONFIG_MII0) && CONFIG_MII0 if(dev_num == 0) /*interface eth0 (MII0)*/{ switch((ps_status >> 0x1) & 0x3) /*Bit 2~1 */{ case 0: priv->current_speed=SPEED_10; break; case 1: priv->current_speed=SPEED_100; break; case 2: priv->current_speed=SPEED_1000; break; default: printk("%s[%d]: Error!!! ps-Status:0x%08x",__FUNCTION__,__LINE__,ps_status); } ecmd.speed = priv->current_speed; if (ps_status & 0x8 ) priv->full_duplex=DUPLEX_FULL; else priv->full_duplex=DUPLEX_HALF; ecmd.duplex = priv->full_duplex; if (ps_status & 0x1 ) ecmd.reserved[0]=0x1; /* link up Bit0:1*/ else ecmd.reserved[0]=0x0; /*link down*/ if (ps_status & 0x10 ) ecmd.reserved[0] |=0x2; /*flow control enable Bit1:1*/ else ecmd.reserved[0] |= 0x0; /*flow control disable*/ ecmd.phy_address = PHY0_ADDR; } #endif /* CONFIG_MII0*/ #if defined( CONFIG_MII1) && CONFIG_MII1 if(dev_num == 1) /*Interface eth1 (MII1) */{ switch( (ps_status>>9) & 0x3){ case 0: priv->current_speed=SPEED_10; break; case 1: priv->current_speed=SPEED_100; break; case 2: priv->current_speed=SPEED_1000; break; default: printk("%s[%d]: Error!!! Ps-Status:0x%08x",__FUNCTION__,__LINE__,ps_status); } ecmd.speed = priv->current_speed; if (ps_status & 0x800 ) priv->full_duplex=DUPLEX_FULL; else priv->full_duplex=DUPLEX_HALF; ecmd.duplex = priv->full_duplex; if (ps_status & 0x100 ) ecmd.reserved[0]=0x1; /*link up bit:0*/ else ecmd.reserved[0]=0x0; /*link down */ if (ps_status & 0x1000 ) ecmd.reserved[0] |=0x2; /*flow control enable Bit1:1*/ else ecmd.reserved[0] |= 0x0; /*flow control disable*/ ecmd.phy_address = PHY1_ADDR; } #endif /*CONFIG_MII1*/ /* ecmd.speed =priv->current_speed; ecmd.duplex = priv->full_duplex; */ if (copy_to_user(ifr->ifr_data, &ecmd, sizeof (ecmd))) return -EFAULT; ret=IFX_SUCCESS; } break; case ETHTOOL_SSET:/*force the speed and duplex mode*/{ if (!capable(CAP_NET_ADMIN)) { return -EPERM; } ret=set_mac(dev,ecmd.speed,ecmd.duplex,ecmd.autoneg); } break; case ETHTOOL_GDRVINFO:/*get driver information*/{ struct ethtool_drvinfo info; memset((void *) &info, 0, sizeof (info)); strncpy(info.driver, "AMAZON_S_SW SWITCH DRIVER", sizeof(info.driver) - 1); // strncpy(info.fw_version, "0.0.1", sizeof(info.fw_version) - 1); strncpy(info.fw_version, "1.0.0", sizeof(info.fw_version) - 1); strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1); info.regdump_len = 0; info.eedump_len = 0; info.testinfo_len = 0; if (copy_to_user(ifr->ifr_data, &info, sizeof (info))) return -EFAULT; ret=IFX_SUCCESS; } break; case ETHTOOL_NWAY_RST:/*restart auto negotiation*/ /* MDIO (p2.10) & MDC (p2.11) */ IFX_SWITCH_ALTSEL0_SET(SWITCH_MDIO); IFX_SWITCH_ALTSEL1_CLR(SWITCH_MDIO); IFX_SWITCH_OD_SET(SWITCH_MDIO); IFX_SWITCH_ALTSEL0_SET(SWITCH_MDC); IFX_SWITCH_ALTSEL1_CLR(SWITCH_MDC); IFX_SWITCH_OD_SET(SWITCH_MDC); ret=IFX_SUCCESS; break; default: return -EOPNOTSUPP; break; } return ret; } int set_vlan_cos(x_IFX_vlan_cos_req* vlan_cos_req){ u32 pri=vlan_cos_req->pri; u32 cos_value=vlan_cos_req->cos_value; u32 value; value=AMAZON_S_REG32(AMAZON_S_SW_1P_PRT)&~(3<<(pri*2)); AMAZON_S_REG32(AMAZON_S_SW_1P_PRT) =value|(cos_value<<(pri*2)); return IFX_SUCCESS;/*cannot fail*/ } int set_dscp_cos(x_IFX_dscp_cos_req* dscp_cos_req){ u32 dscp=dscp_cos_req->dscp; u32 cos_value=dscp_cos_req->cos_value; (AMAZON_S_REG32(AMAZON_S_SW_DFSRV_MAP0+dscp/16*4)) |= cos_value << dscp%16*2 ; return IFX_SUCCESS; } /** * \fn int switch_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief ioctl interface * \param dev pointer to a structure net_device * \param ifr pointer to a structure ifreq * \param cmd device specific commands * \return On Success return success otherwise error code */ int switch_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){ int result=IFX_SUCCESS; int port_offset = !(strcmp(dev->name, "eth0")) ? 0 : 1; x_IFX_vlan_cos_req etop_vlan_cos_req; x_IFX_dscp_cos_req etop_dscp_cos_req; switch(cmd){ case SIOCETHTOOL: switch_ethtool_ioctl(dev,ifr); break; case IFX_SET_VLAN_COS: copy_from_user(&etop_vlan_cos_req,\ (x_IFX_vlan_cos_req*)ifr->ifr_data,sizeof(x_IFX_vlan_cos_req)); set_vlan_cos(&etop_vlan_cos_req); break; case IFX_SET_DSCP_COS: copy_from_user(&etop_dscp_cos_req,\ (x_IFX_dscp_cos_req*)ifr->ifr_data,sizeof(x_IFX_dscp_cos_req)); set_dscp_cos(&etop_dscp_cos_req); break; case IFX_ENABLE_VLAN_CLASSIFICATION: if(port_offset) AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) |= (1<<27); /*port 1*/ else AMAZON_S_REG32(AMAZON_S_SW_P0_CTL) |= (1<<27); /*port 0*/ break; case IFX_DISABLE_VLAN_CLASSIFICATION: if(port_offset) AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) &= ~(1<<27); /*port 1*/ else AMAZON_S_REG32(AMAZON_S_SW_P0_CTL) &= ~(1<<27); /*port 0*/ break; case IFX_ENABLE_DSCP_CLASSIFICATION: if(port_offset) AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) |= (1<<26); /*port 1*/ else AMAZON_S_REG32(AMAZON_S_SW_P0_CTL) |= (1<<26); /*port 0*/ break; case IFX_DISABLE_DSCP_CLASSIFICATION: if(port_offset) AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) &= ~(1<<26); /*port 1*/ else AMAZON_S_REG32(AMAZON_S_SW_P0_CTL) &= ~(1<<26); /*port 0*/ break; case IFX_VLAN_CLASS_FIRST: break; case IFX_VLAN_CLASS_SECOND: break; case IFX_PASS_UNICAST_PACKETS: if(port_offset) AMAZON_S_REG32(AMAZON_S_SW_DF_PORTMAP) |= (1<<25); /*port 1*/ else AMAZON_S_REG32(AMAZON_S_SW_DF_PORTMAP) |= (1<<24); /*port 0*/ break; case IFX_FILTER_UNICAST_PACKETS: if(port_offset) AMAZON_S_REG32(AMAZON_S_SW_DF_PORTMAP) &= ~(1<<25); /*port 1*/ else AMAZON_S_REG32(AMAZON_S_SW_DF_PORTMAP) &= ~(1<<24); /*port 0*/ break; case IFX_KEEP_BROADCAST_PACKETS: if(port_offset) AMAZON_S_REG32(AMAZON_S_SW_DF_PORTMAP) |= (1<<17); /*port 1*/ else AMAZON_S_REG32(AMAZON_S_SW_DF_PORTMAP) |= (1<<16); /*port 0*/ break; case IFX_DROP_BROADCAST_PACKETS: if(port_offset) AMAZON_S_REG32(AMAZON_S_SW_DF_PORTMAP) &= ~(1<<17); /*port 1*/ else AMAZON_S_REG32(AMAZON_S_SW_DF_PORTMAP) &= ~(1<<16); /*port 0*/ break; case IFX_KEEP_MULTICAST_PACKETS: if(port_offset) AMAZON_S_REG32(AMAZON_S_SW_DF_PORTMAP) |= (1<<9); /*port 1*/ else AMAZON_S_REG32(AMAZON_S_SW_DF_PORTMAP) |= (1<<8); /*port 0*/ break; case IFX_DROP_MULTICAST_PACKETS: if(port_offset) AMAZON_S_REG32(AMAZON_S_SW_DF_PORTMAP) &= ~(1<<9); /*port 1*/ else AMAZON_S_REG32(AMAZON_S_SW_DF_PORTMAP) &= ~(1<<8); /*port 0*/ break; } return result; } /** * \fn static struct net_device_stats *amazon_s_get_stats(struct net_device *dev) * \ingroup AMAZON_S_SWITCH_FUNCTIONS * \brief get device stats * \param dev pointer to a structure net_device * \return net device stats */ static struct net_device_stats *amazon_s_get_stats(struct net_device *dev){ return (struct net_device_stats *)dev->priv; } int misc_counter_proc_read(char *buf, char **start, off_t offset, int count, int *eof, void *data){ int len=0, en; len+=sprintf(buf+len,"Received from protocol stack:0x%08x\n",g_transmit); len+=sprintf(buf+len,"Skb head room is not sufficient :0x%08x \n",g_skb_headroom); en = amazon_s_switch_get_logical_port_status(); len+=sprintf(buf+len,"Logical Port:%s\n",(en==1)?"Enabled":"Disabled"); en = amazon_s_switch_get_headerstatus_pmactodma(); len+=sprintf(buf+len,"PMAC to DMA header:%s\n",(en==1)?"Enabled":"Disabled"); en = amazon_s_switch_get_headerstatus_dmatopmac(); len+=sprintf(buf+len,"DMA to PMAC header:%s\n",(en==1)?"Enabled":"Disabled"); en = amazon_s_switch_get_portingress_directforwarding(0); len+=sprintf(buf+len,"Port 0 Ingress direct forward :%s\n",(en==1)?"Enabled":"Disabled"); en = amazon_s_switch_get_portingress_directforwarding(1); len+=sprintf(buf+len,"Port 1 Ingress direct forward :%s\n",(en==1)?"Enabled":"Disabled"); en = amazon_s_switch_get_portegress_redirect(0); len+=sprintf(buf+len,"Port 0 Egress Redirect :%s\n",(en==1)?"Enabled":"Disabled"); en = amazon_s_switch_get_portegress_redirect(1); len+=sprintf(buf+len,"Port 1 Egress Redirect :%s\n",(en==1)?"Enabled":"Disabled"); return len; } int ingress_en_proc_read(char *buf, char **start, off_t offset, int count, int *eof, void *data){ int len=0; amazon_s_switch_set_portingress_directforwarding(0, 1); /*Port 0 */ amazon_s_switch_set_portingress_directforwarding(1, 1); /*Port 1 */ return len; } int ingress_dis_proc_read(char *buf, char **start, off_t offset, int count, int *eof, void *data){ int len=0; amazon_s_switch_set_portingress_directforwarding(0, 0); /*Port 0 */ amazon_s_switch_set_portingress_directforwarding(1, 0); /*Port 1 */ return len; } int egress_en_proc_read(char *buf, char **start, off_t offset, int count, int *eof, void *data){ int len=0; amazon_s_switch_set_portegress_redirect(0, 1); amazon_s_switch_set_portegress_redirect(1, 1); return len; } int egress_dis_proc_read(char *buf, char **start, off_t offset, int count, int *eof, void *data){ int len=0; amazon_s_switch_set_portegress_redirect(0, 0); amazon_s_switch_set_portegress_redirect(1, 0); return len; } #if 0 unsigned long reg_buf1[120]; int switch_reset_proc_read(char *buf, char **start, off_t offset, int count, int *eof, void *data){ int len=0,i; len+=sprintf(buf+len,"Re configure reg Done\n"); for(i=0;i<120; i++) AMAZON_S_REG32(AMAZON_S_SW + (i *4))= reg_buf1[i]; /*TODO: add the register value here, if the user does not want to use the mem application*/ return len; } #endif static int stricmp(const char *p1, const char *p2) { int c1, c2; while ( *p1 && *p2 ) { c1 = *p1 >= 'A' && *p1 <= 'Z' ? *p1 + 'a' - 'A' : *p1; c2 = *p2 >= 'A' && *p2 <= 'Z' ? *p2 + 'a' - 'A' : *p2; if ( (c1 -= c2) ) return c1; p1++; p2++; } return *p1 - *p2; } static int get_token(char **p1, char **p2, int *len, int *colon) { int tlen = 0; while ( *len && !((**p1 >= 'A' && **p1 <= 'Z') || (**p1 >= 'a' && **p1<= 'z') || (**p1 >= '0' && **p1<= '9')) ) { (*p1)++; (*len)--; } if ( !*len ) return 0; if ( *colon ) { *colon = 0; *p2 = *p1; while ( *len && **p2 > ' ' && **p2 != ',' ) { if ( **p2 == ':' ) { *colon = 1; break; } (*p2)++; (*len)--; tlen++; } **p2 = 0; } else { *p2 = *p1; while ( *len && **p2 > ' ' && **p2 != ',' ) { (*p2)++; (*len)--; tlen++; } **p2 = 0; } return tlen; } u16 ar9_smi_reg_read(u16 reg); u16 ar9_smi_reg_write(u16 reg, u16 data); static int proc_read_flowcontrol(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0; u16 value; value = ar9_smi_reg_read(0x00f5); if ( value == 0x0BBB ) len += sprintf(page + off + len, "external tantos flow control: enable\n"); else if ( value == 0x0AAA ) len += sprintf(page + off + len, "external tantos flow control: disable\n"); else len += sprintf(page + off + len, "external tantos flow control: value = 0x%04x\n", (u32)value); len += sprintf(page + off + len, (AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) & 1) ? "MII0 flow control: enable\n" : "MII0 flow control: disable\n"); len += sprintf(page + off + len, (AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) & (1 << 10)) ? "MII1 flow control: enable\n" : "MII0 flow control: disable\n"); *eof = 1; return len; } static int proc_write_flowcontrol(struct file *file, const char *buf, unsigned long count, void *data) { char local_buf[2048]; int len; char *p1, *p2; int colon = 0; int f_enable = 0; int flag = 0; len = sizeof(local_buf) < count ? sizeof(local_buf) - 1 : count; len = len - copy_from_user(local_buf, buf, len); local_buf[len] = 0; p1 = local_buf; while ( get_token(&p1, &p2, &len, &colon) ) { if ( stricmp(p1, "enable") == 0 ) f_enable = 1; else if ( stricmp(p1, "disable") == 0 ) f_enable = -1; else if ( stricmp(p1, "help") == 0 || strcmp(p1, "?") == 0 ) { f_enable = 0; flag = 0; break; } else if ( f_enable ) { if ( stricmp(p1, "sw") == 0 || stricmp(p1, "tantos") == 0 || stricmp(p1, "external") == 0 || stricmp(p1, "ext") == 0 ) flag = (flag & ~3) | (f_enable > 0 ? 3 : 2); else if ( stricmp(p1, "eth0") == 0 || stricmp(p1, "mii0") == 0 ) flag = (flag & ~(3 << 2)) | ((f_enable > 0 ? 3 : 2) << 2); else if ( stricmp(p1, "eth1") == 0 || stricmp(p1, "mii1") == 0 ) flag = (flag & ~(3 << 4)) | ((f_enable > 0 ? 3 : 2) << 4); } p1 = p2; } if ( !flag && f_enable ) flag = f_enable > 0 ? 0x3F : 0x2A; if ( (flag & 3) ) { if ( (flag & 1) ) ar9_smi_reg_write(0x00f5, 0x0bbb); else ar9_smi_reg_write(0x00f5, 0x0aaa); } if ( (flag & (3 << 2)) ) { if ( (flag & (1 << 2)) ) //AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= 1; amazon_s_switch_enable_fc(0); else //AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= ~1; amazon_s_switch_disable_fc(0); } if ( (flag & (3 << 4)) ) { if ( (flag & (1 << 4)) ) //AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= 1 << 10; amazon_s_switch_enable_fc(1); else //AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= ~(1 << 10); amazon_s_switch_disable_fc(1); } if ( !flag ) printk("echo [sw/mii0/mii1] > /proc/eth/flowcontrol\n"); return count; } struct net_device_stats *switch_stats(struct net_device *dev){ x_IFX_switch_priv_t *priv = (x_IFX_switch_priv_t *) dev->priv; return &priv->stats; } #define MDIO_OP_READ 2 << 10 #define MDIO_OP_WRITE 1 << 10 #define TANTOS_CHIP_ID 0x2599 u16 ar9_smi_reg_read(u16 reg){ while((AMAZON_S_REG32(AMAZON_S_SW_MDIO_CTL) & 0x8000)==0x8000); AMAZON_S_REG32(AMAZON_S_SW_MDIO_CTL) = (MDIO_OP_READ | (reg&0x3ff)|0x8000) ; udelay(500); while((AMAZON_S_REG32(AMAZON_S_SW_MDIO_CTL) & 0x8000)==0x8000); return((u16) (AMAZON_S_REG32(AMAZON_S_SW_MDIO_DATA))); } u16 ar9_smi_reg_write(u16 reg, u16 data){ while((AMAZON_S_REG32(AMAZON_S_SW_MDIO_CTL) & 0x8000)==0x8000); AMAZON_S_REG32(AMAZON_S_SW_MDIO_CTL) = ((data<<16) | MDIO_OP_WRITE | (reg&0x3ff)|0x8000) ; udelay(500); while((AMAZON_S_REG32(AMAZON_S_SW_MDIO_CTL) & 0x8000)==0x8000); return 0; } /* * \brief This function init the externl tantos switch * \param: none * \return: none */ int tantos_switch_init(void){ u16 chipid, readData; if(init_done) /*avoid multiple calls */ return IFX_SUCCESS; IFX_SWITCH_PIN_RESERVE(SWITCH_MDIO); IFX_SWITCH_ALTSEL0_SET(SWITCH_MDIO); IFX_SWITCH_ALTSEL1_CLR(SWITCH_MDIO); IFX_SWITCH_DIR_OUT(SWITCH_MDIO); IFX_SWITCH_OD_SET(SWITCH_MDIO); IFX_SWITCH_PIN_RESERVE(SWITCH_MDC); IFX_SWITCH_ALTSEL0_SET(SWITCH_MDC); IFX_SWITCH_ALTSEL1_CLR(SWITCH_MDC); IFX_SWITCH_DIR_OUT(SWITCH_MDC); IFX_SWITCH_OD_SET(SWITCH_MDC); chipid = (unsigned short)(ar9_smi_reg_read(0x101)); printk(" External Switch ID :0x%08x\n",chipid); if (chipid == TANTOS_CHIP_ID) { ar9_smi_reg_write(0xa1,0x0004); /*PORT 5 */ udelay(500); /*Fix me */ chipid = (unsigned short)(ar9_smi_reg_read(0xa1)); if(chipid != 0x4) printk("%s[%d] Error!!!!\n", __FUNCTION__,__LINE__); ar9_smi_reg_write(0xc1,0x0004); /*PORT 6*/ udelay(500); chipid = (unsigned short)(ar9_smi_reg_read(0xc1)); if(chipid != 0x4) printk("%s[%d] Error!!!!\n", __FUNCTION__,__LINE__); #if 0 ar9_smi_reg_write(0x81,0x0004); /* PORT 4 */ udelay(500); /*Fix me */ chipid = (unsigned short)(ar9_smi_reg_read(0x81)); if(chipid != 0x4) printk("%s[%d] Error!!!!\n", __FUNCTION__,__LINE__); #endif #if defined( ENABLE_SWITCH_FLOW_CONTROL ) && ENABLE_SWITCH_FLOW_CONTROL ar9_smi_reg_write(0xf5,0x0bbb); /*Enable flow control */ udelay(500); chipid = (unsigned short)(ar9_smi_reg_read(0xf5)); if(chipid != 0x0bbb) printk("%s[%d] Error!!!!\n", __FUNCTION__,__LINE__); #else ar9_smi_reg_write(0xf5,0x0aaa); /*Disable flow control */ udelay(500); chipid = (unsigned short)(ar9_smi_reg_read(0xf5)); if(chipid != 0x0aaa) printk("%s[%d] Error!!!!\n", __FUNCTION__,__LINE__); #endif /*Set Bypass mode */ /*P0 portbase vlan map reg */ readData = (unsigned short)(ar9_smi_reg_read(0x03)); ar9_smi_reg_write(0x03, (readData| 0x80)); /*P1 portbase vlan map reg */ readData = (unsigned short)(ar9_smi_reg_read(0x23)); ar9_smi_reg_write(0x23, (readData| 0x80)); /*P2 portbase vlan map reg */ readData = (unsigned short)(ar9_smi_reg_read(0x43)); ar9_smi_reg_write(0x43, (readData| 0x80)); /*P3 portbase vlan map reg */ readData = (unsigned short)(ar9_smi_reg_read(0x63)); ar9_smi_reg_write(0x63, (readData| 0x80)); /*P4 portbase vlan map reg */ readData = (unsigned short)(ar9_smi_reg_read(0x83)); ar9_smi_reg_write(0x83, (readData| 0x80)); /*P5 portbase vlan map reg */ readData = (unsigned short)(ar9_smi_reg_read(0xa3)); ar9_smi_reg_write(0xa3, (readData| 0x80)); /*P6 portbase vlan map reg */ readData = (unsigned short)(ar9_smi_reg_read(0xc3)); ar9_smi_reg_write(0xc3, (readData| 0x80)); } else{ /* TO DO*/ #if 0 ar9_smi_reg_write(0x1,0x840f); ar9_smi_reg_write(0x3,0x840f); ar9_smi_reg_write(0x5,0x840f); ar9_smi_reg_write(0x7,0x840f); ar9_smi_reg_write(0x8,0x840f); ar9_smi_reg_write(0x12,0x3602); ar9_smi_reg_write(0x33,0x4000); /*(Clock out2 @25MHz*/ #endif } return IFX_SUCCESS; } void amazon_s_sw_chip_init(int mode, int port) { #if defined( CONFIG_MII0) && CONFIG_MII0 if(port == 0){ //GPIO P2.0(MII0_COL), P2.1(MII0_CRS),P2.8(MII0_TXERR) & P2.9(MII0_RXERR) if ((mode == REV_MII_MODE) || (mode ==TURBO_REV_MII_MODE) || (mode == MII_MODE)) { IFX_SWITCH_PIN_RESERVE(MII0_COL); IFX_SWITCH_ALTSEL0_SET(MII0_COL); IFX_SWITCH_ALTSEL1_CLR(MII0_COL); if(mode == MII_MODE ) IFX_SWITCH_DIR_IN(MII0_COL); else { IFX_SWITCH_DIR_OUT(MII0_COL); IFX_SWITCH_OD_SET(MII0_COL); } IFX_SWITCH_PIN_RESERVE(MII0_CRS); IFX_SWITCH_ALTSEL0_SET(MII0_CRS); IFX_SWITCH_ALTSEL1_CLR(MII0_CRS); if(mode == MII_MODE ) IFX_SWITCH_DIR_IN(MII0_CRS); else { IFX_SWITCH_DIR_OUT(MII0_CRS); IFX_SWITCH_OD_SET(MII0_CRS); } IFX_SWITCH_PIN_RESERVE(MII0_TXERR); IFX_SWITCH_ALTSEL0_SET(MII0_TXERR); IFX_SWITCH_ALTSEL1_CLR(MII0_TXERR); if(mode == MII_MODE ){ IFX_SWITCH_DIR_OUT(MII0_TXERR); IFX_SWITCH_OD_SET(MII0_TXERR); } else IFX_SWITCH_DIR_IN(MII0_TXERR); IFX_SWITCH_PIN_RESERVE(MII0_RXERR); IFX_SWITCH_ALTSEL0_SET(MII0_RXERR); IFX_SWITCH_ALTSEL1_CLR(MII0_RXERR); if(mode == MII_MODE ) IFX_SWITCH_DIR_IN(MII0_RXERR); else { IFX_SWITCH_DIR_OUT(MII0_RXERR); IFX_SWITCH_OD_SET(MII0_RXERR); } } } /*port 0 */ #endif /*CONFIG_MII0*/ #if defined( CONFIG_MII1) && CONFIG_MII1 if(port == 1){ *AMAZON_S_CGU_IFCCR &= ~(3<<10); /*Select Clock_Out2 @25MHz */ /* Select GPIO P0.3 for CLOCK OUT 2 */ if(!init_done) /*avoid multiple calls */ { IFX_SWITCH_PIN_RESERVE(CLOCK_OUT2); IFX_SWITCH_ALTSEL0_SET(CLOCK_OUT2); IFX_SWITCH_ALTSEL1_CLR(CLOCK_OUT2); IFX_SWITCH_DIR_OUT(CLOCK_OUT2); IFX_SWITCH_OD_SET(CLOCK_OUT2); } //GPIO P2.12(MII1_COL), P2.15(MII1_CRS),P2.13(MII1_TXERR) & P2.14(MII1_RXERR) if((mode == REV_MII_MODE) || (mode ==TURBO_REV_MII_MODE) || (mode == MII_MODE)) { IFX_SWITCH_PIN_RESERVE(MII1_COL); IFX_SWITCH_ALTSEL0_SET(MII1_COL); IFX_SWITCH_ALTSEL1_CLR(MII1_COL); if(mode == MII_MODE ) IFX_SWITCH_DIR_IN(MII1_COL); else { IFX_SWITCH_DIR_OUT(MII1_COL); IFX_SWITCH_OD_SET(MII1_COL); } IFX_SWITCH_PIN_RESERVE(MII1_CRS); IFX_SWITCH_ALTSEL0_SET(MII1_CRS); IFX_SWITCH_ALTSEL1_CLR(MII1_CRS); if(mode == MII_MODE ) IFX_SWITCH_DIR_IN(MII1_CRS); else{ IFX_SWITCH_DIR_OUT(MII1_CRS); IFX_SWITCH_OD_SET(MII1_CRS); } IFX_SWITCH_PIN_RESERVE(MII1_TXERR); IFX_SWITCH_ALTSEL0_SET(MII1_TXERR); IFX_SWITCH_ALTSEL1_CLR(MII1_TXERR); if(mode == MII_MODE ){ IFX_SWITCH_DIR_OUT(MII1_TXERR); IFX_SWITCH_OD_SET(MII1_TXERR); } else IFX_SWITCH_DIR_IN(MII1_TXERR); IFX_SWITCH_PIN_RESERVE(MII1_RXERR); IFX_SWITCH_ALTSEL0_SET(MII1_RXERR); IFX_SWITCH_ALTSEL1_CLR(MII1_RXERR); if(mode == MII_MODE ) IFX_SWITCH_DIR_IN(MII1_RXERR); else { IFX_SWITCH_DIR_OUT(MII1_RXERR); IFX_SWITCH_OD_SET(MII1_RXERR); } } } /*port 1*/ #endif /*CONFIG_MII1*/ #if defined( CONFIG_MII0) && CONFIG_MII0 if(port == 0){ #if defined (TANTOS_SWITCH_INIT) && TANTOS_SWITCH_INIT /* Initilize the Tanto switch */ tantos_switch_init(); #endif AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= 0xffcffc0f ; AMAZON_S_REG32(AMAZON_S_RCU_PPE_CONF) &= 0xffff81ff; #if defined (AR9_RGMII0_BYPASS_DELAY_FIX) && AR9_RGMII0_BYPASS_DELAY_FIX AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= (0x2<<6); /*Set RGMI0 Rx clock delay DLL 1.75nSec*/ AMAZON_S_REG32(AMAZON_S_RCU_PPE_CONF) |= 5<<9 ; /*DLL bypass for SWITCH Rx port 1.75ns delay */ #endif AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= ((u32)(mode &0x3))<<8; if((mode &0x3) == 0) /* RGMII, MII, REV MII, RGMII_100MB, RGMII_10MB */{ AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= 0xfffffff3; /*10MB*/ if(mode == RGMII_MODE_100MB) AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= 0x4;/*100MB*/ else if (mode == RGMII_MODE) AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= 0x8; /*1000MB*/ } if(mode == TURBO_REV_MII_MODE) AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= ((u32) (1<<20)); /*Set clock 50Mhz*/ if(mode == RED_MII_MODE_OC) AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= ((u32) (1<<21)); /*output clock*/ #if defined( ENABLE_SWITCH_FLOW_CONTROL ) && ENABLE_SWITCH_FLOW_CONTROL amazon_s_switch_enable_fc(0); #else amazon_s_switch_disable_fc(0); #endif #if defined(CONFIG_PORT_INGRESS_DIRECT_FORWARD_ENABLE) && CONFIG_PORT_INGRESS_DIRECT_FORWARD_ENABLE amazon_s_switch_set_portingress_directforwarding(0, 1); /*Port 0 */ #else amazon_s_switch_set_portingress_directforwarding(0, 0); /*Port 0 */ #endif #if defined(CONFIG_PORT_REDIRECT_ENABLE) && CONFIG_PORT_REDIRECT_ENABLE amazon_s_switch_set_portegress_redirect(0, 1); #else amazon_s_switch_set_portegress_redirect(0, 0); #endif /* AMAZON_S_REG32(AMAZON_S_SW_P0_CTL)|=0x40001; */ AMAZON_S_REG32(AMAZON_S_SW_P0_CTL)|=0x00001; /*Interface is enabled when eth0 interface is up*/ } /*port == 0*/ #endif /*CONFIG_MII0*/ #if defined( CONFIG_MII1) && CONFIG_MII1 if(port == 1){ AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= 0xff303fff ; AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= ((u32)(mode &0x3))<<18; #if defined (AR9_RGMII1_BYPASS_DELAY_FIX) && AR9_RGMII1_BYPASS_DELAY_FIX AMAZON_S_REG32(AMAZON_S_RCU_PPE_CONF) &= 0xffe07fff; AMAZON_S_REG32(AMAZON_S_RCU_PPE_CONF) |= (0x20 << 15 ); /* Tx-->1.75ns, Rx-->1.75ns */ #else AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= 0xa<<14; /* Tx-->1.75ns, Rx-->1.75ns */ #endif if((mode &0x3) == 0){ AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= 0xffffcfff; if(mode == RGMII_MODE_100MB) AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= 0x1000; else AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= 0x2000; } if(mode == TURBO_REV_MII_MODE) AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= ((u32) (1<<22)); if(mode == RED_MII_MODE_OC) AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= ((u32) (1<<23)); #if defined( ENABLE_SWITCH_FLOW_CONTROL ) && ENABLE_SWITCH_FLOW_CONTROL amazon_s_switch_enable_fc(1); #else amazon_s_switch_disable_fc(1); #endif #if defined(CONFIG_PORT_INGRESS_DIRECT_FORWARD_ENABLE) && CONFIG_PORT_INGRESS_DIRECT_FORWARD_ENABLE amazon_s_switch_set_portingress_directforwarding(1, 1); /*Port 0 */ #else amazon_s_switch_set_portingress_directforwarding(1, 0); /*Port 0 */ #endif #if defined(CONFIG_PORT_REDIRECT_ENABLE) && CONFIG_PORT_REDIRECT_ENABLE amazon_s_switch_set_portegress_redirect(1, 1); #else /* ifx_switch_set_portegress_redirect(1, 0); */ amazon_s_switch_set_portegress_redirect(1, 0); #endif #if !defined(CONFIG_PMAC_DMA_ENABLE) || ! CONFIG_PMAC_DMA_ENABLE AMAZON_S_REG32(AMAZON_S_SW_P1_CTL)|=0x40001; #endif } /*port 1 */ #endif /*CONFIG_MII1*/ AMAZON_S_REG32(AMAZON_S_SW_GCTL0) &= (~0x300); /*default, 1522 Bytes*/ /* AMAZON_S_REG32(AMAZON_S_SW_GCTL0) = (AMAZON_S_REG32(AMAZON_S_SW_GCTL0) & (~0x300)) | 0x100; */ /*1518Bytes */ /* AMAZON_S_REG32(AMAZON_S_SW_GCTL0) = (AMAZON_S_REG32(AMAZON_S_SW_GCTL0) & (~0x300)) | 0x200; */ /*1536Bytes*/ AMAZON_S_REG32(AMAZON_S_SW_P2_CTL)|=0x40001; AMAZON_S_REG32(AMAZON_S_SW_PMAC_HD_CTL) |= 0x40000; //enable CRC /* TRACE("PMAC_HD_CTL:0x%08x\n",AMAZON_S_REG32(AMAZON_S_SW_PMAC_HD_CTL)); TRACE("SW_GCTL0:0x%08x\n",AMAZON_S_REG32(AMAZON_S_SW_GCTL0)); */ } int switch_dma_setup_init(void){ /*initialize the dma device*/ int i, result; g_dma_device=dma_device_reserve("PPE"); if(!g_dma_device) { printk("Dma-device_reserve Error!!! or Already registerd with PPE channels\n" ); return IFX_ERROR; } g_dma_device->buffer_alloc=&etop_dma_buffer_alloc; g_dma_device->buffer_free=&etop_dma_buffer_free; g_dma_device->intr_handler=&dma_intr_handler; g_dma_device->max_rx_chan_num=4;/*turn on all the receive channels*/ g_dma_device->max_tx_chan_num=4;/*turn on all the receive channels*/ for(i=0;imax_rx_chan_num;i++){ g_dma_device->rx_chan[i]->packet_size=ETHERNET_PACKET_DMA_BUFFER_SIZE; g_dma_device->rx_chan[i]->control=AMAZON_S_DMA_CH_ON; } for(i=0;imax_tx_chan_num;i++){ if(i==0) g_dma_device->tx_chan[i]->control=AMAZON_S_DMA_CH_ON; else g_dma_device->tx_chan[i]->control=AMAZON_S_DMA_CH_OFF; } g_dma_device->tx_burst_len = DMA_TX_BURST_LEN; g_dma_device->rx_burst_len = DMA_RX_BURST_LEN; #if defined(ENABLE_NAPI) && ENABLE_NAPI g_dma_device->activate_poll = switch_activate_poll; g_dma_device->inactivate_poll = switch_inactivate_poll; #endif result=dma_device_register(g_dma_device); if(!result) printk("Dma-device_register failed, result:%d\n", result ); return result; } static int switch_init(struct net_device *dev){ u64 retval=0; static int macVal=0; int i; // ether_setup(dev); /* assign some of the fields */ TRACE("%s up\n",dev->name); dev->open = amazon_s_switch_open; dev->stop = switch_release; dev->hard_start_xmit = switch_tx; dev->do_ioctl = switch_ioctl; dev->get_stats = amazon_s_get_stats; //dev->change_mtu = switch_change_mtu; //dev->set_mac_address =switch_set_mac_address; dev->tx_timeout =switch_tx_timeout; dev->watchdog_timeo =timeout; //dev->flags |= IFF_NOARP|IFF_PROMISC; #if defined(ENABLE_NAPI) && ENABLE_NAPI dev->poll = switch_poll; dev->weight = 64; #endif /*--- SET_MODULE_OWNER(dev); XXX ---*/ /*read the mac address from the mac table and put them into the mac table.*/ for (i = 0; i < 6; i++){ retval +=my_ethaddr[i]; } /* ethaddr not set in u-boot ? */ if (retval == 0){ printk("use default MAC address\n"); dev->dev_addr[0] = 0x00; dev->dev_addr[1] = 0x20; dev->dev_addr[2] = 0xda; dev->dev_addr[3] = 0x86; dev->dev_addr[4] = 0x23; dev->dev_addr[5] = 0x74 + macVal; }else{ for (i = 0; i < 6; i++){ dev->dev_addr[i] = my_ethaddr[i]; } dev->dev_addr[5] += + macVal ; } macVal++; #ifdef AMAZON_S_SW_DUMP retval = 0; for (i = 0; i < 6; i++){ retval = (retval<<8) + dev->dev_addr[i]; printk(" %2x ", dev->dev_addr[i]); } #endif return 0; } #if defined (MII1_GPHY_INT_HANDLE) && MII1_GPHY_INT_HANDLE /* * mii1 gphy status structure */ struct mii1_gphy_status { int link; /*link status, up/down */ int speed; /* preset link speed, 10/100/1000*/ int duplex; /*duplex status, FD/HD*/ }; static struct mii1_gphy_status gphy_status; /* * Used for Interrupt Handler */ static irqreturn_t mii1_gphy_interrupt (int irq, void *dev_id){ unsigned short status, linkReg, speedReg; struct mii1_gphy_status *phy_status = (struct mii1_gphy_status *)dev_id; status=ifx_switch_read_mdio(0x11,0x1a); /*read data from phy register to clear phy interrupts */ /* TRACE("Got interrupt, Status: 0x%04x\n",status); */ if(status & 0x8000) /*interrupt status bit */ { if( (status & 0x7000)) /*cause the interrupt due to link status, speed & FDX */{ linkReg=ifx_switch_read_mdio(0x11,0x01); if((linkReg&0x04)==0) /*Link on PHY is down */{ TRACE("Link down \n"); // AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) = 0x40020000; /*Port1 force link down and disable/discard the learning state*/ AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) &= 0xfff9ffff; AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) |= (1 << 17 ); /*Port1 force link down */ // printk("Link down: P1_CTL: 0x%08x \n",AMAZON_S_REG32(AMAZON_S_SW_P1_CTL)); phy_status->link = 0x0; /*LINK DOWN */ } else { speedReg=ifx_switch_read_mdio(0x11,0x1c); TRACE("Got interrupt, link Up Status: 0x%04x\n",speedReg); if(speedReg & 0x20){ TRACE("Link Up with FDX\n"); AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= (0x1 << 11); phy_status->duplex = DUPLEX_FULL; } else{ TRACE("Link Up with HDX\n"); AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= ~(0x1 << 11); phy_status->duplex = DUPLEX_HALF; } switch ((speedReg & 0x18) >> 3 ){ case 0 : /*speed 10BASE-T */ TRACE("Link Up with 10BASE-T, status 0x%04x\n",speedReg); AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= 0xffffcfff; AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) &= 0xfff9ffff; #if defined(CONFIG_PMAC_DMA_ENABLE) && CONFIG_PMAC_DMA_ENABLE if(eth1_up ) AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) |= ( (1 << 18 ) ); /*Port1 force link up*/ #else AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) |= ( (1 << 18 ) ); /*Port1 force link up*/ #endif // printk("Link : P1_CTL: 0x%08x \n",AMAZON_S_REG32(AMAZON_S_SW_P1_CTL)); phy_status->speed = SPEED_10; phy_status->link = 0x1; /*LINK UP */ break; case 1: /*speed 100BASE-TX*/ TRACE("Link Up with 100BASE-T, status 0x%04x\n",speedReg); AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= 0xffffcfff; AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= (0x1 << 12); AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) &= 0xfff9ffff; #if defined(CONFIG_PMAC_DMA_ENABLE) && CONFIG_PMAC_DMA_ENABLE if(eth1_up ) AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) |= ( (1 << 18 ) ); /*Port1 force link up*/ #else AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) |= ( (1 << 18 ) ); /*Port1 force link up*/ #endif /* printk("Link : P1_CTL: 0x%08x \n",AMAZON_S_REG32(AMAZON_S_SW_P1_CTL)); */ phy_status->speed = SPEED_100; phy_status->link = 0x1; /*LINK UP */ break; case 2: /*speed 1000BASE-T*/ TRACE("Link Up with 1000BASE-T, status 0x%04x\n",speedReg); AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) &= 0xffffcfff; AMAZON_S_REG32(AMAZON_S_SW_RGMII_CTL) |= (0x2 << 12 ) ; AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) &= 0xfff9ffff; #if defined(CONFIG_PMAC_DMA_ENABLE) && CONFIG_PMAC_DMA_ENABLE if(eth1_up ) AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) |= ( (1 << 18 ) ); /*Port1 force link up*/ #else AMAZON_S_REG32(AMAZON_S_SW_P1_CTL) |= ( (1 << 18 ) ); /*Port1 force link up*/ #endif /* printk("Link : P1_CTL: 0x%08x \n",AMAZON_S_REG32(AMAZON_S_SW_P1_CTL)); */ phy_status->speed = SPEED_1000; phy_status->link = 0x1; /*LINK UP */ break; } } } } return IRQ_HANDLED; } #endif /*MII1_GPHY_INT_HANDLE*/ #if defined(SWITCH_INTERRUPT) && SWITCH_INTERRUPT struct ifx_switch_status { u32 sw_status; }; static struct ifx_switch_status switch_status; /* * Used for Interrupt Handler */ static irqreturn_t ifx_switch_interrupt (int irq, void *dev_id){ /*Testing purpose */ printk("switch status: 0x%08x\n",AMAZON_S_REG32(AMAZON_S_SW_INT_ST)); return IRQ_HANDLED; } #endif #ifdef ENABLE_OLD_IFX_ETHSW_API /** * The following details applies to internal AR9 switch */ #define IFX_SW_MAJ_NO 244 #define IFX_SW_MIN_NO_BASE 1 #define IFX_SW_MAX_DEVICES 1 #define DEV_NAME "AR9" /** List of Wrapper functions for Registeration with ifx_swops */ extern IFX_return_t IFX_SWAPI_Register_LL_Drv (IFX_ETHSW_DRV_CTX_t* pLLDrvCtx); extern IFX_return_t IFX_SWAPI_Unregister_LL_Drv (IFX_ETHSW_DRV_CTX_t* pCtx); extern int ar9_switch_get_mac_table_entry (IFX_ETHSW_MAC_TABLE_GET_t *mac_table_entry); extern int ar9_switch_add_mac_table_entry (IFX_ETHSW_MAC_TABLE_ADD_t *mac_table_add); extern int ar9_switch_del_mac_table_entry (IFX_ETHSW_MAC_TABLE_DEL_t *mac_table_del); extern int ar9_switch_get_portcfg (IFX_ETHSW_PORT_CFG_t *portcfg); extern int ar9_switch_set_portcfg (IFX_ETHSW_PORT_CFG_t *portcfg); extern int ar9_switch_get_port_linkcfg (IFX_ETHSW_PORT_LINK_CFG_t *portlink_cfg); extern int ar9_switch_set_port_linkcfg (IFX_ETHSW_PORT_LINK_CFG_t *portlink_cfg); extern int ar9_switch_get_port_hwmode (IFX_ETHSW_PORT_HW_MODE_t *port_hwmode); /** Initialize the Major & Minor Numbers for AR9 switch */ IFX_uint16_t major = IFX_SW_MAJ_NO; IFX_uint16_t minorBase = IFX_SW_MIN_NO_BASE; IFX_char_t *devName = "ar9"; /** Lowlevel Functions supported by AR9 */ IFX_ETHSW_LL_FKT_t ar9_drv_sw_ops = { sw_init: tantos_switch_init, fkt_ifx_ethsw_cap_get: NULL, fkt_ifx_ethsw_port_cfg_get: ar9_switch_get_portcfg, fkt_ifx_ethsw_port_cfg_set: ar9_switch_set_portcfg, fkt_ifx_ethsw_port_link_get: ar9_switch_get_port_linkcfg, fkt_ifx_ethsw_port_link_set: ar9_switch_set_port_linkcfg, fkt_ifx_ethsw_port_hw_mode_get: ar9_switch_get_port_hwmode, fkt_ifx_ethsw_mac_table_entry_get: ar9_switch_get_mac_table_entry, fkt_ifx_ethsw_mac_table_entry_add: ar9_switch_add_mac_table_entry, fkt_ifx_ethsw_mac_table_entry_del: ar9_switch_del_mac_table_entry, }; /** * \brief Register the Low level driver with the Kernel Switch API * * \param IFX_void_t VOID * * \return -1 on failure and 0 on success */ int IFX_Register_AR9_int_switch_Drv(IFX_void_t) { /* 1. fill the IFX_ETHSW_DRV_CTX_t struct 2. call the device registration hook function of Generic Kernel API */ int ret = 0; IFX_ETHSW_DRV_CTX_t *pDrvCtx = NULL; pDrvCtx = (IFX_ETHSW_DRV_CTX_t *) kmalloc (sizeof (IFX_ETHSW_DRV_CTX_t), GFP_ATOMIC); if(pDrvCtx == NULL) { printk("Error : memory allocation failed !!\n"); return -1; } memset (pDrvCtx, 0, sizeof(IFX_ETHSW_DRV_CTX_t)); pDrvCtx->devNodeName = devName; pDrvCtx->majorNumber = IFX_SW_MAJ_NO; /* Need to consider the offset for multiple dev */ pDrvCtx->minorBase = IFX_SW_MIN_NO_BASE; pDrvCtx->maxDevs = IFX_SW_MAX_DEVICES; pDrvCtx->drvName = DEV_NAME; pDrvCtx->ifx_sw_ops = &ar9_drv_sw_ops; /* Invoke the hook function to register the LL driver */ ret = IFX_SWAPI_Register_LL_Drv(pDrvCtx); if(ret == -1) { printk("Registration of dev [%s] with Genric Kernel API failed", pDrvCtx->drvName); } else { printk("Successfully registered dev [%s] with Genric Kernel API", pDrvCtx->drvName); } /* Free the memory alloced above */ if(pDrvCtx) kfree(pDrvCtx); return ret; } #endif /* ENABLE_OLD_IFX_ETHSW_API */ int switch_init_module (void){ int i,device_present=0, result; x_IFX_switch_priv_t* priv; int interrupt_no = 0; struct proc_dir_entry *res; printk("Switch Driver Version: %s\n", AMAZON_S_SWITCH_DRIVER_VERSION); SWITCH_PMU_SETUP(PMU_ENABLE); /* Enable Switch */ AMAZON_S_REG32(AMAZON_S_SW_GCTL0) |= 0x80000000; AMAZON_S_REG32(AMAZON_S_SW_P0_CTL)|=(1<<22); /*Disable MDIO auto polling mode */ g_amazon_s_sw_dir=proc_mkdir("amazon_s_sw",NULL); create_proc_read_entry("DSCP_COS", 0, g_amazon_s_sw_dir, etop_dscp_cos_proc_read, NULL); create_proc_read_entry("VLAN_COS", 0, g_amazon_s_sw_dir, etop_vlan_cos_proc_read, NULL); create_proc_read_entry("GET_ALL_PORTS_MIB",0,g_amazon_s_sw_dir, get_all_ports_mib_proc_read, NULL); create_proc_read_entry("GET_PORT0_MIB", 0,g_amazon_s_sw_dir, get_port0_mib_proc_read, NULL); create_proc_read_entry("GET_PORT1_MIB", 0, g_amazon_s_sw_dir, get_port1_mib_proc_read, NULL); create_proc_read_entry("GET_PORT2_MIB", 0, g_amazon_s_sw_dir, get_port2_mib_proc_read, NULL); create_proc_read_entry("CLEAR_ALL_PORTS_MIB",0,g_amazon_s_sw_dir, clr_all_ports_mib_proc_read, NULL); create_proc_read_entry("CLR_PORT0_MIB", 0,g_amazon_s_sw_dir, clr_port0_mib_proc_read, NULL); create_proc_read_entry("CLR_PORT1_MIB", 0, g_amazon_s_sw_dir, clr_port1_mib_proc_read, NULL); create_proc_read_entry("CLR_PORT2_MIB", 0, g_amazon_s_sw_dir, clr_port2_mib_proc_read, NULL); create_proc_read_entry("misc", 0, g_amazon_s_sw_dir, misc_counter_proc_read, NULL); create_proc_read_entry("ingress_enable", 0, g_amazon_s_sw_dir, ingress_en_proc_read, NULL); create_proc_read_entry("ingress_disable", 0, g_amazon_s_sw_dir, ingress_dis_proc_read, NULL); create_proc_read_entry("egress_enable", 0, g_amazon_s_sw_dir, egress_en_proc_read, NULL); create_proc_read_entry("egress_disable", 0, g_amazon_s_sw_dir, egress_dis_proc_read, NULL); /* create_proc_read_entry("reset", 0, g_amazon_s_sw_dir, switch_reset_proc_read, NULL); */ res = create_proc_entry("flowcontrol", 0, g_amazon_s_sw_dir); if ( res ) { res->read_proc = proc_read_flowcontrol; res->write_proc = proc_write_flowcontrol; } switch_dma_setup_init(); #if defined( CONFIG_MII0) && CONFIG_MII0 amazon_s_sw_chip_init(MII0_INTERFACE,0); #endif #if defined( CONFIG_MII1) && CONFIG_MII1 amazon_s_sw_chip_init(MII1_INTERFACE,1); #endif #if defined(PMAC_RX_IPG_DELAY) && PMAC_RX_IPG_DELAY AMAZON_S_REG32(AMAZON_S_SW_PMAC_RX_IPG) = 0x3b; #endif #if defined(GPHY_RESET_ENABLE) && GPHY_RESET_ENABLE /*Reset GPHY*/ /*GPIO P2.0*/ IFX_SWITCH_PIN_RESERVE(RESET_GPHY); IFX_SWITCH_ALTSEL0_CLR(RESET_GPHY); IFX_SWITCH_ALTSEL1_CLR(RESET_GPHY); IFX_SWITCH_DIR_OUT(RESET_GPHY); IFX_SWITCH_OD_SET(RESET_GPHY); IFX_SWITCH_OUTPUT_SET(RESET_GPHY); ifx_mdelay( 50); IFX_SWITCH_OUTPUT_CLR(RESET_GPHY); ifx_mdelay( 50); IFX_SWITCH_OUTPUT_SET(RESET_GPHY); ifx_mdelay( 50); #endif #if defined ( CONFIG_LOGICAL_PORT_ENABLE) && CONFIG_LOGICAL_PORT_ENABLE amazon_s_switch_set_logical_port_status(1); #else amazon_s_switch_set_logical_port_status(0); #endif #if defined(CONFIG_PMAC_DMA_ENABLE) && CONFIG_PMAC_DMA_ENABLE amazon_s_switch_set_headerstatus_pmactodma(1); #else amazon_s_switch_set_headerstatus_pmactodma(0); #endif #if defined(CONFIG_DMA_PMAC_ENABLE) && CONFIG_DMA_PMAC_ENABLE amazon_s_switch_set_headerstatus_dmatopmac(1); #else amazon_s_switch_set_headerstatus_dmatopmac(0); #endif /** ** Set internal switch configurations is, ** Classification: 802.1q & DSCP ** Scheduling for all internal ports: Strict Priority and Rate limit is Disabled **/ #if SWITCH_STRICT_PRI_AND_CLASSIFICATION /*classification scheme: if packet is IP packet, then classification is based on DSCP. if packet is inot IP packet, then classification is based on 802.1q. */ for(i=0;i <3;i++) { /*Enable VLAN,DSCP & IP Over VLAN priority */ AMAZON_S_REG32(AMAZON_S_SW_P0_CTL+4*i) |= (7<<25); } /*Queue Mapping */ AMAZON_S_REG32(AMAZON_S_SW_1P_PRT) = 0xFA41; AMAZON_S_REG32(AMAZON_S_SW_DFSRV_MAP0) = 0x11100000; AMAZON_S_REG32(AMAZON_S_SW_DFSRV_MAP1) = 0x22211111; AMAZON_S_REG32(AMAZON_S_SW_DFSRV_MAP2) = 0x30222222; AMAZON_S_REG32(AMAZON_S_SW_DFSRV_MAP3) = 0x00030003; /* Scheduling Scheme Strict Priority scheduling is used for all ports and Rate limit is disabled */ AMAZON_S_REG32(AMAZON_S_SW_P0_ECS_Q32) = 0x03E803E8; AMAZON_S_REG32(AMAZON_S_SW_P0_ECS_Q10) = 0x03E803E8; AMAZON_S_REG32(AMAZON_S_SW_P1_ECS_Q32) = 0x03E803E8; AMAZON_S_REG32(AMAZON_S_SW_P1_ECS_Q10) = 0x03E803E8; AMAZON_S_REG32(AMAZON_S_SW_P2_ECS_Q32) = 0x03E803E8; AMAZON_S_REG32(AMAZON_S_SW_P2_ECS_Q10) = 0x03E803E8; AMAZON_S_REG32(AMAZON_S_SW_P0_ECW_Q32) = 0x0; AMAZON_S_REG32(AMAZON_S_SW_P0_ECW_Q10) = 0x0; AMAZON_S_REG32(AMAZON_S_SW_P1_ECW_Q32) = 0x0; AMAZON_S_REG32(AMAZON_S_SW_P1_ECW_Q10) = 0x0; AMAZON_S_REG32(AMAZON_S_SW_P2_ECW_Q32) = 0x0; AMAZON_S_REG32(AMAZON_S_SW_P2_ECW_Q10) = 0x0; #endif /*SWITCH_STRICT_PRI_AND_CLASSIFICATION */ #if 0 for(i=0;i<120; i++){ reg_buf1[i] = AMAZON_S_REG32(AMAZON_S_SW + (i *4)); /* printk("Reg: 0x%8x, Value: 0x%08x \n",AMAZON_S_SW+(i*4), AMAZON_S_REG32(AMAZON_S_SW+(i*4))); */ } #endif #if defined (MII1_GPHY_INT_HANDLE) && MII1_GPHY_INT_HANDLE IFX_SWITCH_PIN_RESERVE(EXT_INT_GPIO); #if EXT_INT_GPIO == 0 /*Extern interrupt 0 */ IFX_SWITCH_ALTSEL0_SET(EXT_INT_GPIO); IFX_SWITCH_ALTSEL1_CLR(EXT_INT_GPIO); #define EXT_INT_IRQ INT_NUM_IM4_IRL30 /*IM4_IRL30 */ #elif EXT_INT_GPIO == 1 /*Extern interrupt 1 */ IFX_SWITCH_ALTSEL0_SET(EXT_INT_GPIO); IFX_SWITCH_ALTSEL1_CLR(EXT_INT_GPIO); #define EXT_INT_IRQ INT_NUM_IM3_IRL31 /*IM3_IRL31 */ #elif EXT_INT_GPIO == 2 /*Extern interrupt 2 */ IFX_SWITCH_ALTSEL0_CLR(EXT_INT_GPIO); IFX_SWITCH_ALTSEL1_SET(EXT_INT_GPIO); #define EXT_INT_IRQ INT_NUM_IM1_IRL26 /*IM1_IRL26 */ #elif EXT_INT_GPIO == 9 /*Extern interrupt 5 */ IFX_SWITCH_ALTSEL0_SET(EXT_INT_GPIO); IFX_SWITCH_ALTSEL1_SET(EXT_INT_GPIO); #define EXT_INT_IRQ INT_NUM_IM1_IRL2 /*IM1_IRL2 */ #elif EXT_INT_GPIO == 10 /*Extern interrupt 4 */ IFX_SWITCH_ALTSEL0_SET(EXT_INT_GPIO); IFX_SWITCH_ALTSEL1_SET(EXT_INT_GPIO); #define EXT_INT_IRQ INT_NUM_IM1_IRL1 /*IM1_IRL1 */ #elif EXT_INT_GPIO == 39 /*Extern interrupt 3 */ IFX_SWITCH_ALTSEL0_CLR(EXT_INT_GPIO); IFX_SWITCH_ALTSEL1_SET(EXT_INT_GPIO); #define EXT_INT_IRQ INT_NUM_IM1_IRL0 /*IM1_IRL0 */ #else printk("%s[%d]: Wrong Externel Interrupt!!! \n",__FUNCTION__,__LINE__); interrupt_no = 1; #endif IFX_SWITCH_DIR_IN(EXT_INT_GPIO); if (!interrupt_no){ result = request_irq(EXT_INT_IRQ, mii1_gphy_interrupt, IRQF_DISABLED, "ifx_mii1_gphy", (void*)&gphy_status); if ( result ){ printk("error, cannot get ext int3 irq!\n"); free_irq(EXT_INT_IRQ,(void*)&mii1_gphy_interrupt); return -EFAULT; } ifx_switch_write_mdio(0x11, 0x19, 0xf000); AMAZON_S_REG32(AMAZON_S_ICU_EIU_EXIN_C) |= ((0x2 << EXT_INT_NO * 4)); /*Falling edge */ AMAZON_S_REG32(AMAZON_S_ICU_EIU_INEN) |= (1<< EXT_INT_NO); /*Enable External interrupt*/ } #endif /*MII1_GPHY_INT_HANDLE*/ for (i=0; iinit=switch_init; priv = (x_IFX_switch_priv_t*)switch_devs[i]->priv; if ( !(result = register_netdev(switch_devs[i]))){ device_present++; } } #ifdef ENABLE_OLD_IFX_ETHSW_API /** Invoke the Ethernet Switch Device Registeration */ IFX_Register_AR9_int_switch_Drv(); #endif #if defined(SWITCH_INTERRUPT) && SWITCH_INTERRUPT result=request_irq(INT_NUM_IM1_IRL16,ifx_switch_interrupt, IRQF_DISABLED, "ifx_switch_int",(void*)&switch_status); if(result){ printk("error, cannot get switch_irq!\n"); return -EFAULT; } AMAZON_S_REG32(AMAZON_S_SW_INT_ENA) |= (1 << 7); #endif init_done = 1; return device_present ? 0 : -ENODEV; } void switch_cleanup(void) { int i; struct dma_device_info* dma_dev=g_dma_device; #ifdef ENABLE_OLD_IFX_ETHSW_API int ret = 0; IFX_ETHSW_DRV_CTX_t *pDrvCtx = NULL; #endif if( dma_dev ) { dma_device_unregister(dma_dev); dma_device_release(dma_dev); } #ifdef ENABLE_OLD_IFX_ETHSW_API pDrvCtx = (IFX_ETHSW_DRV_CTX_t *) kmalloc (sizeof (IFX_ETHSW_DRV_CTX_t), GFP_ATOMIC); if(pDrvCtx == NULL) { printk("Error : memory allocation failed !!\n"); return; } memset (pDrvCtx, 0, sizeof(IFX_ETHSW_DRV_CTX_t)); pDrvCtx->devNodeName = devName; pDrvCtx->majorNumber = IFX_SW_MAJ_NO; pDrvCtx->minorBase = IFX_SW_MIN_NO_BASE; /* Need to consider the offset for multiple dev */ pDrvCtx->maxDevs = IFX_SW_MAX_DEVICES; pDrvCtx->drvName = DEV_NAME; #endif remove_proc_entry("DSCP_COS", g_amazon_s_sw_dir); remove_proc_entry("VLAN_COS", g_amazon_s_sw_dir); remove_proc_entry("GET_ALL_PORTS_MIB",g_amazon_s_sw_dir); remove_proc_entry("GET_PORT0_MIB", g_amazon_s_sw_dir); remove_proc_entry("GET_PORT1_MIB", g_amazon_s_sw_dir); remove_proc_entry("GET_PORT2_MIB", g_amazon_s_sw_dir); remove_proc_entry("CLEAR_ALL_PORTS_MIB",g_amazon_s_sw_dir); remove_proc_entry("CLR_PORT0_MIB", g_amazon_s_sw_dir); remove_proc_entry("CLR_PORT1_MIB", g_amazon_s_sw_dir); remove_proc_entry("CLR_PORT2_MIB", g_amazon_s_sw_dir); remove_proc_entry("misc", g_amazon_s_sw_dir); remove_proc_entry("ingress_enable", g_amazon_s_sw_dir); remove_proc_entry("ingress_disable", g_amazon_s_sw_dir); remove_proc_entry("egress_enable", g_amazon_s_sw_dir); remove_proc_entry("egress_disable", g_amazon_s_sw_dir); /* remove_proc_entry("reset", g_amazon_s_sw_dir); */ remove_proc_entry("flowcontrol", g_amazon_s_sw_dir); remove_proc_entry("amazon_s_sw", NULL); for (i=0; idrvName); } else { printk("Successfully unregistered dev [%s] with Genric Kernel API", pDrvCtx->drvName); } if(pDrvCtx) kfree(pDrvCtx); #endif } module_init(switch_init_module); module_exit(switch_cleanup); void amazon_s_sw_config(void){ TRACE("%s:\n", __FUNCTION__); #if defined( CONFIG_MII0) && CONFIG_MII0 amazon_s_sw_chip_init(MII0_INTERFACE,0); #endif #if defined( CONFIG_MII1) && CONFIG_MII1 amazon_s_sw_chip_init(MII1_INTERFACE,1); #endif #if defined(GPHY_RESET_ENABLE) && GPHY_RESET_ENABLE /*Reset GPHY*/ /*GPIO P2.0*/ if(!init_done) /*avoid multiple calls */ { IFX_SWITCH_PIN_RESERVE(RESET_GPHY); IFX_SWITCH_ALTSEL0_CLR(RESET_GPHY); IFX_SWITCH_ALTSEL1_CLR(RESET_GPHY); } IFX_SWITCH_DIR_OUT(RESET_GPHY); IFX_SWITCH_OD_SET(RESET_GPHY); IFX_SWITCH_OUTPUT_SET(RESET_GPHY); ifx_mdelay( 50); IFX_SWITCH_OUTPUT_CLR(RESET_GPHY); ifx_mdelay( 50); IFX_SWITCH_OUTPUT_SET(RESET_GPHY); ifx_mdelay( 50); /*Enable GPHY interrupts, after reset it */ ifx_switch_write_mdio(0x11, 0x19, 0xf000); #endif #if defined ( CONFIG_LOGICAL_PORT_ENABLE) && CONFIG_LOGICAL_PORT_ENABLE amazon_s_switch_set_logical_port_status(1); #else amazon_s_switch_set_logical_port_status(0); #endif #if defined(CONFIG_PMAC_DMA_ENABLE) && CONFIG_PMAC_DMA_ENABLE amazon_s_switch_set_headerstatus_pmactodma(1); #else amazon_s_switch_set_headerstatus_pmactodma(0); #endif #if defined(CONFIG_DMA_PMAC_ENABLE) && CONFIG_DMA_PMAC_ENABLE amazon_s_switch_set_headerstatus_dmatopmac(1); amazon_s_switch_set_logical_port_status(1); amazon_s_switch_set_logical_port_status(0); amazon_s_switch_set_headerstatus_dmatopmac(1); #else amazon_s_switch_set_headerstatus_dmatopmac(0); #endif } EXPORT_SYMBOL(amazon_s_sw_config);