/***************************************************************************** * sdla_aft_te1.c * * WANPIPE(tm) AFT TE1 Hardware Support * * Authors: Nenad Corbic * * Copyright: (c) 2003-2008 Sangoma Technologies Inc. * * 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. * ============================================================================ * Feb 04,2008 Nenad Corbic Support for RTP TAP, Fixed 56K * Mar 16,2007 David Rokhvarg Support for ISDN BRI card. * Oct 25,2004 Nenad Corbic Support for QuadPort TE1 * Jan 07,2003 Nenad Corbic Initial version. *****************************************************************************/ #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) # include # include # include # include # include /* Socket Driver common area */ # include # include # include # include #else # include # include # include # include # include # include /* Socket Driver common area */ # include # include # include # include # include # include #endif #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG # include "wanpipe_lapb_kernel.h" #endif #if defined(CONFIG_WANPIPE_HWEC) # include #endif #define INIT_FE_ONLY 0 #if 1 #define AFT_FUNC_DEBUG() #else #define AFT_FUNC_DEBUG() DEBUG_EVENT("%s:%d\n",__FUNCTION__,__LINE__) #endif #if 0 # define AFT_XTEST_UPDATE 1 #else # undef AFT_XTEST_UPDATE #endif #if 1 # define AFT_SECURITY_CHECK 1 #else # undef AFT_SECURITY_CHECK # warning "AFT_SECURITY_CHECK disabled" #endif #if 1 # define AFT_WDT_ENABLE 1 #else # warning "DISABLED WDT" # undef AFT_WDT_ENABLE #endif #if 0 # define AFT_RX_FIFO_DEBUG 1 # warning "AFT_RX_FIFO_DEBUG Flag used" #else # undef AFT_RX_FIFO_DEBUG #endif #if 0 # define AFT_TX_FIFO_DEBUG 1 # warning "AFT_TX_FIFO_DEBUG Flag used" #else # undef AFT_TX_FIFO_DEBUG #endif #if 0 # define AFT_SINGLE_DMA_CHAIN 1 # warning "AFT_SINGLE_DMA_CHAIN: SET" #else # undef AFT_SINGLE_DMA_CHAIN #endif #if 1 # define AFT_IFT_INTR_ENABLE 1 #else # warning "AFT_IFT_INTR_ENABLE NOT ENABLED" # undef AFT_IFT_INTR_ENABLE #endif #if 0 # warning "IRQ INTR DEBUGGIN ON" # define AFT_IRQ_DEBUG 1 #else # undef AFT_IRQ_DEBUG #endif #if 0 # warning "IRQ STAT DEBUGGIN ON" # define AFT_IRQ_STAT_DEBUG 1 #else # undef AFT_IRQ_STAT_DEBUG #endif #if 0 # define AFT_TDMV_BH_ENABLE 1 # error "AFT_TDMV_BH_ENABLE flag used" #else # undef AFT_TDMV_BH_ENABLE #endif #if 1 # define AFT_TDMV_CHANNELIZATION 1 #else # undef AFT_TDMV_CHANNELIZATION #endif #if 1 # define AFT_CLOCK_SYNC 1 #else # undef AFT_CLOCK_SYNC #endif #if 0 # warning "AFT_SERIAL_DEBUGGING is enabled" # define AFT_SINGLE_DMA_CHAIN 1 # define AFT_SERIAL_DEBUG #else # undef AFT_SERIAL_DEBUG #endif #if defined(__LINUX__) #define AFT_TDM_API_SUPPORT 1 #else #undef AFT_TDM_API_SUPPORT #endif #if defined(__LINUX__) #define AFT_API_SUPPORT 1 #else #undef AFT_API_SUPPORT #endif #if defined(__LINUX__) # define AFT_RTP_SUPPORT 1 #else # undef AFT_RTP_SUPPORT #endif #if defined(WANPIPE_64BIT_4G_DMA) #warning "Wanpipe compiled for 64bit 4G DMA" #endif /* Trigger on Number of transactions * 1= 1x8 byte transactions * 2= 2x8 byte transactions * 3= 3x8 byte transactions * 4= 4x8 byte transactions */ #define AFT_TDMV_FIFO_LEVEL 1 #define AFT_TDMV_CIRC_BUF 128 #define AFT_TDMV_CIRC_BUF_LEN 4 #define AFT_TDMV_BUF_MASK 0x1FF #define AFT_SS7_CTRL_LEN_MASK 0x0F #define AFT_SS7_CTRL_TYPE_BIT 4 #define AFT_SS7_CTRL_FORCE_BIT 5 #define AFT_MAX_CHIP_SECURITY_CNT 100 #define AFT_FE_FIX_FIRM_VER 100 aft_hw_dev_t aft_hwdev[MAX_AFT_HW_DEV]; enum { TDM_RUNNING, TDM_PENDING, }; /****** Defines & Macros ****************************************************/ /* Private critical flags */ enum { POLL_CRIT = PRIV_CRIT, CARD_DOWN, TE_CFG, CARD_HW_EC, CARD_MASTER_CLOCK, CARD_PORT_TASK_DOWN, CARD_PORT_TASK_RUNNING }; enum { LINK_DOWN, DEVICE_DOWN }; enum { TX_DMA_BUSY, TX_HANDLER_BUSY, TX_INTR_PENDING, RX_HANDLER_BUSY, RX_DMA_BUSY, RX_INTR_PENDING }; enum { AFT_FE_CFG_ERR, AFT_FE_CFG, AFT_FE_INTR, AFT_FE_POLL, AFT_FE_TDM_RBS, AFT_FE_LED, AFT_FE_EC_POLL, AFT_FE_RESTART, AFT_RTP_TAP_Q }; #define MAX_IP_ERRORS 10 #define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) #if 1 # define TRUE_FIFO_SIZE 1 #else # undef TRUE_FIFO_SIZE # define HARD_FIFO_CODE 0x1F #endif /* Remove HDLC Address * 1=Remove Enabled * 0=Remove Disabled */ #if 0 #define WANPIPE_CODEC_CONVERTER 1 #else #undef WANPIPE_CODEC_CONVERTER #endif static int aft_rx_copyback=500; /******Data Structures*****************************************************/ /* This structure is placed in the private data area of the device structure. * The card structure used to occupy the private area but now the following * structure will incorporate the card structure along with Protocol specific data */ /* Route Status options */ #define NO_ROUTE 0x00 #define ADD_ROUTE 0x01 #define ROUTE_ADDED 0x02 #define REMOVE_ROUTE 0x03 #define WP_WAIT 0 #define WP_NO_WAIT 1 /* variable for keeping track of enabling/disabling FT1 monitor status */ /* static int rCount; */ /* Function interface between WANPIPE layer and kernel */ extern wan_iface_t wan_iface; extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); /**SECTOIN************************************************** * * Function Prototypes * ***********************************************************/ int wp_aft_te1default_devcfg(sdla_t* card, wandev_conf_t* conf); int wp_aft_te1default_ifcfg(sdla_t* card, wanif_conf_t* conf); /* WAN link driver entry points. These are called by the WAN router module. */ static int update (wan_device_t* wandev); static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf); static int del_if(wan_device_t *wandev, netdevice_t *dev); /* Network device interface */ #if defined(__LINUX__) static int if_init (netdevice_t* dev); #endif static int if_open (netdevice_t* dev); static int if_close (netdevice_t* dev); static int if_do_ioctl(netdevice_t*, struct ifreq*, wan_ioctl_cmd_t); #if defined(__LINUX__) static int if_send (netskb_t* skb, netdevice_t* dev); static int if_change_mtu(netdevice_t *dev, int new_mtu); static struct net_device_stats* if_stats (netdevice_t* dev); #else static int if_send(netdevice_t*, netskb_t*, struct sockaddr*,struct rtentry*); #endif static void handle_front_end_state(void* card_id); static void enable_timer(void* card_id); static void enable_ec_timer(void* card_id); static void if_tx_timeout (netdevice_t *dev); /* Miscellaneous Functions */ static void port_set_state (sdla_t *card, int); static void disable_comm (sdla_t *card); /* Interrupt handlers */ static WAN_IRQ_RETVAL wp_aft_global_isr (sdla_t* card); static void wp_aft_dma_per_port_isr(sdla_t *card); static void wp_aft_tdmv_per_port_isr(sdla_t *card); static void wp_aft_fifo_per_port_isr(sdla_t *card); static void wp_aft_wdt_per_port_isr(sdla_t *card, int wdt_intr); static void wp_aft_serial_status_isr(sdla_t *card, u32 status); /* Bottom half handlers */ #if defined(__LINUX__) static void wp_bh (unsigned long); static void wp_tdm_bh (unsigned long); #else static void wp_bh (void*,int); static void wp_tdm_bh (void*,int); #endif /* Miscellaneous functions */ static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, private_area_t*, int local_dev); static int aft_global_chip_configuration(sdla_t *card, wandev_conf_t* conf); static int aft_global_chip_disable(sdla_t *card); static int aft_chip_configure(sdla_t *card, wandev_conf_t* conf); static int aft_chip_unconfigure(sdla_t *card); static int aft_dev_configure(sdla_t *card, private_area_t *chan, wanif_conf_t* conf); static void aft_dev_unconfigure(sdla_t *card, private_area_t *chan); static int aft_dma_rx(sdla_t *card, private_area_t *chan); static void aft_dev_enable(sdla_t *card, private_area_t *chan); static void aft_dev_close(sdla_t *card, private_area_t *chan); static void aft_dev_open(sdla_t *card, private_area_t *gchan); static void aft_dma_tx_complete (sdla_t *card, private_area_t *chan,int wdt, int reset); static int aft_dma_rx_complete(sdla_t *card, private_area_t *chan, int reset); static int aft_init_rx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char); static int aft_init_tx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char); static void aft_tx_post_complete (sdla_t *card, private_area_t *chan, netskb_t *skb); static void aft_rx_post_complete (sdla_t *card, private_area_t *chan, netskb_t *skb, netskb_t **new_skb, unsigned char *pkt_error); static int aft_dma_rx_tdmv(sdla_t *card, private_area_t *chan); #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) static int aft_voice_span_rx_tx(sdla_t *card, int rotate); #endif static int aft_tdmapi_mtu_check(sdla_t *card_ptr, unsigned int *mtu); static void aft_channel_txdma_ctrl(sdla_t *card, private_area_t *chan, int on); static void aft_channel_rxdma_ctrl(sdla_t *card, private_area_t *chan, int on); static void aft_channel_txintr_ctrl(sdla_t *card, private_area_t *chan, int on); static void aft_channel_rxintr_ctrl(sdla_t *card, private_area_t *chan, int on); static int aft_read_security(sdla_t *card); static int aft_front_end_mismatch_check(sdla_t * card); static int aft_tslot_sync_ctrl(sdla_t *card, private_area_t *chan, int mode); #if defined(__LINUX__) # if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) static void aft_port_task (void * card_ptr); # else static void aft_port_task (struct work_struct *work); # endif #else static void aft_port_task (void * card_ptr, int arg); #endif #if defined(AFT_RTP_SUPPORT) static int aft_rtp_config(sdla_t *card); static void aft_rtp_unconfig(sdla_t *card); static void aft_rtp_tap(void *card_ptr, u8 chan, u8* rx, u8* tx, u32 len); #endif static int aft_devel_ioctl(sdla_t *card,struct ifreq *ifr); static int aft_write_bios(sdla_t *card, wan_cmd_api_t *api_cmd); static int aft_write(sdla_t *card, wan_cmd_api_t *api_cmd); static int aft_read(sdla_t *card, wan_cmd_api_t *api_cmd); static int aft_fe_write(sdla_t *card, wan_cmd_api_t *api_cmd); static int aft_fe_read(sdla_t *card, wan_cmd_api_t *api_cmd); static void front_end_interrupt(sdla_t *card, unsigned long reg, int lock); static void enable_data_error_intr(sdla_t *card); static void disable_data_error_intr(sdla_t *card, unsigned char); static void aft_tx_fifo_under_recover (sdla_t *card, private_area_t *chan); static void aft_rx_fifo_over_recover(sdla_t *card, private_area_t *chan); static int set_chan_state(sdla_t* card, netdevice_t* dev, int state); static int update_comms_stats(sdla_t* card); static int protocol_init (sdla_t*card,netdevice_t *dev, private_area_t *chan, wanif_conf_t* conf); static int protocol_stop (sdla_t *card, netdevice_t *dev); static int protocol_shutdown (sdla_t *card, netdevice_t *dev); static void protocol_recv(sdla_t *card, private_area_t *chan, netskb_t *skb); static int aft_alloc_rx_dma_buff(sdla_t *card, private_area_t *chan, int num, int irq); static int aft_init_requeue_free_skb(private_area_t *chan, netskb_t *skb); static int aft_dma_tx (sdla_t *card,private_area_t *chan); static void aft_tx_dma_chain_handler(unsigned long data, int wdt, int reset); static void aft_tx_dma_voice_handler(unsigned long data, int wdt, int reset); static void aft_tx_dma_chain_init(private_area_t *chan, wan_dma_descr_t *); static void aft_rx_dma_chain_init(private_area_t *chan, wan_dma_descr_t *); static void aft_index_tx_rx_dma_chains(private_area_t *chan); static void aft_init_tx_rx_dma_descr(private_area_t *chan); static void aft_free_rx_complete_list(private_area_t *chan); static void aft_rx_cur_go_test(private_area_t *chan); static void aft_free_rx_descriptors(private_area_t *chan); static void aft_reset_rx_chain_cnt(private_area_t *chan); static void aft_reset_tx_chain_cnt(private_area_t *chan); static void aft_free_tx_descriptors(private_area_t *chan); static int aft_realign_skb_pkt(private_area_t *chan, netskb_t *skb); static void aft_data_mux_cfg(sdla_t *card); static void aft_data_mux_get_cfg(sdla_t *card); static int aft_ss7_tx_mangle(sdla_t *card,private_area_t *chan, netskb_t *skb); static int aft_hdlc_repeat_mangle(sdla_t *card,private_area_t *chan, netskb_t *skb, netskb_t **rkb); static int aft_tdmv_init(sdla_t *card, wandev_conf_t *conf); #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) static int aft_tdmv_free(sdla_t *card); #endif static int aft_tdmv_if_init(sdla_t *card, private_area_t *chan, wanif_conf_t *conf); static int aft_tdmv_if_free(sdla_t *card, private_area_t *chan); static int digital_loop_test(sdla_t* card,wan_udp_pkt_t* wan_udp_pkt); #if 0 static void wp_tdmv_api_chan_rx_tx(sdla_t *card, private_area_t *chan, unsigned char *rxdata, unsigned char *tx_data); static void wp_tdmv_api_rx_tx (sdla_t *card, private_area_t *chan); #endif static int aft_fifo_intr_ctrl(sdla_t *card, int ctrl); static int aft_tdm_intr_ctrl(sdla_t *card, int ctrl); #if defined(__LINUX__) static void aft_set_ss7_force_rx(sdla_t *card, private_area_t *chan); #endif static void aft_clear_ss7_force_rx(sdla_t *card, private_area_t *chan); #if defined(AFT_API_SUPPORT) || defined(AFT_TDM_API_SUPPORT) static int aft_event_ctrl(void *chan_ptr, wan_event_ctrl_t *ctrl); #endif #ifdef AFT_TDM_API_SUPPORT static int aft_read_rbs_bits(void *chan_ptr, u32 ch, u8 *rbs_bits); static int aft_write_rbs_bits(void *chan_ptr, u32 ch, u8 rbs_bits); static int aft_write_hdlc_frame(void *chan_ptr, netskb_t *skb); #endif static int aft_tdm_ring_rsync(sdla_t *card); static void aft_critical_shutdown(sdla_t *card); static int aft_handle_clock_master (sdla_t *card_ptr); /* API VoIP event */ #if defined(AFT_API_SUPPORT) static int wan_aft_api_ioctl(sdla_t *card, private_area_t *chan, char *user_data); static void wan_aft_api_dtmf (void* card_id, wan_event_t *event); static void wan_aft_api_hook (void* card_id, wan_event_t *event); static void wan_aft_api_ringtrip (void* card_id, wan_event_t *event); static void wan_aft_api_ringdetect (void* card_id, wan_event_t *event); #endif static void callback_front_end_state(void *card_id); #if 0 static void aft_list_descriptors(private_area_t *chan); #endif #if 0 static void aft_list_dma_chain_regs(sdla_t *card); #endif #if 0 static void aft_list_tx_descriptors(private_area_t *chan); #endif #if 0 static void aft_display_chain_history(private_area_t *chan); static void aft_chain_history(private_area_t *chan,u8 end, u8 cur, u8 begin, u8 loc); #endif unsigned char aft_read_cpld(sdla_t *card, unsigned short cpld_off); int aft_write_cpld(void *pcard, unsigned short off,unsigned char data); /* Procfs functions */ static int wan_aft_get_info(void* pcard, struct seq_file* m, int* stop_cnt); static int wan_aft_init (sdla_t *card, wandev_conf_t* conf); static unsigned char aft_write_ec (void*, unsigned short, unsigned char); static unsigned char aft_read_ec (void*, unsigned short); static int aft_hwec_config(sdla_t *card, private_area_t *chan, wanif_conf_t *conf, int ctrl); static int aft_find_master_if_and_dchan(sdla_t *card, int *master_if,u32 active_ch); #if defined(NETGRAPH) extern void wan_ng_link_state(wanpipe_common_t *common, int state); #endif #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG static int bind_annexg(netdevice_t *dev, netdevice_t *annexg_dev); static netdevice_t * un_bind_annexg(wan_device_t *wandev, netdevice_t* annexg_dev_name); static int get_map(wan_device_t*, netdevice_t*, struct seq_file* m, int*); static void get_active_inactive(wan_device_t *wandev, netdevice_t *dev, void *wp_stats); #endif /**SECTION********************************************************* * * Public Functions * ******************************************************************/ int wp_aft_te1default_devcfg(sdla_t* card, wandev_conf_t* conf) { conf->config_id = WANCONFIG_AFT_TE1; conf->u.aft.dma_per_ch = MAX_RX_BUF; conf->u.aft.mru = 1500; return 0; } int wp_aft_te1default_ifcfg(sdla_t* card, wanif_conf_t* conf) { conf->protocol = WANCONFIG_HDLC; memcpy(conf->usedby, "WANPIPE", 7); conf->if_down = 0; conf->ignore_dcd = WANOPT_NO; conf->ignore_cts = WANOPT_NO; conf->hdlc_streaming = WANOPT_NO; conf->mc = 0; conf->gateway = 0; conf->active_ch = ENABLE_ALL_CHANNELS; return 0; } #if 0 static void aft_delay(int sec) { #if 1 unsigned long timeout=SYSTEM_TICKS; while ((SYSTEM_TICKS-timeout)<(sec*HZ)){ schedule(); } #endif } #endif int aft_global_hw_device_init(void) { memset(aft_hwdev,0,sizeof(aft_hwdev)); #if defined(CONFIG_PRODUCT_WANPIPE_AFT_TE1) aft_hwdev[WANOPT_AFT104].init = 1; aft_hwdev[WANOPT_AFT104].aft_global_chip_config = a104_global_chip_config; aft_hwdev[WANOPT_AFT104].aft_global_chip_unconfig = a104_global_chip_unconfig; aft_hwdev[WANOPT_AFT104].aft_chip_config = a104_chip_config; aft_hwdev[WANOPT_AFT104].aft_chip_unconfig = a104_chip_unconfig; aft_hwdev[WANOPT_AFT104].aft_chan_config = a104_chan_dev_config; aft_hwdev[WANOPT_AFT104].aft_chan_unconfig = a104_chan_dev_unconfig; aft_hwdev[WANOPT_AFT104].aft_led_ctrl = a104_led_ctrl; aft_hwdev[WANOPT_AFT104].aft_test_sync = a104_test_sync; aft_hwdev[WANOPT_AFT104].aft_read_cpld = aft_te1_read_cpld; aft_hwdev[WANOPT_AFT104].aft_write_cpld = aft_te1_write_cpld; aft_hwdev[WANOPT_AFT104].aft_fifo_adjust = a104_fifo_adjust; aft_hwdev[WANOPT_AFT104].aft_check_ec_security = a104_check_ec_security; #endif #if defined(CONFIG_PRODUCT_WANPIPE_AFT_SERIAL) aft_hwdev[WANOPT_AFT_SERIAL].init = 1; aft_hwdev[WANOPT_AFT_SERIAL].aft_global_chip_config = a104_global_chip_config; aft_hwdev[WANOPT_AFT_SERIAL].aft_global_chip_unconfig = a104_global_chip_unconfig; aft_hwdev[WANOPT_AFT_SERIAL].aft_chip_config = a104_chip_config; aft_hwdev[WANOPT_AFT_SERIAL].aft_chip_unconfig = a104_chip_unconfig; aft_hwdev[WANOPT_AFT_SERIAL].aft_chan_config = a104_chan_dev_config; aft_hwdev[WANOPT_AFT_SERIAL].aft_chan_unconfig = a104_chan_dev_unconfig; aft_hwdev[WANOPT_AFT_SERIAL].aft_led_ctrl = a104_led_ctrl; aft_hwdev[WANOPT_AFT_SERIAL].aft_test_sync = a104_test_sync; aft_hwdev[WANOPT_AFT_SERIAL].aft_read_cpld = aft_te1_read_cpld; aft_hwdev[WANOPT_AFT_SERIAL].aft_write_cpld = aft_te1_write_cpld; aft_hwdev[WANOPT_AFT_SERIAL].aft_fifo_adjust = a104_fifo_adjust; aft_hwdev[WANOPT_AFT_SERIAL].aft_check_ec_security = a104_check_ec_security; #endif #if defined(CONFIG_PRODUCT_WANPIPE_AFT_RM) aft_hwdev[WANOPT_AFT_ANALOG].init = 1; aft_hwdev[WANOPT_AFT_ANALOG].aft_global_chip_config = aft_analog_global_chip_config; aft_hwdev[WANOPT_AFT_ANALOG].aft_global_chip_unconfig = aft_analog_global_chip_unconfig; aft_hwdev[WANOPT_AFT_ANALOG].aft_chip_config = aft_analog_chip_config; aft_hwdev[WANOPT_AFT_ANALOG].aft_chip_unconfig = aft_analog_chip_unconfig; aft_hwdev[WANOPT_AFT_ANALOG].aft_chan_config = aft_analog_chan_dev_config; aft_hwdev[WANOPT_AFT_ANALOG].aft_chan_unconfig = aft_analog_chan_dev_unconfig; aft_hwdev[WANOPT_AFT_ANALOG].aft_led_ctrl = aft_analog_led_ctrl; aft_hwdev[WANOPT_AFT_ANALOG].aft_test_sync = aft_analog_test_sync; aft_hwdev[WANOPT_AFT_ANALOG].aft_read_cpld = aft_analog_read_cpld; aft_hwdev[WANOPT_AFT_ANALOG].aft_write_cpld = aft_analog_write_cpld; aft_hwdev[WANOPT_AFT_ANALOG].aft_fifo_adjust = aft_analog_fifo_adjust; aft_hwdev[WANOPT_AFT_ANALOG].aft_check_ec_security = a200_check_ec_security; #endif #if defined(CONFIG_PRODUCT_WANPIPE_AFT_BRI) aft_hwdev[WANOPT_AFT_ISDN].init = 1; aft_hwdev[WANOPT_AFT_ISDN].aft_global_chip_config = aft_bri_global_chip_config; aft_hwdev[WANOPT_AFT_ISDN].aft_global_chip_unconfig = aft_bri_global_chip_unconfig; aft_hwdev[WANOPT_AFT_ISDN].aft_chip_config = aft_bri_chip_config; aft_hwdev[WANOPT_AFT_ISDN].aft_chip_unconfig = aft_bri_chip_unconfig; aft_hwdev[WANOPT_AFT_ISDN].aft_chan_config = aft_bri_chan_dev_config; aft_hwdev[WANOPT_AFT_ISDN].aft_chan_unconfig = aft_bri_chan_dev_unconfig; aft_hwdev[WANOPT_AFT_ISDN].aft_led_ctrl = aft_bri_led_ctrl; aft_hwdev[WANOPT_AFT_ISDN].aft_test_sync = aft_bri_test_sync; aft_hwdev[WANOPT_AFT_ISDN].aft_read_cpld = aft_bri_read_cpld; aft_hwdev[WANOPT_AFT_ISDN].aft_write_cpld = aft_bri_write_cpld; aft_hwdev[WANOPT_AFT_ISDN].aft_fifo_adjust = aft_bri_fifo_adjust; aft_hwdev[WANOPT_AFT_ISDN].aft_check_ec_security = bri_check_ec_security; #endif #if defined(CONFIG_PRODUCT_WANPIPE_AFT_56K) aft_hwdev[WANOPT_AFT_56K].init = 1; aft_hwdev[WANOPT_AFT_56K].aft_global_chip_config = a104_global_chip_config; aft_hwdev[WANOPT_AFT_56K].aft_global_chip_unconfig = a104_global_chip_unconfig; aft_hwdev[WANOPT_AFT_56K].aft_chip_config = a104_chip_config; aft_hwdev[WANOPT_AFT_56K].aft_chip_unconfig = a104_chip_unconfig; aft_hwdev[WANOPT_AFT_56K].aft_chan_config = a104_chan_dev_config; aft_hwdev[WANOPT_AFT_56K].aft_chan_unconfig = a104_chan_dev_unconfig; aft_hwdev[WANOPT_AFT_56K].aft_led_ctrl = a104_led_ctrl; aft_hwdev[WANOPT_AFT_56K].aft_test_sync = a104_test_sync; aft_hwdev[WANOPT_AFT_56K].aft_read_cpld = aft_56k_read_cpld; aft_hwdev[WANOPT_AFT_56K].aft_write_cpld = aft_56k_write_cpld; aft_hwdev[WANOPT_AFT_56K].aft_fifo_adjust = a104_fifo_adjust; aft_hwdev[WANOPT_AFT_56K].aft_check_ec_security = a104_check_ec_security; #endif return 0; } /*============================================================================ * wp_aft_te1_init - Cisco HDLC protocol initialization routine. * * @card: Wanpipe card pointer * @conf: User hardware/firmware/general protocol configuration * pointer. * * This routine is called by the main WANPIPE module * during setup: ROUTER_SETUP ioctl(). * * At this point adapter is completely initialized * and firmware is running. * o read firmware version (to make sure it's alive) * o configure adapter * o initialize protocol-specific fields of the adapter data space. * * Return: 0 o.k. * < 0 failure. */ #if defined(CONFIG_PRODUCT_WANPIPE_AFT_RM) int wp_aft_analog_init (sdla_t *card, wandev_conf_t* conf) { /* Verify configuration ID */ if (card->wandev.config_id != WANCONFIG_AFT_ANALOG) { DEBUG_EVENT( "%s: invalid configuration ID %u!\n", card->devname, card->wandev.config_id); return -EINVAL; } ASSERT_AFT_HWDEV(card->wandev.card_type); card->hw_iface.getcfg(card->hw, SDLA_COREREV, &card->u.aft.firm_ver); card->hw_iface.getcfg(card->hw, SDLA_COREID, &card->u.aft.firm_id); if (card->u.aft.firm_ver < AFT_MIN_ANALOG_FRMW_VER){ DEBUG_EVENT( "%s: Invalid/Obselete AFT ANALOG firmware version %X (not >= %X)!\n", card->devname, card->u.aft.firm_ver,AFT_MIN_ANALOG_FRMW_VER); DEBUG_EVENT( "%s Refer to /usr/share/doc/wanpipe/README.aft_firm_update\n", card->devname); DEBUG_EVENT( "%s: Please contact Sangoma Technologies for more info.\n", card->devname); return -EINVAL; } if (conf == NULL){ DEBUG_EVENT("%s: Bad configuration structre!\n", card->devname); return -EINVAL; } /* Make special hardware initialization for Analog board */ memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); wp_remora_iface_init(&card->fe, &card->wandev.fe_iface); card->fe.name = card->devname; card->fe.card = card; card->fe.write_fe_reg = card->hw_iface.fe_write; /* aft_analog_write_fe; */ card->fe.read_fe_reg = card->hw_iface.fe_read; /* aft_analog_read_fe; */ card->fe.__read_fe_reg = card->hw_iface.__fe_read; /* __aft_analog_read_fe; */ card->wandev.fe_enable_timer = enable_timer; card->wandev.ec_enable_timer = enable_ec_timer; card->wandev.te_link_state = callback_front_end_state; if (card->wandev.comm_port == WANOPT_PRI){ conf->clocking = WANOPT_EXTERNAL; } card->wandev.comm_port=card->fe.fe_cfg.line_no; if (card->wandev.comm_port != 0){ DEBUG_EVENT("%s: Error: Invalid port selected %d (Port 1)\n", card->devname,card->wandev.comm_port); return -EINVAL; } card->u.aft.num_of_time_slots=MAX_REMORA_MODULES; return wan_aft_init(card,conf); } #endif #if defined(CONFIG_PRODUCT_WANPIPE_AFT_BRI) int wp_aft_bri_init (sdla_t *card, wandev_conf_t* conf) { /* Verify configuration ID */ if (card->wandev.config_id != WANCONFIG_AFT_ISDN_BRI) { DEBUG_EVENT( "%s: invalid configuration ID %u!\n", card->devname, card->wandev.config_id); return -EINVAL; } ASSERT_AFT_HWDEV(card->wandev.card_type); card->hw_iface.getcfg(card->hw, SDLA_COREREV, &card->u.aft.firm_ver); card->hw_iface.getcfg(card->hw, SDLA_COREID, &card->u.aft.firm_id); /* FIXME:hardcoded!! */ card->u.aft.firm_id = AFT_DS_FE_CORE_ID; if (conf == NULL){ DEBUG_EVENT("%s: Bad configuration structre!\n", card->devname); return -EINVAL; } /* Make special hardware initialization for ISDN BRI board */ memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); wp_bri_iface_init(&card->wandev.fe_iface); card->fe.name = card->devname; card->fe.card = card; card->fe.write_fe_reg = aft_bri_write_fe; card->fe.read_fe_reg = aft_bri_read_fe; card->fe.__read_fe_reg = __aft_bri_read_fe; card->wandev.fe_enable_timer = enable_timer; card->wandev.ec_enable_timer = enable_ec_timer; card->wandev.te_link_state = callback_front_end_state; if (card->wandev.comm_port == WANOPT_PRI){ conf->clocking = WANOPT_EXTERNAL; } #if 1 card->wandev.comm_port=0; if (card->fe.fe_cfg.line_no >= MAX_BRI_MODULES) { card->wandev.comm_port=1; } #else card->wandev.comm_port=card->fe.fe_cfg.line_no; #endif DEBUG_EVENT("%s: BRI CARD Line=%i Port=%i\n", card->devname, card->wandev.comm_port, card->fe.fe_cfg.line_no); /* Set 'num_of_time_slots' to 31. This is needed for the d-chan, which is always at the otherwise unused timeslot 31. */ card->u.aft.num_of_time_slots = MAX_TIMESLOTS; return wan_aft_init(card,conf); } #endif #if defined(CONFIG_PRODUCT_WANPIPE_AFT_SERIAL) int wp_aft_serial_init (sdla_t *card, wandev_conf_t* conf) { /* Verify configuration ID */ if (card->wandev.config_id != WANCONFIG_AFT_SERIAL) { DEBUG_EVENT( "%s: invalid configuration ID %u!\n", card->devname, card->wandev.config_id); return -EINVAL; } ASSERT_AFT_HWDEV(card->wandev.card_type); card->hw_iface.getcfg(card->hw, SDLA_COREREV, &card->u.aft.firm_ver); card->hw_iface.getcfg(card->hw, SDLA_COREID, &card->u.aft.firm_id); if (card->u.aft.firm_ver < AFT_SERIAL_MIN_FRMW_VER){ DEBUG_EVENT( "%s: Invalid/Obselete AFT firmware version %X (not >= %X)!\n", card->devname, card->u.aft.firm_ver,AFT_SERIAL_MIN_FRMW_VER); DEBUG_EVENT( "%s You seem to be running BETA hardware that is not supported any more.\n", card->devname); DEBUG_EVENT( "%s: Please contact Sangoma Technologies for more info.\n", card->devname); return -EINVAL; } if (conf == NULL){ DEBUG_EVENT("%s: Bad configuration structre!\n", card->devname); return -EINVAL; } /* Make special hardware initialization for Serial board */ memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); FE_MEDIA(&(card->fe.fe_cfg)) = WAN_MEDIA_SERIAL; wp_serial_iface_init(&card->wandev.fe_iface); card->fe.name = card->devname; card->fe.card = card; card->fe.write_fe_reg = card->hw_iface.fe_write; /*aft_serial_write_fe;*/ card->fe.read_fe_reg = card->hw_iface.fe_read; /*aft_serial_read_fe;*/ card->fe.__read_fe_reg = card->hw_iface.__fe_read; /*__aft_serial_read_fe;*/ card->wandev.fe_enable_timer = enable_timer; card->wandev.ec_enable_timer = enable_ec_timer; card->wandev.te_link_state = callback_front_end_state; card->wandev.comm_port=card->fe.fe_cfg.line_no; DEBUG_EVENT("%s: Serial A140 CARD Line=%i Port=%i Firm=0x%02X ID=0x%X\n", card->devname, card->wandev.comm_port, card->fe.fe_cfg.line_no, card->u.aft.firm_ver,card->u.aft.firm_id); card->u.aft.num_of_time_slots = 1; return wan_aft_init(card,conf); } #endif #if defined(CONFIG_PRODUCT_WANPIPE_AFT_TE1) int wp_aft_te1_init (sdla_t* card, wandev_conf_t* conf) { AFT_FUNC_DEBUG(); wan_set_bit(CARD_DOWN,&card->wandev.critical); /* Verify configuration ID */ if (card->wandev.config_id != WANCONFIG_AFT_TE1) { DEBUG_EVENT( "%s: invalid configuration ID %u!\n", card->devname, card->wandev.config_id); return -EINVAL; } card->hw_iface.getcfg(card->hw, SDLA_COREREV, &card->u.aft.firm_ver); card->hw_iface.getcfg(card->hw, SDLA_COREID, &card->u.aft.firm_id); if (card->u.aft.firm_ver < AFT_MIN_FRMW_VER){ DEBUG_EVENT( "%s: Invalid/Obselete AFT firmware version %X (not >= %X)!\n", card->devname, card->u.aft.firm_ver,AFT_MIN_FRMW_VER); DEBUG_EVENT( "%s Refer to /usr/share/doc/wanpipe/README.aft_firm_update\n", card->devname); DEBUG_EVENT( "%s: Please contact Sangoma Technologies for more info.\n", card->devname); return -EINVAL; } ASSERT_AFT_HWDEV(card->wandev.card_type); if (conf == NULL){ DEBUG_EVENT("%s: Bad configuration structre!\n", card->devname); return -EINVAL; } /* TE1 Make special hardware initialization for T1/E1 board */ if (IS_TE1_MEDIA(&conf->fe_cfg)){ int max_ports = 4; if (conf->fe_cfg.cfg.te_cfg.active_ch == 0){ conf->fe_cfg.cfg.te_cfg.active_ch = -1; } memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); if (card->u.aft.firm_id == AFT_DS_FE_CORE_ID) { max_ports = 8; sdla_ds_te1_iface_init(&card->fe, &card->wandev.fe_iface); }else{ sdla_te_iface_init(&card->fe, &card->wandev.fe_iface); } card->fe.name = card->devname; card->fe.card = card; card->fe.write_fe_reg = card->hw_iface.fe_write; /*a104_write_fe;*/ card->fe.read_fe_reg = card->hw_iface.fe_read; /*a104_read_fe;*/ card->fe.__read_fe_reg = card->hw_iface.__fe_read; /*__a104_read_fe;*/ card->wandev.fe_enable_timer = enable_timer; card->wandev.ec_enable_timer = enable_ec_timer; card->wandev.te_link_state = callback_front_end_state; conf->electrical_interface = IS_T1_CARD(card) ? WANOPT_V35 : WANOPT_RS232; if (card->wandev.comm_port == WANOPT_PRI){ conf->clocking = WANOPT_EXTERNAL; } card->wandev.comm_port=card->fe.fe_cfg.line_no; if (IS_T1_CARD(card)){ card->u.aft.num_of_time_slots=NUM_OF_T1_CHANNELS; }else{ card->u.aft.num_of_time_slots=NUM_OF_E1_CHANNELS; } }else{ DEBUG_EVENT("%s: Invalid Front-End media type!!\n", card->devname); return -EINVAL; } return wan_aft_init(card,conf); } #endif #if defined(CONFIG_PRODUCT_WANPIPE_AFT_56K) int wp_aft_56k_init (sdla_t* card, wandev_conf_t* conf) { AFT_FUNC_DEBUG(); wan_set_bit(CARD_DOWN,&card->wandev.critical); /* Verify configuration ID */ if (card->wandev.config_id != WANCONFIG_AFT_56K) { DEBUG_EVENT( "%s: invalid configuration ID %u!\n", card->devname, card->wandev.config_id); return -EINVAL; } card->hw_iface.getcfg(card->hw, SDLA_COREREV, &card->u.aft.firm_ver); card->hw_iface.getcfg(card->hw, SDLA_COREID, &card->u.aft.firm_id); #if 0 if (card->u.aft.firm_ver < AFT_56K_MIN_FRMW_VER){ DEBUG_EVENT( "%s: Invalid/Obselete AFT firmware version %X (not >= %X)!\n", card->devname, card->u.aft.firm_ver,AFT_56K_MIN_FRMW_VER); DEBUG_EVENT( "%s Refer to /usr/share/doc/wanpipe/README.aft_firm_update\n", card->devname); DEBUG_EVENT( "%s: Please contact Sangoma Technologies for more info.\n", card->devname); return -EINVAL; } #endif ASSERT_AFT_HWDEV(card->wandev.card_type); if (conf == NULL){ DEBUG_EVENT("%s: Bad configuration structre!\n", card->devname); return -EINVAL; } if (IS_56K_MEDIA(&conf->fe_cfg)){ conf->fe_cfg.cfg.te_cfg.active_ch = 1; memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t)); DEBUG_56K("card->u.aft.firm_id: 0x%X\n", card->u.aft.firm_id); /* if(card->u.aft.firm_id != AFT_56K_FE_CORE_ID){ DEBUG_EVENT("%s: Invalid (56K) Firmware ID: 0x%X!\n", card->devname, card->u.aft.firm_id); return -EINVAL; } */ sdla_56k_iface_init(&card->fe, &card->wandev.fe_iface); card->fe.name = card->devname; card->fe.card = card; card->fe.write_fe_reg = card->hw_iface.fe_write; /* a56k_write_fe;*/ card->fe.read_fe_reg = card->hw_iface.fe_read; /* a56k_read_fe; */ card->fe.__read_fe_reg = card->hw_iface.__fe_read; /* __a56k_read_fe; */ card->wandev.fe_enable_timer = enable_timer; card->wandev.ec_enable_timer = enable_ec_timer; card->wandev.te_link_state = callback_front_end_state; card->wandev.comm_port=0; card->u.aft.num_of_time_slots=1; }else{ DEBUG_EVENT("%s: Invalid Front-End media type!!\n", card->devname); return -EINVAL; } return wan_aft_init(card,conf); } #endif static int wan_aft_init (sdla_t *card, wandev_conf_t* conf) { int err; int used_cnt; /* Obtain hardware configuration parameters */ card->wandev.clocking = conf->clocking; card->wandev.ignore_front_end_status = conf->ignore_front_end_status; card->wandev.ttl = conf->ttl; card->wandev.electrical_interface = conf->electrical_interface; card->wandev.udp_port = conf->udp_port; card->wandev.new_if_cnt = 0; wan_atomic_set(&card->wandev.if_cnt,0); card->u.aft.chip_security_cnt=0; memcpy(&card->u.aft.cfg,&conf->u.aft,sizeof(wan_xilinx_conf_t)); memcpy(&card->rtp_conf,&conf->rtp_conf,sizeof(conf->rtp_conf)); memset(card->u.aft.dev_to_ch_map,0,sizeof(card->u.aft.dev_to_ch_map)); memcpy(&card->tdmv_conf,&conf->tdmv_conf,sizeof(wan_tdmv_conf_t)); memcpy(&card->hwec_conf,&conf->hwec_conf,sizeof(wan_hwec_conf_t)); card->u.aft.cfg.dma_per_ch = MAX_RX_BUF; card->u.aft.tdmv_api_rx = NULL; card->u.aft.tdmv_api_tx = NULL; card->u.aft.tdmv_dchan=0; wan_skb_queue_init(&card->u.aft.tdmv_api_tx_list); wan_skb_queue_init(&card->u.aft.rtp_tap_list); if (card->wandev.ignore_front_end_status == WANOPT_NO){ DEBUG_EVENT( "%s: Enabling front end link monitor\n", card->devname); }else{ DEBUG_EVENT( "%s: Disabling front end link monitor\n", card->devname); } AFT_FUNC_DEBUG(); /* WARNING: After this point the init function * must return with 0. The following bind * functions will cause problems if structures * below are not initialized */ card->wandev.update = &update; card->wandev.new_if = &new_if; card->wandev.del_if = &del_if; card->disable_comm = NULL; #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG card->wandev.bind_annexg = &bind_annexg; card->wandev.un_bind_annexg = &un_bind_annexg; card->wandev.get_map = &get_map; card->wandev.get_active_inactive= &get_active_inactive; #endif #ifdef WANPIPE_ENABLE_PROC_FILE_HOOKS /* Proc fs functions hooks */ card->wandev.get_config_info = &get_config_info; card->wandev.get_status_info = &get_status_info; card->wandev.get_dev_config_info= &get_dev_config_info; card->wandev.get_if_info = &get_if_info; card->wandev.set_dev_config = &set_dev_config; card->wandev.set_if_info = &set_if_info; #endif card->wandev.get_info = &wan_aft_get_info; /* Setup Port Bps */ if(card->wandev.clocking) { card->wandev.bps = conf->bps; }else{ card->wandev.bps = 0; } /* For Primary Port 0 */ #ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE card->wandev.mtu = conf->mtu; card->wan_tdmv.sc = NULL; #else card->wandev.mtu=conf->mtu; if (card->wandev.mtu > MAX_WP_PRI_MTU || card->wandev.mtu < MIN_WP_PRI_MTU){ DEBUG_EVENT("%s: Error Invalid Global MTU %d (Min=%d, Max=%d)\n", card->devname,card->wandev.mtu, MIN_WP_PRI_MTU,MAX_WP_PRI_MTU); return -EINVAL; } #endif if (!card->u.aft.cfg.mru){ card->u.aft.cfg.mru = card->wandev.mtu; } if (card->u.aft.cfg.mru > MAX_WP_PRI_MTU || card->u.aft.cfg.mru < MIN_WP_PRI_MTU){ DEBUG_EVENT("%s: Error Invalid Global MRU %d (Min=%d, Max=%d)\n", card->devname,card->u.aft.cfg.mru, MIN_WP_PRI_MTU,MAX_WP_PRI_MTU); return -EINVAL; } card->hw_iface.getcfg(card->hw, SDLA_BASEADDR, &card->u.aft.bar); card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &card->u.aft.bar_virt); port_set_state(card,WAN_CONNECTING); WAN_TASKQ_INIT((&card->u.aft.port_task),0,aft_port_task,card); card->u.aft.chip_cfg_status=0; card->hw_iface.getcfg(card->hw, SDLA_HWCPU_USEDCNT, &used_cnt); /* ====================================================================== * After this point we must call disable_comm() if we fail to configure * =====================================================================*/ wan_clear_bit(CARD_DOWN,&card->wandev.critical); __sdla_push_ptr_isr_array(card->hw,card,WAN_FE_LINENO(&card->fe)); card->isr = &wp_aft_global_isr; if (used_cnt==1){ DEBUG_EVENT("%s: Global Chip Configuration: used=%d\n", card->devname,used_cnt); err=aft_global_chip_configuration(card, conf); if (err){ aft_global_chip_disable(card); disable_comm(card); wan_set_bit(CARD_DOWN,&card->wandev.critical); return err; } aft_data_mux_cfg(card); }else{ aft_data_mux_get_cfg(card); err=aft_front_end_mismatch_check(card); if (err){ disable_comm(card); wan_set_bit(CARD_DOWN,&card->wandev.critical); return err; } DEBUG_EVENT("%s: Global Chip Configuration skiped: used=%d\n", card->devname,used_cnt); } card->wandev.ec_intmask=SYSTEM_TICKS; aft_read_security(card); err=aft_chip_configure(card,conf); if (err){ AFT_FUNC_DEBUG(); aft_chip_unconfigure(card); if (used_cnt==1){ aft_global_chip_disable(card); } disable_comm(card); wan_set_bit(CARD_DOWN,&card->wandev.critical); return err; } wan_set_bit(AFT_CHIP_CONFIGURED,&card->u.aft.chip_cfg_status); if (wan_test_bit(AFT_FRONT_END_UP,&card->u.aft.chip_cfg_status)){ wan_smp_flag_t smp_flags; DEBUG_TEST("%s: Front end up, retrying enable front end!\n", card->devname); wan_spin_lock_irq(&card->wandev.lock,&smp_flags); handle_front_end_state(card); wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); wan_clear_bit(AFT_FRONT_END_UP,&card->u.aft.chip_cfg_status); } AFT_FUNC_DEBUG(); aft_read_security(card); DEBUG_EVENT("%s: Configuring Device :%s FrmVr=%02X\n", card->devname,card->devname,card->u.aft.firm_ver); DEBUG_EVENT("%s: Global MTU = %d\n", card->devname, card->wandev.mtu); DEBUG_EVENT("%s: Global MRU = %d\n", card->devname, card->u.aft.cfg.mru); DEBUG_EVENT("%s: Data Mux Map = 0x%08X\n", card->devname, card->u.aft.cfg.data_mux_map); DEBUG_EVENT("%s: Rx CRC Bytes = %i\n", card->devname, card->u.aft.cfg.rx_crc_bytes); wan_clear_bit(AFT_TDM_GLOBAL_ISR,&card->u.aft.chip_cfg_status); wan_clear_bit(AFT_TDM_RING_BUF,&card->u.aft.chip_cfg_status); if (card->u.aft.firm_id == AFT_DS_FE_CORE_ID) { if ((card->adptr_type == A108_ADPTR_8TE1 && card->u.aft.firm_ver >= 0x27) || (card->adptr_type == A104_ADPTR_4TE1 && card->u.aft.firm_ver >= 0x26) || (card->adptr_type == A101_ADPTR_2TE1 && card->u.aft.firm_ver >= 0x26) || (card->adptr_type == A101_ADPTR_1TE1 && card->u.aft.firm_ver >= 0x26)) { wan_set_bit(AFT_TDM_GLOBAL_ISR,&card->u.aft.chip_cfg_status); wan_set_bit(AFT_TDM_RING_BUF,&card->u.aft.chip_cfg_status); } } else { if ((card->adptr_type == A104_ADPTR_4TE1 && card->adptr_subtype == AFT_SUBTYPE_SHARK && card->u.aft.firm_ver >= 0x23)) { wan_set_bit(AFT_TDM_GLOBAL_ISR,&card->u.aft.chip_cfg_status); wan_set_bit(AFT_TDM_RING_BUF,&card->u.aft.chip_cfg_status); } } if(IS_BRI_CARD(card)){ wan_set_bit(AFT_TDM_GLOBAL_ISR,&card->u.aft.chip_cfg_status); wan_set_bit(AFT_TDM_RING_BUF,&card->u.aft.chip_cfg_status); } if (card->wandev.config_id == WANCONFIG_AFT_ANALOG) { wan_set_bit(AFT_TDM_SW_RING_BUF,&card->u.aft.chip_cfg_status); } DEBUG_EVENT("%s: Global TDM Int = %s\n", card->devname, wan_test_bit(AFT_TDM_GLOBAL_ISR,&card->u.aft.chip_cfg_status) ? "Enabled" : "Disabled"); DEBUG_EVENT("%s: Global TDM Ring= %s\n", card->devname, wan_test_bit(AFT_TDM_RING_BUF,&card->u.aft.chip_cfg_status) ? "Enabled" : "Disabled"); if (card->wandev.ec_dev){ card->u.aft.tdmv_hw_dtmf = conf->tdmv_conf.hw_dtmf; }else{ card->u.aft.tdmv_hw_dtmf = WANOPT_NO; } DEBUG_EVENT("%s: TDM HW DTMF = %s\n", card->devname, (card->u.aft.tdmv_hw_dtmf == WANOPT_YES) ? "Enabled" : "Disabled"); err=aft_tdmv_init(card,conf); if (err){ disable_comm(card); wan_set_bit(CARD_DOWN,&card->wandev.critical); return err; } card->disable_comm = &disable_comm; #if defined(AFT_RTP_SUPPORT) err=aft_rtp_config(card); DEBUG_EVENT("%s: RTP TAP = %s\n", card->devname, err == 0 ? "Enabled" : "Disabled"); #endif card->wandev.read_ec = aft_read_ec; card->wandev.write_ec = aft_write_ec; return 0; } /**SECTION************************************************************** * * WANPIPE Device Driver Entry Points * * *********************************************************************/ /*============================================================================ * update - Update wanpipe device status & statistics * * @wandev: Wanpipe device pointer * * This procedure is called when updating the PROC file system. * It returns various communications statistics. * * cat /proc/net/wanrouter/wanpipe# (where #=1,2,3...) * * These statistics are accumulated from 3 * different locations: * 1) The 'if_stats' recorded for the device. * 2) Communication error statistics on the adapter. * 3) Operational statistics on the adapter. * * The board level statistics are read during a timer interrupt. * Note that we read the error and operational statistics * during consecitive timer ticks so as to minimize the time * that we are inside the interrupt handler. * */ static int update (wan_device_t* wandev) { sdla_t* card = wandev->priv; netdevice_t* dev; volatile private_area_t* chan; /* sanity checks */ if((wandev == NULL) || (wandev->priv == NULL)) return -EFAULT; if(wandev->state == WAN_UNCONFIGURED) return -ENODEV; if(wan_test_bit(PERI_CRIT, (void*)&card->wandev.critical)) return -EAGAIN; dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); if(dev == NULL) return -ENODEV; if((chan=wan_netif_priv(dev)) == NULL) return -ENODEV; if(card->update_comms_stats){ return -EAGAIN; } DEBUG_TEST("%s: Chain Dma Status=0x%lX, TxCur=%d, TxPend=%d RxCur=%d RxPend=%d\n", chan->if_name, chan->dma_chain_status, chan->tx_chain_indx, chan->tx_pending_chain_indx, chan->rx_chain_indx, chan->rx_pending_chain_indx); #if 1 update_comms_stats(card); #else #warning "COMM STATS DISABLED" #endif return 0; } /*============================================================================ * new_if - Create new logical channel. * * &wandev: Wanpipe device pointer * &dev: Network device pointer * &conf: User configuration options pointer * * This routine is called by the ROUTER_IFNEW ioctl, * in wanmain.c. The ioctl passes us the user configuration * options which we use to configure the driver and * firmware. * * This functions main purpose is to allocate the * private structure for protocol and bind it * to dev->priv pointer. * * Also the dev->init pointer should also be initialized * to the if_init() function. * * Any allocation necessary for the private strucutre * should be done here, as well as proc/ file initializetion * for the network interface. * * o parse media- and hardware-specific configuration * o make sure that a new channel can be created * o allocate resources, if necessary * o prepare network device structure for registaration. * o add network interface to the /proc/net/wanrouter * * The opposite of this function is del_if() * * Return: 0 o.k. * < 0 failure (channel will not be created) */ #ifdef AFT_TDM_API_SUPPORT static int aft_tdm_api_init(sdla_t *card, private_area_t *chan, wanif_conf_t *conf) { int err=0; if (chan->common.usedby != TDM_VOICE_API && chan->common.usedby != TDM_VOICE_DCHAN) { return 0; } if (chan->tdmv_zaptel_cfg) { return 0; } /* Initilaize TDM API Parameters */ chan->wp_tdm_api_dev.chan = chan; chan->wp_tdm_api_dev.card = card; wan_spin_lock_init(&chan->wp_tdm_api_dev.lock,"wp_aft_tdmapi_lock"); strncpy(chan->wp_tdm_api_dev.name,chan->if_name,WAN_IFNAME_SZ); if (conf->hdlc_streaming) { chan->wp_tdm_api_dev.hdlc_framing=1; } chan->wp_tdm_api_dev.event_ctrl = aft_event_ctrl; chan->wp_tdm_api_dev.read_rbs_bits = aft_read_rbs_bits; chan->wp_tdm_api_dev.write_rbs_bits = aft_write_rbs_bits; chan->wp_tdm_api_dev.write_hdlc_frame = aft_write_hdlc_frame; chan->wp_tdm_api_dev.cfg.rx_disable = 0; chan->wp_tdm_api_dev.cfg.tx_disable = 0; chan->wp_tdm_api_dev.tx_q_len = MAX_AFT_DMA_CHAINS; if (IS_TE1_CARD(card)) { if (IS_T1_CARD(card)){ chan->wp_tdm_api_dev.cfg.hw_tdm_coding=WP_MULAW; chan->wp_tdm_api_dev.tdm_chan = chan->first_time_slot+1; }else{ chan->wp_tdm_api_dev.cfg.hw_tdm_coding=WP_ALAW; chan->wp_tdm_api_dev.tdm_chan = chan->first_time_slot; } } else if (IS_BRI_CARD(card)) { if (chan->dchan_time_slot >= 0) { chan->wp_tdm_api_dev.tdm_chan = 3; } else { chan->wp_tdm_api_dev.tdm_chan = (chan->first_time_slot % 2)+1; } if (card->fe.fe_cfg.tdmv_law == WAN_TDMV_MULAW){ chan->wp_tdm_api_dev.cfg.hw_tdm_coding=WP_MULAW; } else { chan->wp_tdm_api_dev.cfg.hw_tdm_coding=WP_ALAW; } chan->wp_tdm_api_dev.tx_q_len = 0; } else { if (card->fe.fe_cfg.tdmv_law == WAN_TDMV_MULAW){ chan->wp_tdm_api_dev.cfg.hw_tdm_coding=WP_MULAW; chan->wp_tdm_api_dev.tdm_chan = chan->first_time_slot+1; } else { chan->wp_tdm_api_dev.cfg.hw_tdm_coding=WP_ALAW; chan->wp_tdm_api_dev.tdm_chan = chan->first_time_slot+1; } } if (IS_E1_CARD(card)){ chan->wp_tdm_api_dev.active_ch = conf->active_ch; }else{ chan->wp_tdm_api_dev.active_ch = conf->active_ch << 1; } DEBUG_TEST("%s: TDM API ACTIVE CH 0x%08X CHAN=%i\n", chan->if_name, chan->wp_tdm_api_dev.active_ch,chan->wp_tdm_api_dev.tdm_chan); chan->wp_tdm_api_dev.cfg.idle_flag = conf->u.aft.idle_flag; chan->wp_tdm_api_dev.cfg.rbs_tx_bits = conf->u.aft.rbs_cas_idle; chan->wp_tdm_api_dev.tdm_span = card->tdmv_conf.span_no; chan->wp_tdm_api_dev.dtmfsupport = card->u.aft.tdmv_hw_dtmf; err=wanpipe_tdm_api_reg(&chan->wp_tdm_api_dev); if (err){ return err; } wan_set_bit(0,&chan->wp_tdm_api_dev.init); return err; } #endif static int aft_tdm_api_free(sdla_t *card, private_area_t *chan) { #ifdef AFT_TDM_API_SUPPORT int err=0; if (wan_test_bit(0,&chan->wp_tdm_api_dev.init)){ wan_clear_bit(0,&chan->wp_tdm_api_dev.init); err=wanpipe_tdm_api_unreg(&chan->wp_tdm_api_dev); if (err){ wan_set_bit(0,&chan->wp_tdm_api_dev.init); return err; } } #endif return 0; } static int aft_chan_if_init(sdla_t *card, netdevice_t *dev, private_area_t *chan) { chan->first_time_slot=-1; chan->last_time_slot=-1; chan->logic_ch_num=-1; #if defined(AFT_SINGLE_DMA_CHAIN) chan->single_dma_chain=1; chan->max_tx_bufs=MAX_AFT_DMA_CHAINS; #else chan->single_dma_chain=0; chan->max_tx_bufs=MAX_TX_BUF; #endif chan->tslot_sync=0; strncpy(chan->if_name, wan_netif_name(dev), WAN_IFNAME_SZ); chan->card = card; chan->common.card = card; WAN_IFQ_INIT(&chan->wp_tx_pending_list,0); WAN_IFQ_INIT(&chan->wp_tx_complete_list,0); WAN_IFQ_INIT(&chan->wp_tx_hdlc_rpt_list,0); WAN_IFQ_INIT(&chan->wp_rx_free_list,0); WAN_IFQ_INIT(&chan->wp_rx_complete_list,0); WAN_IFQ_INIT(&chan->wp_rx_stack_complete_list, 0); WAN_IFQ_INIT(&chan->wp_rx_bri_dchan_complete_list, 0); wan_trace_info_init(&chan->trace_info,MAX_TRACE_QUEUE); /* Initiaize Tx/Rx DMA Chains */ aft_index_tx_rx_dma_chains(chan); /* Initialize the socket binding information * These hooks are used by the API sockets to * bind into the network interface */ WAN_TASKLET_INIT((&chan->common.bh_task),0,wp_bh,chan); chan->common.dev = dev; chan->tracing_enabled = 0; return 0; } static int aft_ss7_if_init(sdla_t *card, private_area_t *chan, wanif_conf_t *conf) { if (chan->common.usedby != API){ /* SS7 Support not supported in non API mode */ chan->cfg.ss7_enable = 0; return 0; } DEBUG_EVENT("%s: SS7 Support :%s\n", card->devname, chan->cfg.ss7_enable?"On":"Off"); if (chan->cfg.ss7_enable){ wan_smp_flag_t smp_flags; u32 lcfg_reg; DEBUG_EVENT("%s: SS7 Mode :%s\n", card->devname, chan->cfg.ss7_mode?"4096":"128"); DEBUG_EVENT("%s: SS7 LSSU Size :%d\n", card->devname, chan->cfg.ss7_lssu_size); wan_spin_lock_irq(&card->wandev.lock,&smp_flags); card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG),&lcfg_reg); if (chan->cfg.ss7_mode){ aft_lcfg_ss7_mode4096_cfg(&lcfg_reg,chan->cfg.ss7_lssu_size); }else{ aft_lcfg_ss7_mode128_cfg(&lcfg_reg,chan->cfg.ss7_lssu_size); } card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), lcfg_reg); card->u.aft.lcfg_reg=lcfg_reg; wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); aft_hwdev[card->wandev.card_type].aft_fifo_adjust(card,AFT_TDMV_FIFO_LEVEL); chan->single_dma_chain=1; } return 0; } static int aft_transp_if_init(sdla_t *card, private_area_t *chan, wanif_conf_t *conf) { unsigned char *buf; if (chan->mtu&0x03){ DEBUG_EVENT("%s:%s: Error, Transparent MTU must be word aligned!\n", card->devname,chan->if_name); return -EINVAL; } chan->max_idle_size=chan->mtu; if (chan->tslot_sync && chan->mtu%chan->num_of_time_slots){ DEBUG_EVENT("%s:%s: Error, Sync Transparent MTU must be timeslot aligned!\n", card->devname,chan->if_name); DEBUG_EVENT("%s:%s: Error, MTU=%d not multiple of %d timeslots!\n", card->devname,chan->if_name, chan->mtu,chan->num_of_time_slots); return -EINVAL; } if (conf->protocol != WANCONFIG_LIP_ATM && conf->protocol != WANCONFIG_LIP_KATM && chan->mru%chan->num_of_time_slots){ DEBUG_EVENT("%s:%s: Error, Transparent MRU must be timeslot aligned!\n", card->devname,chan->if_name); DEBUG_EVENT("%s:%s: Error, MRU=%d not multiple of %d timeslots!\n", card->devname,chan->if_name, chan->mru,chan->num_of_time_slots); return -EINVAL; } DEBUG_TEST("%s:%s: Config for Transparent mode: Idle=%X Len=%u\n", card->devname,chan->if_name, chan->idle_flag,chan->max_idle_size); if(conf->u.aft.idle_flag){ chan->idle_flag=conf->u.aft.idle_flag; DEBUG_EVENT("%s: Idle flag :0x%02x\n", card->devname, chan->idle_flag); } else { chan->idle_flag=0x7E; } if (chan->tdmv_zaptel_cfg){ #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) chan->idle_flag = WAN_TDMV_IDLE_FLAG; #endif } /* We use the dma_mru value here, just because it will * be easier to change the idle tx size on the fly */ chan->tx_idle_skb = wan_skb_alloc(chan->dma_mru); if (!chan->tx_idle_skb){ return -EINVAL; } buf = wan_skb_put(chan->tx_idle_skb,chan->dma_mru); if(conf->protocol != WANCONFIG_LIP_ATM && conf->protocol != WANCONFIG_LIP_KATM){ memset(buf,chan->idle_flag,chan->dma_mru); }else{ chan->lip_atm = 1; /* if running below LIP ATM, transmit idle cells */ if(init_atm_idle_buffer((unsigned char*)buf, wan_skb_len(chan->tx_idle_skb), chan->if_name, chan->cfg.data_mux )){ wan_skb_free(chan->tx_idle_skb); chan->tx_idle_skb = NULL; return -EINVAL; } } /* reset the tx idle buffer to the actual mtu size */ wan_skb_init(chan->tx_idle_skb,16); wan_skb_trim(chan->tx_idle_skb,0); wan_skb_put(chan->tx_idle_skb,chan->max_idle_size); return 0; } static int new_if_private (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf, int channelized, int dchan, int silent) { sdla_t* card = wandev->priv; private_area_t* chan; int dma_per_ch=card->u.aft.cfg.dma_per_ch; int err = 0, dma_alignment = 4, i =0; /* DCHAN interface should not be log suppressed */ if (dchan>=0) { silent=0; } if (silent) { DEBUG_EVENT( "%s: Configuring Interface: %s (log supress)\n", card->devname, wan_netif_name(dev)); } else { DEBUG_EVENT( "%s: Configuring Interface: %s\n", card->devname, wan_netif_name(dev)); } if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)){ DEBUG_EVENT( "%s: Invalid interface name!\n", card->devname); return -EINVAL; } if (card->adptr_subtype != AFT_SUBTYPE_SHARK){ if (card->u.aft.security_id != 0x01 && card->u.aft.security_cnt >= 2){ DEBUG_EVENT("%s: Error: Security: Max HDLC channels(2) exceeded!\n", card->devname); DEBUG_EVENT("%s: Un-Channelised AFT supports 2 HDLC ifaces!\n", card->devname); return -EINVAL; } } /* ====================================== * Allocate and initialize private data * =====================================*/ chan = wan_kmalloc(sizeof(private_area_t)); if(chan == NULL){ WAN_MEM_ASSERT(card->devname); return -ENOMEM; } memset(chan, 0, sizeof(private_area_t)); memcpy(&chan->cfg,&conf->u.aft,sizeof(chan->cfg)); chan->true_if_encoding=conf->true_if_encoding; aft_chan_if_init(card,dev,chan); if (card->wandev.config_id == WANCONFIG_AFT_ANALOG) { chan->single_dma_chain = 1; conf->hdlc_streaming=0; } if (card->wandev.config_id == WANCONFIG_AFT_ISDN_BRI) { chan->single_dma_chain = 1; } /* If 'dchan_time_slot' is less than zero, it is NOT a dchan. If 'dchan_time_slot' is greater or equal to zero it is a dchan. NOTE: 'dchan' is NOT the same as 'hdlc_eng'. The 'hdlc_eng' is a flag for AFT hardware to use it's HDLC core. */ chan->dchan_time_slot = dchan; if(IS_56K_CARD(card)){ chan->single_dma_chain = 1; conf->hdlc_streaming=1; } if (chan->cfg.hdlc_repeat) { if (!conf->hdlc_streaming) { DEBUG_EVENT("%s: HDLC Repeat configured for non hdlc channel!\n", chan->if_name); err= -EINVAL; goto new_if_error; } chan->single_dma_chain = 1; conf->hdlc_streaming=1; } if (channelized) { chan->channelized_cfg=1; if (wan_netif_priv(dev)) { #if 1 private_area_t *cptr; for (cptr=wan_netif_priv(dev);cptr->next!=NULL;cptr=cptr->next); cptr->next=chan; chan->next=NULL; #else #warning "DEBUG: Chan list backwards!" chan->next = wan_netif_priv(dev); wan_netif_set_priv(dev, chan); #endif } else { wan_netif_set_priv(dev, chan); } } else { chan->channelized_cfg=0; wan_netif_set_priv(dev, chan); } /* ====================================== * Configure chan MTU and MRU Values * And setup E1 timeslots * =====================================*/ chan->mtu = card->wandev.mtu; if (conf->u.aft.mtu){ chan->mtu=conf->u.aft.mtu; if (chan->mtu > MAX_WP_PRI_MTU || chan->mtu < MIN_WP_PRI_MTU){ DEBUG_EVENT("%s: Error Invalid %s MTU %d (Min=%d, Max=%d)\n", card->devname,chan->if_name,chan->mtu, MIN_WP_PRI_MTU,MAX_WP_PRI_MTU); err= -EINVAL; goto new_if_error; } } chan->mru = card->u.aft.cfg.mru; if (conf->u.aft.mru){ chan->mru = conf->u.aft.mru; if (chan->mru > MAX_WP_PRI_MTU || chan->mru < MIN_WP_PRI_MTU){ DEBUG_EVENT("%s: Error Invalid %s MRU %d (Min=%d, Max=%d)\n", card->devname,chan->if_name,chan->mru, MIN_WP_PRI_MTU,MAX_WP_PRI_MTU); err= -EINVAL; goto new_if_error; } } /*==================================================== * Interface connects top services to driver * Interface can be used by the following services: * WANPIPE = TCP/IP -> Driver * API = Raw Socket Access -> Driver * BRIDGE = Bridge to Ethernet -> Driver * BRIDGE_NODE = TCP/IP to Ethernet -> Driver * STACK = LIP -> Driver * TDM_VOICE = Zaptel -> Trans Ch Driver * TDM_VOICE_DCHAN = Zaptel -> Hdlc Driver (PRIVATE) * TDM_VOICE_API = Raw Socket -> Transp Ch Driver * TMD_API = Raw Socket -> Transp Channelized API *===================================================*/ if(strcmp(conf->usedby, "WANPIPE") == 0) { DEBUG_EVENT( "%s: Running in WANPIPE mode\n", wandev->name); chan->common.usedby = WANPIPE; /* Used by GENERIC driver only otherwise protocols * are in LIP layer */ if (conf->protocol != WANOPT_NO){ wan_netif_set_priv(dev, chan); if ((err=protocol_init(card,dev,chan,conf)) != 0){ wan_netif_set_priv(dev, NULL); goto new_if_error; } } #if defined(__LINUX__) } else if( strcmp(conf->usedby, "TDM_API") == 0) { DEBUG_EVENT("%s:%s: Error: TDM API mode is not supported!\n", card->devname,chan->if_name); err=-EINVAL; goto new_if_error; #endif #if defined(AFT_API_SUPPORT) } else if( strcmp(conf->usedby, "API") == 0) { chan->common.usedby = API; DEBUG_EVENT( "%s:%s: Running in API mode\n", wandev->name,chan->if_name); wan_reg_api(chan, dev, card->devname); card->wandev.event_callback.dtmf = wan_aft_api_dtmf; card->wandev.event_callback.hook = wan_aft_api_hook; card->wandev.event_callback.ringtrip = wan_aft_api_ringtrip; card->wandev.event_callback.ringdetect = wan_aft_api_ringdetect; #endif #if defined(__LINUX__) }else if (strcmp(conf->usedby, "BRIDGE") == 0) { chan->common.usedby = BRIDGE; DEBUG_EVENT( "%s:%s: Running in WANPIPE (BRIDGE) mode.\n", card->devname,chan->if_name); #endif #if defined(__LINUX__) }else if (strcmp(conf->usedby, "BRIDGE_N") == 0) { chan->common.usedby = BRIDGE_NODE; DEBUG_EVENT( "%s:%s: Running in WANPIPE (BRIDGE_NODE) mode.\n", card->devname,chan->if_name); #endif }else if (strcmp(conf->usedby, "TDM_VOICE") == 0) { #ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE chan->common.usedby = TDM_VOICE; chan->tdmv_zaptel_cfg=1; card->u.aft.tdmv_zaptel_cfg=1; conf->hdlc_streaming=0; chan->single_dma_chain=1; chan->max_tx_bufs=MAX_AFT_DMA_CHAINS; if (dchan >= 0){ # ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE_DCHAN chan->common.usedby = TDM_VOICE_DCHAN; conf->hdlc_streaming=1; chan->single_dma_chain=0; chan->mru=chan->mtu=1500; # else DEBUG_EVENT("%s: Error: TDMV_DCHAN Option not compiled into the driver!\n", card->devname); err=-EINVAL; goto new_if_error; # endif } if (!silent) { DEBUG_EVENT( "%s:%s: Running in TDM %sVoice Zaptel Mode.\n", card->devname,chan->if_name, chan->common.usedby == TDM_VOICE_DCHAN?"DCHAN ":""); } #else DEBUG_EVENT("\n"); DEBUG_EVENT("%s:%s: Error: TDM VOICE prot not compiled\n", card->devname,chan->if_name); DEBUG_EVENT("%s:%s: during installation process!\n", card->devname,chan->if_name); err=-EINVAL; goto new_if_error; #endif #if defined(__LINUX__) }else if (strcmp(conf->usedby, "TDM_VOICE_API") == 0) { chan->common.usedby = TDM_VOICE_API; chan->cfg.data_mux=1; conf->hdlc_streaming=0; chan->single_dma_chain=1; chan->tdmv_zaptel_cfg=0; if (dchan >= 0){ chan->common.usedby = TDM_VOICE_DCHAN; chan->cfg.data_mux=0; chan->single_dma_chain=0; conf->hdlc_streaming=1; chan->mru=chan->mtu=1500; } if (!silent) { if (chan->common.usedby == TDM_VOICE_DCHAN) { DEBUG_EVENT( "%s:%s: Running in TDM Voice DCHAN API Mode.\n", card->devname,chan->if_name); } else { DEBUG_EVENT( "%s:%s: Running in TDM Voice API Mode.\n", card->devname,chan->if_name); } } #endif #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG } else if (strcmp(conf->usedby, "ANNEXG") == 0) { DEBUG_EVENT("%s:%s: Interface running in ANNEXG mode!\n", wandev->name,chan->if_name); chan->common.usedby=ANNEXG; if (strlen(conf->label)){ strncpy(chan->label,conf->label,WAN_IF_LABEL_SZ); } #endif }else if (strcmp(conf->usedby, "STACK") == 0) { chan->common.usedby = STACK; DEBUG_EVENT( "%s:%s: Running in Stack mode.\n", card->devname,chan->if_name); }else if (strcmp(conf->usedby, "NETGRAPH") == 0) { chan->common.usedby = WP_NETGRAPH; DEBUG_EVENT( "%s:%s: Running in Netgraph mode.\n", card->devname,chan->if_name); }else{ DEBUG_EVENT( "%s:%s: Error: Invalid IF operation mode %s\n", card->devname,chan->if_name,conf->usedby); err=-EINVAL; goto new_if_error; } /*=============================================== * Interface Operation Setup *==============================================*/ if (conf->hwec.enable){ if (card->wandev.config_id == WANCONFIG_AFT_ISDN_BRI) { card->wandev.ec_enable_map = 0x3; }else{ card->wandev.ec_enable_map |= conf->active_ch; } } /* Read user specified active_ch, we must do it * here because the active_ch value might change * for different user modes*/ chan->time_slot_map=conf->active_ch; chan->num_of_time_slots= aft_get_num_of_slots(card->u.aft.num_of_time_slots, chan->time_slot_map); if (!chan->num_of_time_slots){ DEBUG_EVENT("%s: Error: Invalid number of timeslots in map 0x%08X!\n", chan->if_name,chan->time_slot_map); return -EINVAL; } if (card->wandev.config_id == WANCONFIG_AFT_ANALOG && chan->num_of_time_slots > 1) { DEBUG_EVENT( "%s: Error: Invalid Analog number of timeslots in map 0x%08X: (Valid=1)\n", chan->if_name,chan->time_slot_map); return -EINVAL; } /* ===================== * Interaface TDMV Setup * * Initialize the interface for TDMV * operation, if TDMV is not used this * function will just return */ err=aft_tdmv_if_init(card,chan,conf); if (err){ err=-EINVAL; goto new_if_error; } /* ===================== * Interaface SS7 Setup * * Initialize the interface for TDMV * operation, if TDMV is not used this * function will just return */ err=aft_ss7_if_init(card,chan,conf); if (err){ err=-EINVAL; goto new_if_error; } if (!silent) { /* Print out the current configuration */ DEBUG_EVENT("%s: MRU :%d\n", card->devname, chan->mru); DEBUG_EVENT("%s: MTU :%d\n", card->devname, chan->mtu); chan->hdlc_eng = conf->hdlc_streaming; DEBUG_EVENT("%s: HDLC Eng :%s | %s\n", card->devname, chan->hdlc_eng?"On":"Off (Transparent)", chan->cfg.hdlc_repeat?"Repeat":"N/A"); } /* Obtain the DMA MRU size based on user confgured * MRU. The DMA MRU must be of size 2^x */ chan->dma_mru = chan->mtu; chan->dma_mru = aft_valid_mtu(chan->dma_mru); if (!chan->dma_mru){ DEBUG_EVENT("%s:%s: Error invalid MTU %d MRU %d\n", card->devname, chan->if_name, chan->mtu,chan->mru); err= -EINVAL; goto new_if_error; } if (conf->single_tx_buf || IS_BRI_CARD(card) || ((card->adptr_type == A101_ADPTR_2TE1 || card->adptr_type == A101_ADPTR_1TE1) && card->u.aft.firm_id == AFT_DS_FE_CORE_ID)){ chan->single_dma_chain=1; chan->max_tx_bufs=MAX_AFT_DMA_CHAINS; dma_per_ch=MAX_AFT_DMA_CHAINS; } if (!chan->hdlc_eng){ /* If hardware HDLC engine is disabled: * 1. Configure DMA chains for SINGLE DMA * 2. Enable Timeslot Synchronization * 3. Configure Interface for Transparent Operation */ chan->single_dma_chain=1; chan->max_tx_bufs=MAX_AFT_DMA_CHAINS; if (chan->channelized_cfg) { dma_per_ch=MAX_AFT_DMA_CHAINS; }else{ dma_per_ch= (MAX_AFT_DMA_CHAINS*1500) / chan->mtu; if (dma_per_ch < MAX_AFT_DMA_CHAINS) { dma_per_ch=MAX_AFT_DMA_CHAINS; } } chan->tslot_sync=1; if(conf->protocol == WANCONFIG_LIP_ATM || conf->protocol == WANCONFIG_LIP_KATM){ chan->tslot_sync=0; } err=aft_transp_if_init(card,chan,conf); if (err){ goto new_if_error; } }else{ /* If hardware HDLC engine is enabled: * 1. Force Disable DATA MUX option * just in case user made a mistake */ chan->cfg.data_mux=0; } if (!silent){ DEBUG_EVENT("%s: Data Mux Ctrl :%s\n", card->devname, chan->cfg.data_mux?"On":"Off"); } /*================================================= * AFT CHANNEL Configuration * * Configure the AFT Hardware for this * logic channel. Enable the above selected * operation modes. *================================================*/ err=aft_dev_configure(card,chan,conf); if (err){ goto new_if_error; } /*Set the actual logic ch number of this chan *as the dchan. Due to HDLC security issue, the *HDLC channels are mapped on first TWO logic channels */ if (chan->common.usedby == TDM_VOICE_DCHAN){ card->u.aft.tdmv_dchan=chan->logic_ch_num+1; } /* Configure the DCHAN on LAST Master interface. * We will use the master interface information, until * the next interface with the current DCHAN info is * configured. This must be done in order to register * the DCHAN in zaptel. */ if (card->u.aft.tdmv_dchan_cfg_on_master && card->u.aft.tdmv_dchan){ int dchan=card->u.aft.tdmv_dchan; if (IS_T1_CARD(card)){ dchan--; } if (wan_test_bit(dchan,&conf->active_ch)){ DEBUG_EVENT("%s: TDMV DCHAN :%d\n", card->devname,dchan); card->u.aft.tdmv_chan_ptr=chan; card->u.aft.tdmv_dchan=chan->logic_ch_num+1; } } #ifdef AFT_TDM_API_SUPPORT err=aft_tdm_api_init(card,chan,conf); if (err){ goto new_if_error; } #endif err=aft_hwec_config(card,chan,conf,1); if (err){ goto new_if_error; } if (chan->channelized_cfg && !chan->hdlc_eng) { chan->dma_mru = 1024; dma_per_ch = 4; } if (!silent) { DEBUG_EVENT("%s: DMA/Len/Chain/EC :%d/%d/%s/%s\n", card->devname, dma_per_ch, chan->dma_mru, chan->single_dma_chain?"Off":"On", card->wandev.ec_enable_map?"On":"Off"); } /* New DMA support A-DMA */ dma_alignment = 4; if (chan->channelized_cfg && !chan->hdlc_eng){ dma_alignment = 0x200; } err = card->hw_iface.busdma_tag_create( card->hw, &chan->rx_dma_chain_table[0], dma_alignment, chan->dma_mru, MAX_AFT_DMA_CHAINS); if (err) { DEBUG_EVENT("%s: Failed to allocate DMA Rx mtag!\n", card->devname); err = -EINVAL; goto new_if_error; } err = card->hw_iface.busdma_tag_create( card->hw, &chan->tx_dma_chain_table[0], dma_alignment, chan->dma_mru, MAX_AFT_DMA_CHAINS); if (err) { DEBUG_EVENT("%s: Failed to allocate DMA Tx mtag!\n", card->devname); err = card->hw_iface.busdma_tag_destroy( card->hw, &chan->rx_dma_chain_table[0], MAX_AFT_DMA_CHAINS); err = -EINVAL; goto new_if_error; } for (i=0;ihw_iface.busdma_alloc( card->hw, &chan->tx_dma_chain_table[i]); if (err){ DEBUG_EVENT( "%s:%s: Unable to load TX DMA buffer %d (%d)!\n", card->devname, chan->if_name, i, err); err = -EINVAL; break; } DEBUG_DMA("%s:%s: Alloc DMA TX buffer %d virt=%p len=%d\n", card->devname, chan->if_name, i, chan->tx_dma_chain_table[i].dma_virt, chan->dma_mru); err = card->hw_iface.busdma_alloc( card->hw, &chan->rx_dma_chain_table[i]); if (err){ DEBUG_EVENT( "%s:%s: Unable to load RX DMA buffer %d (%d)!\n", card->devname, chan->if_name, i, err); err = -EINVAL; break; } DEBUG_DMA("%s:%s: Alloc DMA RX buffer %d virt=%p len=%d\n", card->devname, chan->if_name, i, chan->rx_dma_chain_table[i].dma_virt, chan->dma_mru); } if (err){ for (i=0;ihw_iface.busdma_free( card->hw, &chan->rx_dma_chain_table[i]); card->hw_iface.busdma_free( card->hw, &chan->tx_dma_chain_table[i]); } err = card->hw_iface.busdma_tag_destroy( card->hw, &chan->rx_dma_chain_table[0], MAX_AFT_DMA_CHAINS); err = card->hw_iface.busdma_tag_destroy( card->hw, &chan->tx_dma_chain_table[0], MAX_AFT_DMA_CHAINS); err = -EINVAL; goto new_if_error; } err=aft_alloc_rx_dma_buff(card, chan, dma_per_ch,0); if (err){ goto new_if_error; } /*======================================================= * Interface OS Specific Configuration *======================================================*/ /* If gateway option is set, then this interface is the * default gateway on this system. We must know that information * in case DYNAMIC interface configuration is enabled. * * I.E. If the interface is brought down by the driver, the * default route will also be removed. Once the interface * is brought back up, we must know to re-astablish the * default route. */ if ((chan->gateway = conf->gateway) == WANOPT_YES){ DEBUG_EVENT( "%s: Interface %s is set as a gateway.\n", card->devname,chan->if_name); } /* Get Multicast Information from the user * FIXME: This is IP relevant, since this is now * a hardware interface this option should't * be here */ chan->mc = conf->mc; /* The network interface "dev" has been passed as * an argument from the above layer. We must initialize * it so it can be registered into the kernel. * * The "dev" structure is the link between the kernel * stack and the wanpipe driver. It contains all * access hooks that kernel uses to communicate to * the our driver. * * For now, just set the "dev" name to the user * defined name and initialize: * dev->if_init : function that will be called * to further initialize * dev structure on "ifconfig up" * * dev->priv : private structure allocated above * */ /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * * DO NOT PLACE ANY CODE BELOW THAT COULD RETURN ERROR * *!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ /* Only setup the dev pointer once the new_if function has * finished successfully. DO NOT place any code below that * can return an error */ #if defined(__LINUX__) dev->init = &if_init; # if defined(CONFIG_PRODUCT_WANPIPE_GENERIC) if_init(dev); # endif #else if (chan->common.usedby != TDM_VOICE && chan->common.usedby != TDM_VOICE_API){ chan->common.is_netdev = 1; } chan->common.iface.open = &if_open; chan->common.iface.close = &if_close; chan->common.iface.output = &if_send; chan->common.iface.ioctl = &if_do_ioctl; chan->common.iface.tx_timeout= &if_tx_timeout; if (wan_iface.attach){ if (!ifunit(wan_netif_name(dev))){ wan_iface.attach(dev, NULL, chan->common.is_netdev); } }else{ DEBUG_EVENT("%s: Failed to attach interface %s!\n", card->devname, wan_netif_name(dev)); wan_netif_set_priv(dev, NULL); err = -EINVAL; goto new_if_error; } wan_netif_set_mtu(dev, chan->mtu); #endif /* * Increment the number of network interfaces * configured on this card. */ wan_atomic_inc(&card->wandev.if_cnt); if (chan->hdlc_eng){ ++card->u.aft.security_cnt; } /* Keep the original tx queue len in case we have to go back to it */ chan->max_tx_bufs_orig = chan->max_tx_bufs; set_chan_state(card, dev, WAN_CONNECTING); //chan->common.state = WAN_CONNECTING; DEBUG_EVENT( "\n"); return 0; new_if_error: return err; } static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf) { int err=-EINVAL; sdla_t *card=wandev->priv; wan_netif_set_priv(dev, NULL); if (IS_E1_CARD(card) && !(WAN_FE_FRAME(&card->fe) == WAN_FR_UNFRAMED)) { conf->active_ch = conf->active_ch << 1; wan_clear_bit(0,&conf->active_ch); }else if (IS_56K_CARD(card)) { conf->active_ch = 1; } if (strcmp(conf->usedby, "TDM_VOICE") == 0) { #ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE if (card->tdmv_conf.span_no){ switch(card->wandev.config_id){ case WANCONFIG_AFT_ANALOG: err = wp_tdmv_remora_init(&card->tdmv_iface); break; #if defined(CONFIG_PRODUCT_WANPIPE_AFT_BRI) case WANCONFIG_AFT_ISDN_BRI: err = wp_tdmv_bri_init(&card->tdmv_iface); break; #endif default: err = wp_tdmv_te1_init(&card->tdmv_iface); break; } if (err){ DEBUG_EVENT("%s: Error: Failed to initialize tdmv functions!\n", card->devname); return -EINVAL; } WAN_TDMV_CALL(create, (card, &card->tdmv_conf), err); if (err){ DEBUG_EVENT("%s: Error: Failed to create tdmv span!\n", card->devname); return err; } } #else DEBUG_EVENT("\n"); DEBUG_EVENT("%s: Error: TDM VOICE prot not compiled\n", card->devname); DEBUG_EVENT("%s: during installation process!\n", card->devname); return -EINVAL; #endif } err=-EINVAL; if (strcmp(conf->usedby, "TDM_VOICE") == 0 || strcmp(conf->usedby, "TDM_VOICE_API") == 0){ int i=0,master_if=-1; int if_cnt=0; u32 active_ch=conf->active_ch; if(IS_BRI_CARD(card)) { wan_set_bit(BRI_DCHAN_LOGIC_CHAN,&card->u.aft.tdmv_dchan); } if (card->wandev.fe_iface.active_map){ conf->active_ch = card->wandev.fe_iface.active_map(&card->fe, 0); if(IS_BRI_CARD(card)) { wan_set_bit(BRI_DCHAN_LOGIC_CHAN,&conf->active_ch); wan_set_bit(BRI_DCHAN_LOGIC_CHAN,&card->tdmv_conf.dchan); } active_ch=conf->active_ch; } err=aft_find_master_if_and_dchan(card,&master_if,active_ch); if (err < 0) { return err; } DEBUG_TEST("%s: TDM VOICE: DCHAN CHAN in 0x%08X Timeslots=%i CFG DCHAN=0x%08X MasterIF=%i\n", card->devname, active_ch, card->u.aft.num_of_time_slots, card->tdmv_conf.dchan,master_if); for (i=0;iu.aft.num_of_time_slots;i++){ if (wan_test_bit(i,&active_ch)){ int dchan=-1; conf->active_ch=0; conf->u.aft.tdmv_master_if=0; wan_set_bit(i,&conf->active_ch); if (wan_test_bit(i,&card->tdmv_conf.dchan)){ dchan=i; } if (i==master_if){ conf->u.aft.tdmv_master_if=1; } err=new_if_private(wandev,dev,conf,1,dchan,if_cnt); if (err){ break; } if_cnt++; } } #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) if (!err && card->u.aft.tdmv_zaptel_cfg){ WAN_TDMV_CALL(software_init, (&card->wan_tdmv), err); } #endif }else{ if(IS_BRI_CARD(card)) { if (conf->active_ch & ~(0x07)) { DEBUG_EVENT("%s: Error: BRI Active Channels range 1 to 3: Range 0x%08X invalid\n", card->devname,conf->active_ch); err=-EINVAL; goto new_if_cfg_skip; } if (wan_test_bit(BRI_DCHAN_ACTIVE_CFG_CHAN, &conf->active_ch)) { /* if bit 2 is set, user wants to run on the bri dchan */ wan_set_bit(BRI_DCHAN_LOGIC_CHAN, &card->u.aft.tdmv_dchan); card->u.aft.tdmv_dchan = BRI_DCHAN_LOGIC_CHAN; err=new_if_private(wandev,dev,conf,0, BRI_DCHAN_LOGIC_CHAN,0); } else { /* BRI B-Channels */ card->u.aft.tdmv_dchan = 0; conf->active_ch = conf->active_ch << (2*WAN_FE_LINENO(&card->fe)); DEBUG_EVENT("%s: Configure BRI Active CH 0x%08X\n", card->devname,conf->active_ch); err=new_if_private(wandev,dev,conf,0,-1,0); } } else { card->tdmv_conf.dchan=0; err=new_if_private(wandev,dev,conf,0,-1,0); } } new_if_cfg_skip: if (err == 0 && wan_netif_priv(dev)) { wan_smp_flag_t flags; int card_use_counter; card->hw_iface.getcfg(card->hw, SDLA_HWCPU_USEDCNT, &card_use_counter); /* If FRONT End is down, it means that the DMA * is disabled. In this case don't try to * reset fifo. Let the enable_data_error_intr() * function do this, after front end has come up */ wan_spin_lock_irq(&card->wandev.lock,&flags); aft_dev_open(card, wan_netif_priv(dev)); if (card->wandev.state == WAN_CONNECTED){ set_chan_state(card, dev, WAN_CONNECTED); } wan_spin_unlock_irq(&card->wandev.lock,&flags); if (card->wandev.config_id == WANCONFIG_AFT_ANALOG || card->wandev.config_id == WANCONFIG_AFT_SERIAL) { wan_spin_lock_irq(&card->wandev.lock,&flags); card->fe.fe_status = FE_CONNECTED; handle_front_end_state(card); set_chan_state(card, dev, WAN_CONNECTED); wan_spin_unlock_irq(&card->wandev.lock,&flags); } else if (card->wandev.config_id == WANCONFIG_AFT_ISDN_BRI) { wan_spin_lock_irq(&card->wandev.lock,&flags); enable_data_error_intr(card); wan_spin_unlock_irq(&card->wandev.lock,&flags); } } else if (err && wan_netif_priv(dev)){ del_if(wandev,dev); if (wan_netif_priv(dev)){ wan_free(wan_netif_priv(dev)); wan_netif_set_priv(dev, NULL); } } return err; } /*============================================================================ * del_if - Delete logical channel. * * @wandev: Wanpipe private device pointer * @dev: Netowrk interface pointer * * This function is called by ROUTER_DELIF ioctl call * to deallocate the network interface. * * The network interface and the private structure are * about to be deallocated by the upper layer. * We have to clean and deallocate any allocated memory. * * NOTE: DO NOT deallocate dev->priv here! It will be * done by the upper layer. * */ static int del_if_private (wan_device_t* wandev, netdevice_t* dev) { private_area_t* chan = wan_netif_priv(dev); sdla_t* card; wan_smp_flag_t flags; int i; if (!chan){ DEBUG_EVENT("%s: Critical Error del_if_private() chan=NULL!\n", wan_netif_name(dev)); return 0; } card = chan->card; if (!card){ DEBUG_EVENT("%s: Critical Error del_if_private() chan=NULL!\n", wan_netif_name(dev)); return 0; } #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG if (chan->common.usedby == ANNEXG && chan->annexg_dev){ netdevice_t *tmp_dev; int err; DEBUG_EVENT("%s: Unregistering Lapb Protocol\n",wandev->name); if (!IS_FUNC_CALL(lapb_protocol,lapb_unregister)){ wan_spin_lock_irq(&wandev->lock, &flags); chan->annexg_dev = NULL; wan_spin_unlock_irq(&wandev->lock, &flags); return 0; } wan_spin_lock_irq(&wandev->lock, &flags); tmp_dev=chan->annexg_dev; chan->annexg_dev=NULL; wan_spin_unlock_irq(&wandev->lock, &flags); if ((err=lapb_protocol.lapb_unregister(tmp_dev))){ wan_spin_lock_irq(&wandev->lock, &flags); chan->annexg_dev=tmp_dev; wan_spin_unlock_irq(&wandev->lock, &flags); return err; } } #endif aft_hwec_config(card,chan,NULL,0); wan_spin_lock_irq(&card->wandev.lock,&flags); aft_dev_unconfigure(card,chan); wan_spin_unlock_irq(&card->wandev.lock,&flags); AFT_FUNC_DEBUG(); #if INIT_FE_ONLY return 0; #endif WAN_TASKLET_KILL(&chan->common.bh_task); if (chan->common.usedby == API){ wan_unreg_api(chan, card->devname); } if (aft_tdm_api_free(card,chan)) { DEBUG_EVENT("%s: Error: Failed to del iface: TDM API Device in use!\n", chan->if_name); return -EBUSY; } wan_spin_lock_irq(&card->wandev.lock,&flags); aft_tdmv_if_free(card,chan); wan_spin_unlock_irq(&card->wandev.lock,&flags); protocol_shutdown(card,dev); #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) if (wan_iface.detach){ wan_iface.detach(dev, chan->common.is_netdev); } #endif /* We must set used by to API because * the free_tx and free_rx are not allowed * for TDM_VOICE mode in regular operation */ wan_spin_lock_irq(&card->wandev.lock,&flags); chan->common.usedby = API; aft_free_tx_descriptors(chan); aft_free_rx_descriptors(chan); wan_spin_unlock_irq(&card->wandev.lock,&flags); for (i=0;ihw_iface.busdma_free( card->hw, &chan->rx_dma_chain_table[i]); card->hw_iface.busdma_free( card->hw, &chan->tx_dma_chain_table[i]); } card->hw_iface.busdma_tag_destroy( card->hw, &chan->rx_dma_chain_table[0], MAX_AFT_DMA_CHAINS); card->hw_iface.busdma_tag_destroy( card->hw, &chan->tx_dma_chain_table[0], MAX_AFT_DMA_CHAINS); wan_spin_lock_irq(&card->wandev.lock,&flags); WAN_IFQ_DMA_PURGE(&chan->wp_rx_free_list); WAN_IFQ_DESTROY(&chan->wp_rx_free_list); WAN_IFQ_PURGE(&chan->wp_rx_complete_list); WAN_IFQ_DESTROY(&chan->wp_rx_complete_list); WAN_IFQ_PURGE(&chan->wp_rx_stack_complete_list); WAN_IFQ_DESTROY(&chan->wp_rx_stack_complete_list); WAN_IFQ_PURGE(&chan->wp_tx_pending_list); WAN_IFQ_DESTROY(&chan->wp_tx_pending_list); WAN_IFQ_PURGE(&chan->wp_rx_bri_dchan_complete_list); WAN_IFQ_DESTROY(&chan->wp_rx_bri_dchan_complete_list); WAN_IFQ_PURGE(&chan->wp_tx_complete_list); WAN_IFQ_DESTROY(&chan->wp_tx_complete_list); if (chan->tx_idle_skb){ wan_skb_free(chan->tx_idle_skb); chan->tx_idle_skb=NULL; } if (chan->tx_realign_buf){ wan_free(chan->tx_realign_buf); chan->tx_realign_buf=NULL; } if (chan->tx_ss7_realign_buf){ wan_free(chan->tx_ss7_realign_buf); chan->tx_ss7_realign_buf=NULL; } if (card->u.aft.tdmv_chan_ptr == chan){ card->u.aft.tdmv_chan_ptr=NULL; } chan->logic_ch_num=-1; wan_spin_unlock_irq(&card->wandev.lock,&flags); /* Delete interface name from proc fs. */ #if 0 wanrouter_proc_delete_interface(wandev, chan->if_name); #endif /* Decrement the number of network interfaces * configured on this card. */ wan_atomic_dec(&card->wandev.if_cnt); if (chan->hdlc_eng){ --card->u.aft.security_cnt; } DEBUG_SUB_MEM(sizeof(private_area_t)); return 0; } static int del_if (wan_device_t* wandev, netdevice_t* dev) { private_area_t* chan=wan_netif_priv(dev); wan_smp_flag_t flags; sdla_t *card; int card_use_cnt=0; int err=0; if (!chan){ DEBUG_EVENT("%s: Critical Error del_if() chan=NULL!\n", wan_netif_name(dev)); return 0; } if (!(card=chan->card)){ DEBUG_EVENT("%s: Critical Error del_if() chan=NULL!\n", wan_netif_name(dev)); return 0; } card->hw_iface.getcfg(card->hw, SDLA_HWCPU_USEDCNT, &card_use_cnt); wan_spin_lock_irq(&card->wandev.lock,&flags); aft_dev_close(card,chan); wan_spin_unlock_irq(&card->wandev.lock,&flags); if (chan->channelized_cfg) { sdla_t *card=chan->card; #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) if (chan->tdmv_zaptel_cfg) { sdla_t *card=chan->card; int err; WAN_TDMV_CALL(running, (card), err); if (err){ return -EBUSY; } } #endif /* Disable the TDMV Interrupt first, before * shutting down all TDMV channels */ wan_spin_lock_irq(&card->wandev.lock,&flags); if (IS_BRI_CARD(card)) { int card_use_cnt; card->wandev.state=WAN_DISCONNECTED; card->hw_iface.getcfg(card->hw, SDLA_HWCPU_USEDCNT, &card_use_cnt); if (card_use_cnt == 1) { DEBUG_TEST("%s: BRI Disabling TDMV INTR\n", card->devname); aft_tdm_intr_ctrl(card,0); aft_fifo_intr_ctrl(card, 0); } else { u32 dmareg; /* By removing timeslot out of the global interrupt we can disable the tdm global isr. This code re-triggers it just in case */ card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_DMA_CTRL_REG),&dmareg); wan_set_bit(AFT_DMACTRL_TDMV_RX_TOGGLE,&dmareg); wan_set_bit(AFT_DMACTRL_TDMV_TX_TOGGLE,&dmareg); card->hw_iface.bus_write_4(card->hw, AFT_PORT_REG(card,AFT_DMA_CTRL_REG),dmareg); } } else { aft_tdm_intr_ctrl(card,0); aft_fifo_intr_ctrl(card, 0); } /* Disable RTP Tap */ card->wandev.rtp_len=0; #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) if (card->wan_tdmv.sc) { int err; WAN_TDMV_CALL(state, (card, WAN_DISCONNECTED), err); } #endif wan_spin_unlock_irq(&card->wandev.lock,&flags); while(chan){ int err=del_if_private(wandev,dev); if (err) { return err; } if (chan->next) { wan_netif_set_priv(dev, chan->next); wan_free(chan); chan = wan_netif_priv(dev); } else { /* Leave the last chan dev * in dev->priv. It will get * deallocated normally */ break; } } #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) if (card->wan_tdmv.sc) { aft_tdmv_free(card); } if (card->sdla_tdmv_dummy) { sdla_tdmv_dummy_unregister(card->sdla_tdmv_dummy); } #endif err=0; } else { err=del_if_private(wandev,dev); } return err; } /**SECTION*********************************************************** * * KERNEL Device Entry Interfaces * ********************************************************************/ /*============================================================================ * if_init - Initialize Linux network interface. * * @dev: Network interface pointer * * During "ifconfig up" the upper layer calls this function * to initialize dev access pointers. Such as transmit, * stats and header. * * It is called only once for each interface, * during Linux network interface registration. * * Returning anything but zero will fail interface * registration. */ #if defined(__LINUX__) static int if_init (netdevice_t* dev) { private_area_t* chan = wan_netif_priv(dev); sdla_t* card = chan->card; wan_device_t* wandev = &card->wandev; #if defined(CONFIG_PRODUCT_WANPIPE_GENERIC) hdlc_device* hdlc; #endif /* Initialize device driver entry points */ dev->open = &if_open; dev->stop = &if_close; #if defined(CONFIG_PRODUCT_WANPIPE_GENERIC) hdlc = dev_to_hdlc(dev); hdlc->xmit = if_send; #else dev->hard_start_xmit = &if_send; #endif dev->get_stats = &if_stats; #if 0 dev->tx_timeout = &if_tx_timeout; dev->watchdog_timeo = 2*HZ; #else if (chan->common.usedby == TDM_VOICE || chan->common.usedby == TDM_VOICE_API){ dev->tx_timeout = NULL; }else{ dev->tx_timeout = &if_tx_timeout; } dev->watchdog_timeo = 2*HZ; #endif dev->do_ioctl = if_do_ioctl; dev->change_mtu = if_change_mtu; if (chan->common.usedby == BRIDGE || chan->common.usedby == BRIDGE_NODE){ /* Setup the interface for Bridging */ int hw_addr=0; ether_setup(dev); /* Use a random number to generate the MAC address */ memcpy(dev->dev_addr, "\xFE\xFC\x00\x00\x00\x00", 6); get_random_bytes(&hw_addr, sizeof(hw_addr)); *(int *)(dev->dev_addr + 2) += hw_addr; }else{ dev->flags |= IFF_POINTOPOINT; dev->flags |= IFF_NOARP; dev->type = ARPHRD_PPP; dev->mtu = chan->mtu; dev->hard_header_len = 0; if (chan->common.usedby == API || chan->common.usedby == STACK){ if (chan->hdlc_eng) { dev->mtu = chan->dma_mru+sizeof(api_tx_hdr_t); }else{ dev->mtu = chan->mtu+sizeof(api_tx_hdr_t); } } /* Enable Mulitcasting if user selected */ if (chan->mc == WANOPT_YES){ dev->flags |= IFF_MULTICAST; } if (chan->true_if_encoding){ DEBUG_EVENT("%s: Setting IF Type to Broadcast\n",chan->if_name); dev->type = ARPHRD_PPP; /* This breaks the tcpdump */ dev->flags &= ~IFF_POINTOPOINT; dev->flags |= IFF_BROADCAST; }else{ dev->type = ARPHRD_PPP; } } /* Initialize hardware parameters */ dev->irq = wandev->irq; dev->dma = wandev->dma; dev->base_addr = wandev->ioport; card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); /* Set transmit buffer queue length * If too low packets will not be retransmitted * by stack. */ dev->tx_queue_len = 100; return 0; } #endif /*============================================================================ * if_open - Open network interface. * * @dev: Network device pointer * * On ifconfig up, this function gets called in order * to initialize and configure the private area. * Driver should be configured to send and receive data. * * This functions starts a timer that will call * frmw_config() function. This function must be called * because the IP addresses could have been changed * for this interface. * * Return 0 if O.k. or errno. */ static int if_open (netdevice_t* dev) { private_area_t* chan = wan_netif_priv(dev); sdla_t* card = chan->card; #if defined(__LINUX__) /* Only one open per interface is allowed */ if (open_dev_check(dev)){ DEBUG_EVENT("%s: Open dev check failed!\n", wan_netif_name(dev)); return -EBUSY; } #endif if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ DEBUG_EVENT("%s:%s: Card down: Failed to open interface!\n", card->devname,chan->if_name); return -EINVAL; } /* Initialize the router start time. * Used by wanpipemon debugger to indicate * how long has the interface been up */ wan_getcurrenttime(&chan->router_start_time, NULL); #if !defined(WANPIPE_IFNET_QUEUE_POLICY_INIT_OFF) WAN_NETIF_START_QUEUE(dev); #endif if (card->wandev.state == WAN_CONNECTED){ set_chan_state(card, dev, WAN_CONNECTED); WAN_NETIF_CARRIER_ON(dev); } else { WAN_NETIF_CARRIER_OFF(dev); } /* Increment the module usage count */ wanpipe_open(card); /* Wait for the front end interrupt * before enabling the card */ return 0; } /*============================================================================ * if_close - Close network interface. * * @dev: Network device pointer * * On ifconfig down, this function gets called in order * to cleanup interace private area. * * IMPORTANT: * * No deallocation or unconfiguration should ever occur in this * function, because the interface can come back up * (via ifconfig up). * * Furthermore, in dynamic interfacace configuration mode, the * interface will come up and down to reflect the protocol state. * * Any deallocation and cleanup can occur in del_if() * function. That function is called before the dev interface * itself is deallocated. * * Thus, we should only stop the net queue and decrement * the wanpipe usage counter via wanpipe_close() function. */ static int if_close (netdevice_t* dev) { private_area_t* chan = wan_netif_priv(dev); sdla_t* card = chan->card; WAN_NETIF_STOP_QUEUE(dev); #if defined(LINUX_2_1) dev->start=0; #endif protocol_stop(card,dev); wanpipe_close(card); return 0; } /*============================================================= * disable_comm - Main shutdown function * * @card: Wanpipe device pointer * * The command 'wanrouter stop' has been called * and the whole wanpipe device is going down. * This is the last function called to disable * all comunications and deallocate any memory * that is still allocated. * * o Disable communications, turn off interrupts * o Deallocate memory used, if any * o Unconfigure TE1 card */ /* Wait for 100 ms hardcoded */ static void disable_comm_delay(void) { unsigned long timeout=SYSTEM_TICKS; while ((SYSTEM_TICKS-timeout)< (HZ/10)){ schedule(); } } static void disable_comm (sdla_t *card) { wan_smp_flag_t smp_flags,smp_flags1; int used_cnt; int port_task_timeout=0; AFT_FUNC_DEBUG(); #if INIT_FE_ONLY aft_chip_unconfigure(card); #else /* Make sure that Task is disabled for this card */ wan_set_bit(CARD_PORT_TASK_DOWN,&card->wandev.critical); while (wan_test_bit(CARD_PORT_TASK_RUNNING,&card->wandev.critical)) { disable_comm_delay(); /* 100 ms */ port_task_timeout++; if (port_task_timeout > 20) { DEBUG_EVENT("%s: Warning: Port Task stuck! timing out!\n",card->devname); break; } } __aft_fe_intr_ctrl(card, 0); /* Unconfiging, only on shutdown */ if (card->wandev.fe_iface.pre_release){ card->wandev.fe_iface.pre_release(&card->fe); } card->hw_iface.hw_lock(card->hw,&smp_flags1); wan_spin_lock_irq(&card->wandev.lock, &smp_flags); if (card->wandev.fe_iface.unconfig){ card->wandev.fe_iface.unconfig(&card->fe); } wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); card->hw_iface.hw_unlock(card->hw,&smp_flags1); /* Disable DMA ENGINE before we perform * core reset. Otherwise, we will receive * rx fifo errors on subsequent resetart. */ wan_spin_lock_irq(&card->wandev.lock,&smp_flags); disable_data_error_intr(card,DEVICE_DOWN); aft_handle_clock_master(card); #if defined(AFT_RTP_SUPPORT) aft_rtp_unconfig(card); #endif wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); aft_chip_unconfigure(card); /* Only disable the irq completely once the chip unconfigure is executed */ wan_spin_lock_irq(&card->wandev.lock,&smp_flags); disable_data_error_intr(card,DEVICE_DOWN); wan_set_bit(CARD_DOWN,&card->wandev.critical); wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); WP_DELAY(10); card->hw_iface.getcfg(card->hw, SDLA_HWCPU_USEDCNT, &used_cnt); card->hw_iface.hw_lock(card->hw,&smp_flags1); wan_spin_lock_irq(&card->wandev.lock,&smp_flags); aft_hwdev[card->wandev.card_type].aft_led_ctrl(card, WAN_AFT_RED, 0,WAN_AFT_ON); aft_hwdev[card->wandev.card_type].aft_led_ctrl(card, WAN_AFT_GREEN, 0, WAN_AFT_ON); wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); card->hw_iface.hw_unlock(card->hw,&smp_flags1); __sdla_pull_ptr_isr_array(card->hw,card,WAN_FE_LINENO(&card->fe)); if (used_cnt<=1){ DEBUG_EVENT("%s: Global Chip Shutdown Usage=%d\n", card->devname,used_cnt); wan_spin_lock_irq(&card->wandev.lock,&smp_flags); aft_global_chip_disable(card); wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); } else { /* only re-enable front end interrupt if this * card is not last card */ __aft_fe_intr_ctrl(card, 1); } /* Initialize the AFT operation structure so on subsequent restart the card->u.aft strcutre is fully initialized */ memset(&card->u.aft,0,sizeof(card->u.aft)); #endif return; } /*============================================================================ * if_tx_timeout * * Kernel networking stack calls this function in case * the interface has been stopped for TX_TIMEOUT seconds. * * This would occur if we lost TX interrupts or the * card has stopped working for some reason. * * Handle transmit timeout event from netif watchdog */ static void if_tx_timeout (netdevice_t *dev) { private_area_t* chan = wan_netif_priv(dev); private_area_t* ch_ptr; sdla_t *card = chan->card; unsigned int cur_dma_ptr; u32 reg,dma_ram_desc; wan_smp_flag_t smp_flags; /* If our device stays busy for at least 5 seconds then we will * kick start the device by making dev->tbusy = 0. We expect * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. */ WAN_NETIF_STATS_INC_COLLISIONS(&chan->common); //++chan->if_stats.collisions; DEBUG_EVENT( "%s: Transmit timed out on %s\n", card->devname, wan_netif_name(dev)); dma_ram_desc=chan->logic_ch_num*4+AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); cur_dma_ptr=aft_dmachain_get_tx_dma_addr(reg); DEBUG_EVENT("%s: Chain TxPend=%d, TxCur=%d, TxPend=%d HwCur=%d TxA=%d TxC=%ld\n", chan->if_name, wan_test_bit(TX_INTR_PENDING,&chan->dma_chain_status), chan->tx_chain_indx, chan->tx_pending_chain_indx, cur_dma_ptr, chan->tx_attempts, WAN_NETIF_STATS_TX_PACKETS(&chan->common)); if (wan_test_bit(TX_DMA_BUSY,&chan->dma_status)){ wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); } wan_netif_set_ticks(dev, SYSTEM_TICKS); #ifdef AFT_TX_FIFO_DEBUG aft_list_tx_descriptors(chan); #endif wan_spin_lock_irq(&card->wandev.lock, &smp_flags); if (chan->channelized_cfg){ for (ch_ptr=chan;ch_ptr;ch_ptr=ch_ptr->next){ aft_tx_fifo_under_recover(card,chan); } }else{ aft_tx_fifo_under_recover(card,chan); } wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); #ifdef AFT_TX_FIFO_DEBUG aft_list_tx_descriptors(chan); #endif wanpipe_wake_stack(chan); } /*============================================================================ * if_send - Send a packet on a network interface. * * @dev: Network interface pointer * @skb: Packet obtained from the stack or API * that should be sent out the port. * * o Mark interface as stopped * (marks start of the transmission) to indicate * to the stack that the interface is busy. * * o Check link state. * If link is not up, then drop the packet. * * o Copy the tx packet into the protocol tx buffers on * the adapter. * * o If tx successful: * Free the skb buffer and mark interface as running * and return 0. * * o If tx failed, busy: * Keep interface marked as busy * Do not free skb buffer * Enable Tx interrupt (which will tell the stack * that interace is not busy) * Return a non-zero value to tell the stack * that the tx should be retried. * * Return: 0 complete (socket buffer must be freed) * non-0 packet may be re-transmitted * */ #if defined(__LINUX__) static int if_send (netskb_t* skb, netdevice_t* dev) #else static int if_send(netdevice_t *dev, netskb_t *skb, struct sockaddr *dst,struct rtentry *rt) #endif { private_area_t *chan = wan_netif_priv(dev); sdla_t *card = chan->card; int err; netskb_t *rskb=NULL; wan_smp_flag_t smp_flags; /* Mark interface as busy. The kernel will not * attempt to send any more packets until we clear * this condition */ if (skb == NULL){ /* This should never happen. Just a sanity check. */ DEBUG_EVENT( "%s: interface %s got kicked!\n", card->devname, wan_netif_name(dev)); WAN_NETIF_WAKE_QUEUE(dev); return 0; } DEBUG_TX("%s: Sending %d bytes\n", wan_netif_name(dev), wan_skb_len(skb)); /* Non 2.4 kernels used to call if_send() * after TX_TIMEOUT seconds have passed of interface * being busy. Same as if_tx_timeout() in 2.4 kernels */ #if defined(LINUX_2_1) if (dev->tbusy){ /* If our device stays busy for at least 5 seconds then we will * kick start the device by making dev->tbusy = 0. We expect * that our device never stays busy more than 5 seconds. So this * is only used as a last resort. */ WAN_NETIF_STATS_COLLISIONS(&chan->common); //++chan->if_stats.collisions; if((SYSTEM_TICKS - chan->tick_counter) < (5 * HZ)) { return 1; } if_tx_timeout(dev); } #endif err=0; if (chan->common.state != WAN_CONNECTED){ #if 1 WAN_NETIF_STOP_QUEUE(dev); wan_netif_set_ticks(dev, SYSTEM_TICKS); WAN_NETIF_STATS_INC_TX_CARRIER_ERRORS(&chan->common); //++chan->if_stats.tx_carrier_errors; return 1; #else WAN_NETIF_STATS_INC_TX_CARRIER_ERRORS(&chan->common); //++chan->if_stats.tx_carrier_errors; wan_skb_free(skb); WAN_NETIF_START_QUEUE(dev); err=0; goto if_send_exit_crit; #endif } if (chan->channelized_cfg) { private_area_t *top_chan=wan_netif_priv(chan->common.dev); DEBUG_TEST("%s:%ld Prev: Zaptel HDLC Tt TDMV_DCHAN=%i\n", chan->if_name,chan->logic_ch_num, card->u.aft.tdmv_dchan-1); if (!card->u.aft.tdmv_dchan || card->u.aft.tdmv_dchan>32){ DEBUG_EVENT("%s: DCHAN TX No DCHAN Configured!\n", card->devname); wan_skb_free(skb); WAN_NETIF_START_QUEUE(dev); err=0; goto if_send_exit_crit; } if(IS_BRI_CARD(card)) { chan=(private_area_t*)card->u.aft.dev_to_ch_map[BRI_DCHAN_LOGIC_CHAN]; }else{ chan=(private_area_t*)card->u.aft.dev_to_ch_map[card->u.aft.tdmv_dchan-1]; } if (!chan){ DEBUG_EVENT("%s: Warning: DCHAN TX: No DCHAN Configured (not preset)! Discarding data.\n", card->devname); wan_skb_free(skb); WAN_NETIF_START_QUEUE(dev); err=0; goto if_send_exit_crit; } if (!chan->hdlc_eng || (IS_BRI_CARD(card) && chan->dchan_time_slot < 0)){ wan_skb_free(skb); WAN_NETIF_START_QUEUE(dev); err=0; goto if_send_exit_crit; } wan_capture_trace_packet(chan->card, &top_chan->trace_info, skb,TRC_OUTGOING_FRM); DEBUG_TEST("%s:%ld Zaptel HDLC Tt TDMV_DCHAN=%i\n", chan->if_name,chan->logic_ch_num, card->u.aft.tdmv_dchan-1); } /* For TDM_VOICE_API no tx is supported in if_send */ if (chan->common.usedby == TDM_VOICE_API){ WAN_NETIF_STATS_INC_TX_ERRORS(&chan->common); WAN_NETIF_START_QUEUE(dev); err=0; goto if_send_exit_crit; } if (chan->common.usedby == API){ if (sizeof(api_tx_hdr_t) >= wan_skb_len(skb)){ wan_skb_free(skb); WAN_NETIF_STATS_INC_TX_ERRORS(&chan->common); WAN_NETIF_START_QUEUE(dev); err=0; goto if_send_exit_crit; } if (chan->cfg.ss7_enable) { err=aft_ss7_tx_mangle(card,chan,skb); if (err){ wan_skb_free(skb); WAN_NETIF_STATS_INC_TX_ERRORS(&chan->common); WAN_NETIF_START_QUEUE(dev); err=0; goto if_send_exit_crit; } } else if (chan->cfg.hdlc_repeat) { err=aft_hdlc_repeat_mangle(card,chan,skb,&rskb); if (err){ wan_skb_free(skb); WAN_NETIF_STATS_INC_TX_ERRORS(&chan->common); WAN_NETIF_START_QUEUE(dev); err=0; goto if_send_exit_crit; } } else { wan_skb_pull(skb,sizeof(api_tx_hdr_t)); } } if (!chan->hdlc_eng && chan->tslot_sync){ if (wan_skb_len(skb)%chan->num_of_time_slots){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s:%s: Tx Error pkt len(%d) not multiple of timeslots(%d)\n", card->devname, chan->if_name, wan_skb_len(skb), chan->num_of_time_slots); } wan_skb_free(skb); WAN_NETIF_STATS_INC_TX_ERRORS(&chan->common); //++chan->if_stats.tx_errors; WAN_NETIF_START_QUEUE(dev); err=0; goto if_send_exit_crit; } } if (!chan->hdlc_eng && !chan->lip_atm && (wan_skb_len(skb)%4)){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: Tx Error: Tx Length %i is not 32bit divisible\n", chan->if_name,wan_skb_len(skb)); } wan_skb_free(skb); WAN_NETIF_STATS_INC_TX_ERRORS(&chan->common); //++chan->if_stats.tx_errors; WAN_NETIF_START_QUEUE(dev); err=0; goto if_send_exit_crit; } #if defined(CONFIG_PRODUCT_WANPIPE_AFT_BRI) if(IS_BRI_CARD(card)){ if(chan->dchan_time_slot >= 0){ /* NOTE: BRI dchan tx has to be done inside hw lock. It allows to synchronize access to SPI on the card. */ card->hw_iface.hw_lock(card->hw,&smp_flags); err=aft_bri_dchan_transmit(card, chan, wan_skb_data(skb), wan_skb_len(skb)); card->hw_iface.hw_unlock(card->hw,&smp_flags); if (err == 0 ) { WAN_NETIF_START_QUEUE(dev); wan_skb_free(skb); err=0; goto if_send_exit_crit; }else{ err=1; WAN_NETIF_STOP_QUEUE(dev); goto if_send_exit_crit; } } else { /* On b-channel data is transmitted using AFT DMA. Drop down to code below */ } } #endif wan_spin_lock_irq(&card->wandev.lock, &smp_flags); if (wan_skb_queue_len(&chan->wp_tx_pending_list) > chan->max_tx_bufs){ WAN_NETIF_STOP_QUEUE(dev); aft_dma_tx(card,chan); wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); return 1; } wan_skb_unlink(skb); wan_skb_queue_tail(&chan->wp_tx_pending_list,skb); if(!chan->lip_atm){ aft_dma_tx(card,chan); /*not needed for LIP_ATM!!*/ } if (rskb) { wan_skb_queue_tail(&chan->wp_tx_hdlc_rpt_list,rskb); } wan_netif_set_ticks(dev, SYSTEM_TICKS); WAN_NETIF_START_QUEUE(dev); err=0; wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); #if defined(__LINUX__) if (dev->tx_queue_len < chan->max_tx_bufs && dev->tx_queue_len > 0) { DEBUG_EVENT("%s: Resizing Tx Queue Len to %li\n", chan->if_name,dev->tx_queue_len); chan->max_tx_bufs = dev->tx_queue_len; } if (dev->tx_queue_len > chan->max_tx_bufs && chan->max_tx_bufs != chan->max_tx_bufs_orig) { DEBUG_EVENT("%s: Resizing Tx Queue Len to %i\n", chan->if_name,chan->max_tx_bufs_orig); chan->max_tx_bufs = chan->max_tx_bufs_orig; } #endif if_send_exit_crit: return err; } /*============================================================================ * if_stats * * Used by /proc/net/dev and ifconfig to obtain interface * statistics. * * Return a pointer to struct net_device_stats. */ #if defined(__LINUX__) static struct net_device_stats gstats; static struct net_device_stats* if_stats (netdevice_t* dev) { private_area_t* chan; sdla_t *card; if ((chan=wan_netif_priv(dev)) == NULL) return &gstats; card=chan->card; #if !defined(AFT_IRQ_DEBUG) if (card) { #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) if (card->wan_tdmv.sc && card->wandev.state == WAN_CONNECTED && card->wandev.config_id != WANCONFIG_AFT_ANALOG && chan->common.usedby == TDM_VOICE) { chan->common.if_stats.rx_packets = card->wandev.stats.rx_packets; chan->common.if_stats.tx_packets = card->wandev.stats.tx_packets; } #endif } #endif return &chan->common.if_stats; } #endif /*======================================================================== * * if_do_ioctl - Ioctl handler for fr * * @dev: Device subject to ioctl * @ifr: Interface request block from the user * @cmd: Command that is being issued * * This function handles the ioctls that may be issued by the user * to control or debug the protocol or hardware . * * It does both busy and security checks. * This function is intended to be wrapped by callers who wish to * add additional ioctl calls of their own. * * Used by: SNMP Mibs * wanpipemon debugger * */ static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, wan_ioctl_cmd_t cmd) { private_area_t* chan= (private_area_t*)wan_netif_priv(dev); sdla_t *card; wan_smp_flag_t smp_flags; wan_udp_pkt_t *wan_udp_pkt; int err=-EOPNOTSUPP; if (!chan || !chan->card){ DEBUG_EVENT("%s:%d: No Chan of card ptr\n", __FUNCTION__,__LINE__); return -ENODEV; } card=chan->card; if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ DEBUG_EVENT("%s: Card down: Ignoring Ioctl call!\n", card->devname); return -ENODEV; } switch(cmd) { #if defined(__LINUX__) case SIOC_WANPIPE_BIND_SK: if (!ifr){ err= -EINVAL; break; } wan_spin_lock_irq(&card->wandev.lock, &smp_flags); err=wan_bind_api_to_svc(chan,ifr->ifr_data); WAN_NETIF_STATS_RX_DROPPED(&chan->common)=0; //chan->if_stats.rx_dropped=0; if (!chan->hdlc_eng){ WAN_NETIF_STATS_TX_CARRIER_ERRORS(&chan->common)=0; //chan->if_stats.tx_carrier_errors=0; } wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); break; case SIOC_WANPIPE_UNBIND_SK: if (!ifr){ err= -EINVAL; break; } wan_spin_lock_irq(&card->wandev.lock, &smp_flags); err=wan_unbind_api_from_svc(chan,ifr->ifr_data); wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); break; case SIOC_WANPIPE_CHECK_TX: case SIOC_ANNEXG_CHECK_TX: err=0; break; case SIOC_WANPIPE_DEV_STATE: err = chan->common.state; break; case SIOC_ANNEXG_KICK: err=0; break; case SIOC_AFT_SS7_FORCE_RX: wan_spin_lock_irq(&card->wandev.lock, &smp_flags); aft_set_ss7_force_rx(card,chan); wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); break; #endif #if defined(AFT_API_SUPPORT) case SIOC_WANPIPE_API: DEBUG_TEST("%s: WANPIPE API IOCTL!\n", card->devname); err = wan_aft_api_ioctl(card,chan,ifr->ifr_data); break; #endif case SIOC_WAN_DEVEL_IOCTL: err = aft_devel_ioctl(card, ifr); break; case SIOC_AFT_CUSTOMER_ID: if (!ifr){ return -EINVAL; } else { unsigned char cid=0; wan_smp_flag_t smp_flags1; card->hw_iface.hw_lock(card->hw,&smp_flags1); wan_spin_lock_irq(&card->wandev.lock, &smp_flags); cid=aft_read_cpld(card,CUSTOMER_CPLD_ID_REG); wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); card->hw_iface.hw_unlock(card->hw,&smp_flags1); return WAN_COPY_TO_USER(ifr->ifr_data,&cid,sizeof(unsigned char)); } err=0; break; #if defined(__LINUX__) case SIOC_WANPIPE_GET_DEVICE_CONFIG_ID: err=card->wandev.config_id; break; #endif case SIOC_WANPIPE_SNMP: case SIOC_WANPIPE_SNMP_IFSPEED: return wan_snmp_data(card, dev, cmd, ifr); case SIOC_WANPIPE_PIPEMON: NET_ADMIN_CHECK(); if (wan_atomic_read(&chan->udp_pkt_len) != 0){ return -EBUSY; } wan_atomic_set(&chan->udp_pkt_len,MAX_LGTH_UDP_MGNT_PKT); /* For performance reasons test the critical * here before spin lock */ if (wan_test_bit(0,&card->in_isr)){ wan_atomic_set(&chan->udp_pkt_len,0); return -EBUSY; } wan_udp_pkt=(wan_udp_pkt_t*)chan->udp_pkt_data; if (WAN_COPY_FROM_USER( &wan_udp_pkt->wan_udp_hdr, ifr->ifr_data, sizeof(wan_udp_hdr_t))){ wan_atomic_set(&chan->udp_pkt_len,0); return -EFAULT; } /* We have to check here again because we don't know * what happened during spin_lock */ if (wan_test_bit(0,&card->in_isr)) { DEBUG_EVENT( "%s:%s Pipemon command failed, Driver busy: try again.\n", card->devname, wan_netif_name(dev)); wan_atomic_set(&chan->udp_pkt_len,0); return -EBUSY; } process_udp_mgmt_pkt(card,dev,chan,1); /* This area will still be critical to other * PIPEMON commands due to udp_pkt_len * thus we can release the irq */ if (wan_atomic_read(&chan->udp_pkt_len) > sizeof(wan_udp_pkt_t)){ DEBUG_EVENT( "%s: Error: Pipemon buf too bit on the way up! %d\n", card->devname,wan_atomic_read(&chan->udp_pkt_len)); wan_atomic_set(&chan->udp_pkt_len,0); return -EINVAL; } if (WAN_COPY_TO_USER( ifr->ifr_data, &wan_udp_pkt->wan_udp_hdr, sizeof(wan_udp_hdr_t))){ wan_atomic_set(&chan->udp_pkt_len,0); return -EFAULT; } wan_atomic_set(&chan->udp_pkt_len,0); return 0; #if 0 case SIOC_WAN_EC_IOCTL: if (wan_test_and_set_bit(CARD_HW_EC,&card->wandev.critical)){ DEBUG_EVENT("%s: Error: EC IOCTL Reentrant!\n", card->devname); return -EBUSY; } if (card->wandev.ec){ err = wan_ec_ioctl(card->wandev.ec, ifr, card); }else{ err = -EINVAL; } wan_clear_bit(CARD_HW_EC,&card->wandev.critical); break; #endif /* case SIOC_WAN_FE_IOCTL: DEBUG_TEST("%s: Command %x not supported!\n", card->devname,cmd); return -EOPNOTSUPP; break; */ default: #ifndef WANPIPE_GENERIC DEBUG_TEST("%s: Command %x not supported!\n", card->devname,cmd); return -EOPNOTSUPP; #else if (card->wandev.hdlc_ioctl){ err = card->wandev.hdlc_ioctl(card, dev, ifr, cmd); } #endif } return err; } /**SECTION********************************************************** * * FIRMWARE Specific Interface Functions * *******************************************************************/ #define FIFO_RESET_TIMEOUT_CNT 1000 #define FIFO_RESET_TIMEOUT_US 10 static int aft_init_rx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char wait) { u32 reg; u32 dma_descr; u8 timeout=1; u16 i; unsigned int cur_dma_ptr; u32 dma_ram_desc; /* Clean RX DMA fifo */ if (chan->single_dma_chain){ dma_descr=(chan->logic_ch_num<<4) + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); aft_dmachain_set_rx_dma_addr(®,0); card->hw_iface.bus_write_4(card->hw,dma_ram_desc,reg); }else{ dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); cur_dma_ptr=aft_dmachain_get_rx_dma_addr(reg); dma_descr=(chan->logic_ch_num<<4) + (cur_dma_ptr*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); } reg=0; wan_set_bit(AFT_RXDMA_HI_DMA_CMD_BIT,®); DEBUG_TEST("%s: Clearing RX Fifo %s Ch=%ld DmaDescr=(0x%X) Reg=(0x%X) WAIT=%s\n", __FUNCTION__,chan->if_name,chan->logic_ch_num, dma_descr,reg,wait == WP_WAIT?"YES":"NO"); card->hw_iface.bus_write_4(card->hw,dma_descr,reg); if (wait == WP_WAIT){ for(i=0;ihw_iface.bus_read_4(card->hw,dma_descr,®); if (wan_test_bit(AFT_RXDMA_HI_DMA_CMD_BIT,®)){ WP_DELAY(FIFO_RESET_TIMEOUT_US); continue; } timeout=0; break; } if (timeout){ int max_logic_ch; u32 dmareg; card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),&dmareg); max_logic_ch = aft_dmactrl_get_max_logic_ch(dmareg); DEBUG_EVENT("%s:%s: Error: Rx fifo reset timedout %u us (ch=%d) DMA CTRL=0x%08X DMA MAX=%i\n", card->devname, chan->if_name, i*FIFO_RESET_TIMEOUT_US, chan->logic_ch_num, dmareg,max_logic_ch); }else{ DEBUG_TEST("%s:%s: Rx Fifo Reset Successful\n", card->devname,chan->if_name); } }else{ timeout=0; } return timeout; } static int aft_init_tx_dev_fifo(sdla_t *card, private_area_t *chan, unsigned char wait) { u32 reg; u32 dma_descr,dma_ram_desc; u8 timeout=1; u16 i; unsigned int cur_dma_ptr; if (chan->single_dma_chain){ dma_descr=(chan->logic_ch_num<<4) + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); aft_dmachain_set_tx_dma_addr(®,0); card->hw_iface.bus_write_4(card->hw,dma_ram_desc,reg); }else{ dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); cur_dma_ptr=aft_dmachain_get_tx_dma_addr(reg); /* Clean TX DMA fifo */ dma_descr=(chan->logic_ch_num<<4) + (cur_dma_ptr*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); } reg=0; wan_set_bit(AFT_TXDMA_HI_DMA_CMD_BIT,®); DEBUG_TEST("%s: Clearing TX Fifo %s Ch=%ld DmaDescr=(0x%X) Reg=(0x%X) WAIT=%s\n", __FUNCTION__,chan->if_name,chan->logic_ch_num, dma_descr,reg,wait == WP_WAIT?"YES":"NO"); card->hw_iface.bus_write_4(card->hw,dma_descr,reg); if (wait == WP_WAIT){ for(i=0;ihw_iface.bus_read_4(card->hw,dma_descr,®); if (wan_test_bit(AFT_TXDMA_HI_DMA_CMD_BIT,®)){ WP_DELAY(FIFO_RESET_TIMEOUT_US); continue; } timeout=0; break; } if (timeout){ DEBUG_EVENT("%s:%s: Error: Tx fifo reset timedout %u us (ch=%d)\n", card->devname, chan->if_name, i*FIFO_RESET_TIMEOUT_US, chan->logic_ch_num); }else{ DEBUG_TEST("%s:%s: Tx Fifo Reset Successful\n", card->devname,chan->if_name); } }else{ timeout=0; } return timeout; } static void aft_channel_txdma_ctrl(sdla_t *card, private_area_t *chan, int on) { u32 reg; /* Enable TX DMA for Logic Channel */ card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_TX_DMA_CTRL_REG), ®); if (on){ wan_set_bit(chan->logic_ch_num,®); }else{ wan_clear_bit(chan->logic_ch_num,®); } card->hw_iface.bus_write_4(card->hw, AFT_PORT_REG(card,AFT_TX_DMA_CTRL_REG), reg); } static void aft_channel_rxdma_ctrl(sdla_t *card, private_area_t *chan, int on) { u32 reg; /* Enable TX DMA for Logic Channel */ card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_RX_DMA_CTRL_REG), ®); if (on){ wan_set_bit(chan->logic_ch_num,®); }else{ wan_clear_bit(chan->logic_ch_num,®); } card->hw_iface.bus_write_4(card->hw, AFT_PORT_REG(card,AFT_RX_DMA_CTRL_REG), reg); } static void aft_channel_txintr_ctrl(sdla_t *card, private_area_t *chan, int on) { u32 reg; /* Enable Logic Channel TX Interrupts */ card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_TX_DMA_INTR_MASK_REG), ®); if (on){ wan_set_bit(chan->logic_ch_num,®); }else{ wan_clear_bit(chan->logic_ch_num,®); } card->hw_iface.bus_write_4(card->hw, AFT_PORT_REG(card,AFT_TX_DMA_INTR_MASK_REG), reg); } static void aft_channel_rxintr_ctrl(sdla_t *card, private_area_t *chan, int on) { u32 reg; /* Enable Logic Channel TX Interrupts */ card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_RX_DMA_INTR_MASK_REG), ®); if (on){ wan_set_bit(chan->logic_ch_num,®); }else{ wan_clear_bit(chan->logic_ch_num,®); } card->hw_iface.bus_write_4(card->hw, AFT_PORT_REG(card,AFT_RX_DMA_INTR_MASK_REG), reg); } static void aft_dev_enable(sdla_t *card, private_area_t *chan) { DEBUG_CFG("%s: Enabling Global Inter Mask !\n",chan->if_name); /* Enable TX DMA for Logic Channel */ aft_channel_txdma_ctrl(card,chan,1); /* Enable RX DMA for Logic Channel */ aft_channel_rxdma_ctrl(card,chan,1); /* Enable Logic Channel TX Interrupts */ if (chan->channelized_cfg && !chan->hdlc_eng){ aft_channel_txintr_ctrl(card,chan,0); aft_channel_rxintr_ctrl(card,chan,0); chan->tdmv_irq_cfg=1; }else{ DEBUG_CFG("%s: Enabling FOR NON CHANNELIZED !\n",chan->if_name); aft_channel_txintr_ctrl(card,chan,1); aft_channel_rxintr_ctrl(card,chan,1); } wan_set_bit(chan->logic_ch_num,&card->u.aft.active_ch_map); DEBUG_CFG("%s: ACTIVE CH MAP !\n",chan->if_name); } static void aft_dev_open_private(sdla_t *card, private_area_t *chan) { if (IS_BRI_CARD(card) && chan->dchan_time_slot >= 0){ /* BRI dchan does not use DMA thus skip the dma config code below */ return; } if (card->wandev.state == WAN_CONNECTED && wan_test_bit(0,&card->u.aft.comm_enabled)){ DEBUG_TEST("%s: OPEN reseting fifo Channel = %li\n", chan->if_name,chan->logic_ch_num); aft_tslot_sync_ctrl(card,chan,0); aft_init_rx_dev_fifo(card,chan,WP_NO_WAIT); aft_init_tx_dev_fifo(card,chan,WP_NO_WAIT); aft_dev_enable(card,chan); aft_init_rx_dev_fifo(card,chan,WP_WAIT); aft_init_tx_dev_fifo(card,chan,WP_WAIT); chan->dma_index=0; memset(chan->dma_history,0,sizeof(chan->dma_history)); aft_reset_rx_chain_cnt(chan); aft_dma_rx(card,chan); aft_tslot_sync_ctrl(card,chan,1); if (!chan->hdlc_eng){ aft_reset_tx_chain_cnt(chan); aft_dma_tx(card,chan); } }else{ aft_dev_enable(card,chan); } } static void aft_dev_open(sdla_t *card, private_area_t *gchan) { private_area_t *chan=gchan; if (chan->channelized_cfg){ for (chan=gchan; chan != NULL; chan=chan->next){ aft_dev_open_private(card,chan); wan_set_bit(0,&chan->up); } if (gchan->common.usedby == TDM_VOICE_API){ /* Set the global mtu value which is * the sum of all timeslots mtus */ wan_netif_set_mtu( gchan->common.dev, card->u.aft.tdmv_mtu+sizeof(api_tx_hdr_t)); } wan_set_bit(0,&card->u.aft.tdmv_master_if_up); if (card->wandev.state == WAN_CONNECTED && !wan_test_bit(0,&card->u.aft.comm_enabled)){ DEBUG_EVENT("%s: Master IF Starting %s Communications\n", gchan->if_name,card->devname); enable_data_error_intr(card); } }else{ aft_dev_open_private(card,chan); wan_set_bit(0,&chan->up); } if (gchan->cfg.ss7_enable){ aft_clear_ss7_force_rx(card,gchan); } return; } static void aft_dev_close_private(sdla_t *card, private_area_t *chan) { if (chan->logic_ch_num < 0){ return; } if (IS_BRI_CARD(card) && chan->dchan_time_slot >= 0){ /* BRI dchan does not use DMA thus skip the dma config code below */ return; } DEBUG_TEST("%s: Chan=%i\n",__FUNCTION__,chan->logic_ch_num); /* Disable Logic Channel TX Interrupts */ aft_channel_txintr_ctrl(card,chan,0); /* Disable Logic Channel RX Interrupts */ aft_channel_rxintr_ctrl(card,chan,0); /* Disable TX DMA for Logic Channel */ aft_channel_txdma_ctrl(card,chan,0); /* Disable RX DMA for Logic Channel */ aft_channel_rxdma_ctrl(card,chan,0); /* Initialize DMA descriptors and DMA Chains */ aft_init_tx_rx_dma_descr(chan); } static void aft_dev_close(sdla_t *card, private_area_t *gchan) { private_area_t *chan=gchan; if (chan->channelized_cfg){ if (IS_BRI_CARD(card)) { int card_use_cnt; card->hw_iface.getcfg(card->hw, SDLA_HWCPU_USEDCNT, &card_use_cnt); if (card_use_cnt == 1) { DEBUG_TEST("%s: BRI Disabling TDMV INTR\n", card->devname); aft_tdm_intr_ctrl(card,0); aft_fifo_intr_ctrl(card, 0); } } else { aft_tdm_intr_ctrl(card,0); aft_fifo_intr_ctrl(card, 0); } for (chan=gchan; chan != NULL; chan=chan->next){ aft_dev_close_private(card,chan); DEBUG_TEST("%s: Closing Ch=%ld\n", chan->if_name,chan->logic_ch_num); wan_clear_bit(0,&chan->up); wan_set_bit(0,&chan->interface_down); if (chan->cfg.tdmv_master_if){ wan_clear_bit(0,&card->u.aft.tdmv_master_if_up); } DEBUG_TEST("%s: Closing Ch=%ld MasterUP=%i\n", chan->if_name,chan->logic_ch_num, wan_test_bit(0,&card->u.aft.tdmv_master_if_up)); } }else{ wan_set_bit(0,&chan->interface_down); wan_clear_bit(0,&chan->up); aft_dev_close_private(card,chan); } return; } /**SECTION************************************************************* * * TX Handlers * **********************************************************************/ /*=============================================== * aft_dma_tx_complete * */ static void aft_dma_tx_complete (sdla_t *card, private_area_t *chan, int wdt, int reset) { DEBUG_TEST("%s: Tx interrupt wdt=%d\n",chan->if_name,wdt); if (!wdt){ wan_clear_bit(TX_INTR_PENDING,&chan->dma_chain_status); } if (chan->channelized_cfg && !chan->hdlc_eng){ aft_tx_dma_voice_handler((unsigned long)chan,wdt,reset); }else{ aft_tx_dma_chain_handler((unsigned long)chan,wdt,reset); } wan_set_bit(0,&chan->idle_start); if (reset){ return; } aft_dma_tx(card,chan); if (WAN_NETIF_QUEUE_STOPPED(chan->common.dev)){ /* Wakeup stack also wakes up DCHAN, however, for DCHAN we must always call the upper layer and let it decide what to do */ wanpipe_wake_stack(chan); } if (chan->common.usedby == TDM_VOICE_DCHAN){ #ifdef AFT_TDM_API_SUPPORT if (is_tdm_api(chan,&chan->wp_tdm_api_dev)){ wanpipe_tdm_api_kick(&chan->wp_tdm_api_dev); } #endif } return; } /*=============================================== * aft_tx_post_complete * */ static void aft_tx_post_complete (sdla_t *card, private_area_t *chan, netskb_t *skb) { unsigned int reg = wan_skb_csum(skb); u32 dma_status = aft_txdma_hi_get_dma_status(reg); wan_skb_set_csum(skb,0); if (reg & AFT_TXDMA_HI_DMA_LENGTH_MASK){ chan->errstats.Tx_dma_len_nonzero++; } if ((wan_test_bit(AFT_TXDMA_HI_GO_BIT,®)) || (reg & AFT_TXDMA_HI_DMA_LENGTH_MASK) || dma_status){ DEBUG_TEST("%s:%s: Tx DMA Descriptor=0x%X\n", card->devname,chan->if_name,reg); /* Checking Tx DMA Go bit. Has to be '0' */ if (wan_test_bit(AFT_TXDMA_HI_GO_BIT,®)){ DEBUG_TEST("%s:%s: Error: TxDMA Intr: GO bit set on Tx intr\n", card->devname,chan->if_name); chan->errstats.Tx_dma_errors++; } if (reg & AFT_TXDMA_HI_DMA_LENGTH_MASK){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s:%s: Error: TxDMA Length not equal 0 (reg=0x%08X)\n", card->devname,chan->if_name,reg); } chan->errstats.Tx_dma_errors++; } /* Checking Tx DMA PCI error status. Has to be '0's */ if (dma_status){ chan->errstats.Tx_pci_errors++; if (wan_test_bit(AFT_TXDMA_HIDMASTATUS_PCI_M_ABRT,&dma_status)){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s:%s: Tx Error: Abort from Master: pci fatal error!\n", card->devname,chan->if_name); } } if (wan_test_bit(AFT_TXDMA_HIDMASTATUS_PCI_T_ABRT,&dma_status)){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s:%s: Tx Error: Abort from Target: pci fatal error!\n", card->devname,chan->if_name); } } if (wan_test_bit(AFT_TXDMA_HIDMASTATUS_PCI_DS_TOUT,&dma_status)){ DEBUG_TEST("%s:%s: Tx Warning: PCI Latency Timeout!\n", card->devname,chan->if_name); chan->errstats.Tx_pci_latency++; goto tx_post_ok; } if (wan_test_bit(AFT_TXDMA_HIDMASTATUS_PCI_RETRY,&dma_status)){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s:%s: Tx Error: 'Retry' exceeds maximum (64k): pci fatal error!\n", card->devname,chan->if_name); } } } WAN_NETIF_STATS_INC_TX_ERRORS(&chan->common); //chan->if_stats.tx_errors++; goto tx_post_exit; } tx_post_ok: chan->opstats.Data_frames_Tx_count++; chan->opstats.Data_bytes_Tx_count+=wan_skb_len(skb); WAN_NETIF_STATS_INC_TX_PACKETS(&chan->common); //chan->if_stats.tx_packets++; WAN_NETIF_STATS_INC_TX_BYTES(&chan->common, wan_skb_len(skb)); //chan->if_stats.tx_bytes+=wan_skb_len(skb); #if 0 if (chan->common.usedby != TDM_VOICE){ wan_capture_trace_packet(card, &chan->trace_info, skb, TRC_OUTGOING_FRM); } #endif tx_post_exit: return; } /**SECTION************************************************************* * * RX Handlers * **********************************************************************/ /*=============================================== * aft_rx_post_complete * */ static void aft_rx_post_complete (sdla_t *card, private_area_t *chan, netskb_t *skb, netskb_t **new_skb, unsigned char *pkt_error) { unsigned int len,data_error = 0; unsigned char *buf; wp_rx_element_t *rx_el; u32 dma_status; rx_el=(wp_rx_element_t *)wan_skb_data(skb); DEBUG_RX("%s:%s: RX HI=0x%X LO=0x%X DMA=0x%X", __FUNCTION__, chan->if_name, rx_el->reg, rx_el->align, rx_el->dma_addr); #if 0 /* debugging */ WAN_NETIF_STATS_INC_RX_ERRORS(&chan->common); //chan->if_stats.rx_errors++; #endif rx_el->align&=AFT_RXDMA_LO_ALIGN_MASK; *pkt_error=0; *new_skb=NULL; dma_status=aft_rxdma_hi_get_dma_status(rx_el->reg); /* Checking Rx DMA Go bit. Has to be '0' */ if (wan_test_bit(AFT_RXDMA_HI_GO_BIT,&rx_el->reg)){ DEBUG_TEST("%s:%s: Error: RxDMA Intr: GO bit set on Rx intr\n", card->devname,chan->if_name); WAN_NETIF_STATS_INC_RX_ERRORS(&chan->common); //chan->if_stats.rx_errors++; chan->errstats.Rx_dma_descr_err++; goto rx_comp_error; } /* Checking Rx DMA PCI error status. Has to be '0's */ if (dma_status){ if (wan_test_bit(AFT_RXDMA_HIDMASTATUS_PCI_M_ABRT,&dma_status)){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s:%s: Rx Error: Abort from Master: pci fatal error 0x%X!\n", card->devname,chan->if_name,rx_el->reg); } } if (wan_test_bit(AFT_RXDMA_HIDMASTATUS_PCI_T_ABRT,&dma_status)){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s:%s: Rx Error: Abort from Target: pci fatal error 0x%X!\n", card->devname,chan->if_name,rx_el->reg); } } if (wan_test_bit(AFT_RXDMA_HIDMASTATUS_PCI_DS_TOUT,&dma_status)){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s:%s: Rx Error: No 'DeviceSelect' from target: pci fatal error 0x%X!\n", card->devname,chan->if_name,rx_el->reg); } } if (wan_test_bit(AFT_RXDMA_HIDMASTATUS_PCI_RETRY,&dma_status)){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s:%s: Rx Error: 'Retry' exceeds maximum (64k): pci fatal error 0x%X!\n", card->devname,chan->if_name,rx_el->reg); } } chan->errstats.Rx_pci_errors++; WAN_NETIF_STATS_INC_RX_ERRORS(&chan->common); //chan->if_stats.rx_errors++; card->wandev.stats.rx_errors++; goto rx_comp_error; } if (chan->hdlc_eng){ /* Checking Rx DMA Frame start bit. (information for api) */ if (!wan_test_bit(AFT_RXDMA_HI_START_BIT,&rx_el->reg)){ DEBUG_TEST("%s:%s RxDMA Intr: Start flag missing: MTU Mismatch! Reg=0x%X\n", card->devname,chan->if_name,rx_el->reg); WAN_NETIF_STATS_INC_RX_FRAME_ERRORS(&chan->common); //chan->if_stats.rx_frame_errors++; chan->opstats.Rx_Data_discard_long_count++; chan->errstats.Rx_hdlc_corrupiton++; card->wandev.stats.rx_errors++; goto rx_comp_error; } /* Checking Rx DMA Frame end bit. (information for api) */ if (!wan_test_bit(AFT_RXDMA_HI_EOF_BIT,&rx_el->reg)){ DEBUG_TEST("%s:%s: RxDMA Intr: End flag missing: MTU Mismatch! Reg=0x%X\n", card->devname,chan->if_name,rx_el->reg); WAN_NETIF_STATS_INC_RX_FRAME_ERRORS(&chan->common); //chan->if_stats.rx_frame_errors++; chan->opstats.Rx_Data_discard_long_count++; chan->errstats.Rx_hdlc_corrupiton++; card->wandev.stats.rx_errors++; goto rx_comp_error; } else { /* Check CRC error flag only if this is the end of Frame */ if (wan_test_bit(AFT_RXDMA_HI_FCS_ERR_BIT,&rx_el->reg)){ DEBUG_TEST("%s:%s: RxDMA Intr: CRC Error! Reg=0x%X Len=%d\n", card->devname,chan->if_name,rx_el->reg, (rx_el->reg&AFT_RXDMA_HI_DMA_LENGTH_MASK)>>2); WAN_NETIF_STATS_INC_RX_FRAME_ERRORS(&chan->common); //chan->if_stats.rx_frame_errors++; chan->errstats.Rx_crc_err_count++; card->wandev.stats.rx_crc_errors++; wan_set_bit(WP_CRC_ERROR_BIT,&rx_el->pkt_error); data_error = 1; } /* Check if this frame is an abort, if it is * drop it and continue receiving */ if (wan_test_bit(AFT_RXDMA_HI_FRM_ABORT_BIT,&rx_el->reg)){ DEBUG_TEST("%s:%s: RxDMA Intr: Abort! Reg=0x%X\n", card->devname,chan->if_name,rx_el->reg); WAN_NETIF_STATS_INC_RX_FRAME_ERRORS(&chan->common); //chan->if_stats.rx_frame_errors++; chan->errstats.Rx_hdlc_corrupiton++; card->wandev.stats.rx_frame_errors++; wan_set_bit(WP_ABORT_ERROR_BIT,&rx_el->pkt_error); data_error = 1; } if (chan->common.usedby != API && data_error){ goto rx_comp_error; } } } len = rx_el->len; #if 0 /* FIXME: Remove this later!!! */ len=rx_el->reg&AFT_RXDMA_HI_DMA_LENGTH_MASK; if (chan->hdlc_eng){ /* In HDLC mode, calculate rx length based * on alignment value, received from DMA */ len=((((chan->dma_mru>>2)-1)-len)<<2) - (~(rx_el->align)&AFT_RXDMA_LO_ALIGN_MASK); if (len < 3 || len > chan->dma_mru){ WAN_NETIF_STATS_INC_RX_FRAME_ERRORS(&chan->common); //chan->if_stats.rx_frame_errors++; chan->errstats.Rx_hdlc_corrupiton++; card->wandev.stats.rx_frame_errors++; goto rx_comp_error; } }else{ /* In Transparent mode, our RX buffer will always be * aligned to the 32bit (word) boundary, because * the RX buffers are all of equal length */ len=(((chan->mru>>2)-len)<<2) - (~(0x03)&AFT_RXDMA_LO_ALIGN_MASK); if (len < 1 || len > chan->mru){ WAN_NETIF_STATS_INC_RX_FRAME_ERRORS(&chan->common); //chan->if_stats.rx_frame_errors++; card->wandev.stats.rx_frame_errors++; goto rx_comp_error; } } #endif *pkt_error=rx_el->pkt_error; /* After a RX FIFO overflow, we must mark max 7 * subsequent frames since firmware, cannot * guarantee the contents of the fifo */ if (wan_test_bit(WP_FIFO_ERROR_BIT,&rx_el->pkt_error)){ if (chan->hdlc_eng){ if (++chan->rx_fifo_err_cnt >= WP_MAX_FIFO_FRAMES){ chan->rx_fifo_err_cnt=0; } }else{ chan->rx_fifo_err_cnt=0; } wan_set_bit(WP_FIFO_ERROR_BIT,pkt_error); }else{ if (chan->rx_fifo_err_cnt){ if (++chan->rx_fifo_err_cnt >= WP_MAX_FIFO_FRAMES){ chan->rx_fifo_err_cnt=0; } wan_set_bit(WP_FIFO_ERROR_BIT,pkt_error); } } if (len > aft_rx_copyback){ /* The rx size is big enough, thus * send this buffer up the stack * and allocate another one */ memset(wan_skb_data(skb),0,sizeof(wp_rx_element_t)); #if defined(__FreeBSD__) wan_skb_trim(skb,sizeof(wp_rx_element_t)); #endif wan_skb_put(skb,len); wan_skb_pull(skb, sizeof(wp_rx_element_t)); *new_skb=skb; aft_alloc_rx_dma_buff(card,chan,1,1); }else{ /* The rx packet is very * small thus, allocate a new * buffer and pass it up */ *new_skb=wan_skb_alloc(len + 20); if (!*new_skb){ DEBUG_EVENT( "%s:%s: Failed to allocate rx skb pkt (len=%d)!\n", card->devname,chan->if_name,(len+20)); WAN_NETIF_STATS_INC_RX_DROPPED(&chan->common); //chan->if_stats.rx_dropped++; goto rx_comp_error; } buf=wan_skb_put((*new_skb),len); #if defined(__FreeBSD__) wan_skb_trim(skb,sizeof(wp_rx_element_t)); #endif memcpy(buf,wan_skb_tail(skb),len); aft_init_requeue_free_skb(chan, skb); } #if 0 if (chan->hdlc_eng){ buf=wan_skb_data(*new_skb); if (buf[wan_skb_len(*new_skb)-1] != 0x7E && buf[wan_skb_len(*new_skb)-1] != 0x7F){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: Rx: Invalid packet len=%d: 0x%X 0x%X 0x%X\n", card->devname, wan_skb_len(*new_skb), buf[wan_skb_len(*new_skb)-3], buf[wan_skb_len(*new_skb)-2], buf[wan_skb_len(*new_skb)-1]); } } } #endif return; rx_comp_error: aft_init_requeue_free_skb(chan, skb); return; } /**SECTION************************************************** * * Logic Channel Registration Support and * Utility funcitons * **********************************************************/ static int aft_init_requeue_free_skb(private_area_t *chan, netskb_t *skb) { WAN_ASSERT(skb == NULL); wan_skb_init(skb,16); wan_skb_trim(skb,0); wan_skb_queue_tail(&chan->wp_rx_free_list,skb); return 0; } static int aft_alloc_rx_dma_buff(sdla_t *card, private_area_t *chan, int num, int irq) { int i; netskb_t *skb; for (i=0;ichannelized_cfg && !chan->hdlc_eng){ #if defined(WANPIPE_64BIT_4G_DMA) /* On 64bit Systems greater than 4GB we must * allocated our DMA buffers using GFP_DMA * flag */ if (irq) { skb=__dev_alloc_skb(chan->dma_mru,GFP_DMA|GFP_ATOMIC); } else { skb=__dev_alloc_skb(chan->dma_mru,GFP_DMA|GFP_KERNEL); } #else if (irq) { skb=wan_skb_alloc(chan->dma_mru); } else { skb=wan_skb_kalloc(chan->dma_mru); } #endif } else { if (irq) { skb=wan_skb_alloc(chan->dma_mru); } else { skb=wan_skb_kalloc(chan->dma_mru); } } if (!skb){ DEBUG_EVENT("%s: %s no rx memory\n", chan->if_name,__FUNCTION__); return -ENOMEM; } wan_skb_queue_tail(&chan->wp_rx_free_list,skb); } return 0; } /*============================================================================ * Enable timer interrupt */ static void enable_timer (void* card_id) { sdla_t* card = (sdla_t*)card_id; #if !defined(WAN_IS_TASKQ_SCHEDULE) wan_smp_flag_t smp_flags; wan_smp_flag_t smp_flags1; int delay = 0; #endif if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ DEBUG_EVENT("%s: Card down: Ignoring enable_timer!\n", card->devname); return; } DEBUG_56K("%s: %s Sdla Polling %p!\n",__FUNCTION__, card->devname, card->wandev.fe_iface.polling); #if defined(WAN_IS_TASKQ_SCHEDULE) wan_set_bit(AFT_FE_POLL,&card->u.aft.port_task_cmd); WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); #else card->hw_iface.hw_lock(card->hw,&smp_flags1); wan_spin_lock_irq(&card->wandev.lock, &smp_flags); if (card->wandev.fe_iface.polling){ delay = card->wandev.fe_iface.polling(&card->fe); } wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); if (delay){ card->wandev.fe_iface.add_timer(&card->fe, delay); } card->hw_iface.hw_unlock(card->hw,&smp_flags1); #endif return; } static void enable_ec_timer (void* card_id) { #if defined(CONFIG_WANPIPE_HWEC) sdla_t* card = (sdla_t*)card_id; # if !defined(WAN_IS_TASKQ_SCHEDULE) wan_smp_flag_t smp_flags; wan_smp_flag_t smp_flags1; # endif if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ DEBUG_EVENT("%s: Card down: Ignoring enable_timer!\n", card->devname); return; } DEBUG_TEST("%s: %s Sdla EC Polling !\n",__FUNCTION__, card->devname); # if defined(WAN_IS_TASKQ_SCHEDULE) wan_set_bit(AFT_FE_EC_POLL,&card->u.aft.port_task_cmd); WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); # else # error "TASK Q Not defined" card->hw_iface.hw_lock(card->hw,&smp_flags1); wan_spin_lock_irq(&card->wandev.lock, &smp_flags); wanpipe_ec_poll(card->wandev.ec_dev, card); wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); card->hw_iface.hw_unlock(card->hw,&smp_flags1); # endif #endif return; } /**SECTION************************************************** * * API Bottom Half Handlers * **********************************************************/ static int tdm_check=0; #if defined(__LINUX__) static void wp_tdm_bh (unsigned long data) #else static void wp_tdm_bh (void *data, int pending) #endif { #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) private_area_t* chan = (private_area_t *)data; sdla_t *card=chan->card; int err; #if 0 if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: TDM BH Running !\n", chan->if_name); } #endif if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ goto wp_tdm_bh_exit; } if (!wan_test_bit(0,&chan->up)){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: wp_tdm_bh() chan not up!\n", chan->if_name); } goto wp_tdm_bh_exit; } #if 0 if (tdm_check){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: TDM BH Already Running 0x%02X... cool!\n", chan->if_name,tdm_check); } } wan_set_bit(card->tdmv_conf.span_no,&tdm_check); #endif WAN_TDMV_CALL(rx_tx_span, (card), err); WAN_TASKLET_END((&chan->common.bh_task)); if (card->wan_tdmv.sc){ WAN_TDMV_CALL(is_rbsbits, (&card->wan_tdmv), err); if (err == 1){ wan_set_bit(AFT_FE_TDM_RBS,&card->u.aft.port_task_cmd); WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); } } #if 0 wan_clear_bit(card->tdmv_conf.span_no,&tdm_check); #endif tdm_check++; return; wp_tdm_bh_exit: WAN_TASKLET_END((&chan->common.bh_task)); #endif return; } static void wp_bh_rx(private_area_t* chan, netskb_t *new_skb, u8 pkt_error, int len) { sdla_t *card = chan->card; if (chan->common.usedby == API){ if (chan->hdlc_eng){ if (card->u.aft.cfg.rx_crc_bytes == 3){ wan_skb_put(new_skb,3); }else if (card->u.aft.cfg.rx_crc_bytes == 2){ wan_skb_put(new_skb,2); } } if (chan->common.sk == NULL){ DEBUG_TEST("%s: No sock bound to channel rx dropping!\n", chan->if_name); WAN_NETIF_STATS_INC_RX_DROPPED(&chan->common); /* ++chan->if_stats.rx_dropped; */ wan_skb_free(new_skb); return; } #if defined(__LINUX__) # ifndef CONFIG_PRODUCT_WANPIPE_GENERIC /* Only for API, we insert packet status * byte to indicate a packet error. Take * this byte and put it in the api header */ if (wan_skb_headroom(new_skb) >= sizeof(api_rx_hdr_t)){ api_rx_hdr_t *rx_hdr= (api_rx_hdr_t*)skb_push(new_skb,sizeof(api_rx_hdr_t)); memset(rx_hdr,0,sizeof(api_rx_hdr_t)); rx_hdr->error_flag=pkt_error; }else{ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: Error Rx pkt headroom %u < %u\n", chan->if_name, (u32)wan_skb_headroom(new_skb), (u32)sizeof(api_rx_hdr_t)); } WAN_NETIF_STATS_INC_RX_DROPPED(&chan->common); /* ++chan->if_stats.rx_dropped; */ wan_skb_free(new_skb); return; } new_skb->protocol = htons(PVC_PROT); wan_skb_reset_mac_header(new_skb); new_skb->dev = chan->common.dev; new_skb->pkt_type = WAN_PACKET_DATA; #if 0 WAN_NETIF_STATS_INC_RX_FRAME_ERRORS(&chan->common); /* chan->if_stats.rx_frame_errors++; */ #endif if (wan_api_rx(chan,new_skb) != 0){ WAN_NETIF_STATS_INC_RX_DROPPED(&chan->common); /* ++chan->if_stats.rx_dropped; */ wan_skb_free(new_skb); return; } # endif #endif }else if (chan->common.usedby == TDM_VOICE_DCHAN){ #ifdef AFT_TDM_API_SUPPORT if (is_tdm_api(chan,&chan->wp_tdm_api_dev)) { int err; DEBUG_RX("%s: RX TDM API DCHAN %d\n",chan->if_name, wan_skb_len(new_skb)); if (wan_skb_headroom(new_skb) >= sizeof(api_rx_hdr_t)){ api_rx_hdr_t *rx_hdr = (api_rx_hdr_t*)skb_push(new_skb,sizeof(api_rx_hdr_t)); memset(rx_hdr,0,sizeof(api_rx_hdr_t)); //rx_hdr->error_flag=pkt_error; }else{ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: Error Rx pkt headroom %u < %u\n", chan->if_name, (u32)wan_skb_headroom(new_skb), (u32)sizeof(api_rx_hdr_t)); } WAN_NETIF_STATS_INC_RX_DROPPED(&chan->common); /* ++chan->if_stats.rx_dropped; */ wan_skb_free(new_skb); return; } err=wanpipe_tdm_api_rx_hdlc(&chan->wp_tdm_api_dev,new_skb); if (err){ WAN_NETIF_STATS_INC_RX_DROPPED(&chan->common); /* ++chan->if_stats.rx_dropped; */ wan_skb_free(new_skb); return; } }else #endif if (chan->tdmv_zaptel_cfg){ #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE_DCHAN) && defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) int err; /* ADEBUG */ WAN_TDMV_CALL(rx_dchan, (&card->wan_tdmv,chan->tdmv_chan, wan_skb_data(new_skb),wan_skb_len(new_skb)), err); DEBUG_RX("%s TDM DCHAN VOICE Rx Pkt Len=%i Chan=%i\n", card->devname,wan_skb_len(new_skb), chan->tdmv_chan); #else DEBUG_EVENT("%s: DCHAN Rx Packet critical error TDMV not compiled!\n",card->devname); #endif wan_skb_free(new_skb); /* Continue through since the above * function returns void */ } else { DEBUG_EVENT("%s: DCHAN Rx Packet critical error op not supported\n",card->devname); WAN_NETIF_STATS_INC_RX_DROPPED(&chan->common); /* ++chan->if_stats.rx_dropped; */ wan_skb_free(new_skb); return; } }else if (chan->common.usedby == TDM_VOICE){ DEBUG_EVENT("%s: TDM VOICE CRITICAL: IN BH!!!!\n",card->devname); WAN_NETIF_STATS_INC_RX_DROPPED(&chan->common); /* ++chan->if_stats.rx_dropped; */ wan_skb_free(new_skb); return; }else if (chan->common.usedby == STACK){ wan_skb_set_csum(new_skb,0); if (wanpipe_lip_rx(chan,new_skb) != 0){ WAN_NETIF_STATS_INC_RX_DROPPED(&chan->common); /* ++chan->if_stats.rx_dropped; */ wan_skb_free(new_skb); return; } }else if (chan->common.usedby == ANNEXG){ #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG if (chan->annexg_dev){ new_skb->protocol = htons(ETH_P_X25); new_skb->dev = chan->annexg_dev; wan_skb_reset_mac_header(new_skb); if (IS_FUNC_CALL(lapb_protocol,lapb_rx)){ lapb_protocol.lapb_rx(chan->annexg_dev,new_skb); card->wandev.stats.rx_packets++; card->wandev.stats.rx_bytes += len; }else{ wan_skb_free(new_skb); WAN_NETIF_STATS_INC_RX_DROPPED(&chan->common); } }else #endif { wan_skb_free(new_skb); WAN_NETIF_STATS_INC_RX_DROPPED(&chan->common); } }else{ protocol_recv(chan->card,chan,new_skb); } chan->opstats.Data_frames_Rx_count++; chan->opstats.Data_bytes_Rx_count+=len; WAN_NETIF_STATS_INC_RX_PACKETS(&chan->common); /* chan->if_stats.rx_packets++; */ WAN_NETIF_STATS_INC_RX_BYTES(&chan->common, len); /* chan->if_stats.rx_bytes+=len; */ return; } #if defined(__LINUX__) static void wp_bh (unsigned long data) #else static void wp_bh (void *data, int pending) #endif { private_area_t *chan = (private_area_t *)data; sdla_t *card=chan->card; netskb_t *new_skb,*skb; unsigned char pkt_error; wan_ticks_t timeout=SYSTEM_TICKS; private_area_t *top_chan; int len; #ifdef AFT_IRQ_STAT_DEBUG card->wandev.stats.collisions++; #endif if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ WAN_TASKLET_END((&chan->common.bh_task)); return; } if (card->u.aft.tdmv_dchan){ top_chan=wan_netif_priv(chan->common.dev); }else{ top_chan=chan; } DEBUG_TEST("%s: ------------ BEGIN --------------: %ld\n", __FUNCTION__,(u_int64_t)SYSTEM_TICKS); if (!wan_test_bit(0,&chan->up)){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: wp_bh() chan not up!\n", chan->if_name); } WAN_TASKLET_END((&chan->common.bh_task)); return; } while((skb=wan_skb_dequeue(&chan->wp_rx_complete_list)) != NULL){ #if 0 WAN_NETIF_STATS_INC_RX_ERRORS(&chan->common); //chan->if_stats.rx_errors++; #endif if (SYSTEM_TICKS-timeout > 1){ wan_skb_queue_head(&chan->wp_rx_complete_list,skb); break; } new_skb=NULL; pkt_error=0; /* The post function will take care * of the skb and new_skb buffer. * If new_skb buffer exists, driver * must pass it up the stack, or free it */ aft_rx_post_complete (chan->card, chan, skb, &new_skb, &pkt_error); if (new_skb){ len=wan_skb_len(new_skb); if (chan->hdlc_eng){ /* HDLC packets contain 2 byte crc and 1 byte * flag. If data is not greater than 3, then * we have a 0 length frame. Thus discard * (only if HDLC engine enabled) */ if (len <= 3){ WAN_NETIF_STATS_INC_RX_ERRORS(&chan->common); //++chan->if_stats.rx_errors; wan_skb_free(new_skb); continue; } wan_skb_trim(new_skb,wan_skb_len(new_skb)-3); len-=3; } wan_capture_trace_packet(chan->card, &top_chan->trace_info, new_skb,TRC_INCOMING_FRM); wp_bh_rx(chan, new_skb, pkt_error, len); } } while((skb=wan_skb_dequeue(&chan->wp_rx_stack_complete_list)) != NULL){ len=wan_skb_len(skb); wan_capture_trace_packet(chan->card, &top_chan->trace_info, skb,TRC_INCOMING_FRM); if (wanpipe_lip_rx(chan,skb) != 0){ WAN_NETIF_STATS_INC_RX_DROPPED(&chan->common); //++chan->if_stats.rx_dropped; wan_skb_free(skb); }else{ chan->opstats.Data_frames_Rx_count++; chan->opstats.Data_bytes_Rx_count+=len; WAN_NETIF_STATS_INC_RX_PACKETS(&chan->common); //chan->if_stats.rx_packets++; WAN_NETIF_STATS_INC_RX_BYTES(&chan->common,len); //chan->if_stats.rx_bytes+=len; } } while((skb=wan_skb_dequeue(&chan->wp_rx_bri_dchan_complete_list)) != NULL){ /* for BRI the rx data on D-chan is in 'wp_rx_bri_dchan_complete_list'. */ wan_capture_trace_packet(chan->card, &top_chan->trace_info, skb,TRC_INCOMING_FRM); wp_bh_rx(chan, skb, 0, wan_skb_len(skb)); } while((skb=wan_skb_dequeue(&chan->wp_tx_complete_list)) != NULL){ aft_tx_post_complete (chan->card,chan,skb); wan_skb_free(skb); } WAN_TASKLET_END((&chan->common.bh_task)); /* FIXME: If wanpipe goes down, do not schedule again */ if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ return; } #if 1 if ((len=wan_skb_queue_len(&chan->wp_rx_complete_list))){ WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); }else if ((len=wan_skb_queue_len(&chan->wp_tx_complete_list))){ WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); }else if ((len=wan_skb_queue_len(&chan->wp_rx_stack_complete_list))){ WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); }else if ((len=wan_skb_queue_len(&chan->wp_rx_bri_dchan_complete_list))){ WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); } #endif DEBUG_TEST("%s: ------------ END -----------------: %ld\n", __FUNCTION__,(u_int64_t)SYSTEM_TICKS); return; } /**SECTION************************************************** * * Interrupt Support Functions * **********************************************************/ static void __wp_aft_fifo_per_port_isr(sdla_t *card, u32 rx_status, u32 tx_status) { int num_of_logic_ch; u32 tmp_fifo_reg; private_area_t *chan; int i; tx_status&=card->u.aft.active_ch_map; rx_status&=card->u.aft.active_ch_map; num_of_logic_ch=card->u.aft.num_of_time_slots; if (!wan_test_bit(0,&card->u.aft.comm_enabled)){ if (tx_status){ card->wandev.stats.tx_aborted_errors++; } if (rx_status){ card->wandev.stats.rx_over_errors++; } return; } if (tx_status != 0){ for (i=0;iu.aft.logic_ch_map)){ chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; if (!chan){ DEBUG_EVENT("Warning: ignoring tx fifo intr: no dev!\n"); continue; } if (wan_test_bit(0,&chan->interface_down)){ continue; } #if 1 if (!chan->hdlc_eng && !wan_test_bit(0,&chan->idle_start)){ DEBUG_TEST("%s: Warning: ignoring tx fifo: dev idle start!\n", chan->if_name); continue; } #endif if (IS_BRI_CARD(card) && chan->dchan_time_slot >= 0){ continue; } DEBUG_TEST("%s:%s: Warning TX Fifo Error on LogicCh=%ld Slot=%d!\n", card->devname,chan->if_name,chan->logic_ch_num,i); #if 0 { u32 dma_descr,tmp_reg; dma_descr=(chan->logic_ch_num<<4) + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_descr, &tmp_reg); DEBUG_EVENT("%s:%s: Warning TX Fifo Error on LogicCh=%ld Slot=%d Reg=0x%X!\n", card->devname,chan->if_name,chan->logic_ch_num,i,tmp_reg); #if 1 aft_list_tx_descriptors(chan); aft_critical_shutdown(card); break; #endif } #endif aft_tx_fifo_under_recover(card,chan); WAN_NETIF_STATS_INC_TX_FIFO_ERRORS(&chan->common); //++chan->if_stats.tx_fifo_errors; card->wandev.stats.tx_aborted_errors++; __sdla_bus_read_4(card->hw,AFT_PORT_REG(card,AFT_TX_FIFO_INTR_PENDING_REG),&tmp_fifo_reg); } } } if (rx_status != 0){ for (i=0;iu.aft.logic_ch_map)){ chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; if (!chan){ continue; } if (wan_test_bit(0,&chan->interface_down)){ continue; } if (IS_BRI_CARD(card) && chan->dchan_time_slot >= 0){ continue; } #ifdef AFT_RX_FIFO_DEBUG { u32 dma_descr,tmp1_reg,tmp_reg,cur_dma_ptr; u32 dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,&tmp_reg); cur_dma_ptr=aft_dmachain_get_rx_dma_addr(tmp_reg); dma_descr=(chan->logic_ch_num<<4) + cur_dma_ptr*AFT_DMA_INDEX_OFFSET + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_descr, &tmp_reg); card->hw_iface.bus_read_4(card->hw,(dma_descr-4), &tmp1_reg); if (wan_test_bit(AFT_RXDMA_HI_GO_BIT,&tmp_reg)){ DEBUG_EVENT("%s: Rx Fifo Go Bit Set DMA=%d Addr=0x%X : HI=0x%08X LO=0x%08X OLO=0x%08X Cfg=0x%08X!\n", card->devname, cur_dma_ptr, dma_descr, tmp_reg,tmp1_reg, chan->rx_dma_chain_table[chan->rx_chain_indx].dma_addr, 0); } DEBUG_EVENT("%s:%s: Warning RX Fifo Error on Ch=%ld End=%d Cur=%d: Reg=0x%X Addr=0x%X!\n", card->devname,chan->if_name,chan->logic_ch_num, chan->rx_chain_indx,cur_dma_ptr,tmp_reg,dma_descr); } #if 0 aft_display_chain_history(chan); aft_list_descriptors(chan); #endif #endif WAN_NETIF_STATS_INC_RX_FIFO_ERRORS(&chan->common); //++chan->if_stats.rx_fifo_errors; WAN_NETIF_STATS_INC_RX_OVER_ERRORS(&chan->common); //++chan->if_stats.rx_over_errors; chan->errstats.Rx_overrun_err_count++; card->wandev.stats.rx_over_errors++; aft_rx_fifo_over_recover(card,chan); wan_set_bit(WP_FIFO_ERROR_BIT, &chan->pkt_error); __sdla_bus_read_4(card->hw,AFT_PORT_REG(card,AFT_RX_FIFO_INTR_PENDING_REG),&tmp_fifo_reg); #if 0 /* Debuging Code used to stop the line in * case of fifo errors */ aft_list_descriptors(chan); aft_critical_shutdown(card); #endif } } } return; } static void wp_aft_fifo_per_port_isr(sdla_t *card) { u32 rx_status=0, tx_status=0; u32 i; /* Clear HDLC pending registers */ __sdla_bus_read_4(card->hw, AFT_PORT_REG(card,AFT_TX_FIFO_INTR_PENDING_REG),&tx_status); __sdla_bus_read_4(card->hw, AFT_PORT_REG(card,AFT_RX_FIFO_INTR_PENDING_REG),&rx_status); if (IS_BRI_CARD(card)) { void **card_list=__sdla_get_ptr_isr_array(card->hw); sdla_t *tmp_card; for (i=0;iwandev.critical)) { __wp_aft_fifo_per_port_isr(tmp_card,rx_status,tx_status); } } } else { __wp_aft_fifo_per_port_isr(card,rx_status,tx_status); } return; } static void front_end_interrupt(sdla_t *card, unsigned long reg, int lock) { void **card_list; u32 max_number_of_ports, i; sdla_t *tmp_card; if (IS_BRI_CARD(card)) { max_number_of_ports = MAX_BRI_LINES; /* 24 */ } else { max_number_of_ports = 8; /* 24 */ } card_list=__sdla_get_ptr_isr_array(card->hw); DEBUG_TEST("%s(): card_list ptr: 0x%p\n", __FUNCTION__, card_list); for (i=0; iwandev.critical)) { continue; } DEBUG_TEST("%s(): card ptr: %s, tmp_card ptr: %s\n", __FUNCTION__, card->devname, tmp_card->devname); if (tmp_card->wandev.fe_iface.check_isr && tmp_card->wandev.fe_iface.check_isr(&tmp_card->fe)) { if (tmp_card->wandev.fe_iface.isr && tmp_card->wandev.fe_iface.isr(&tmp_card->fe)) { if (lock) { wan_smp_flag_t smp_flags; wan_spin_lock_irq(&tmp_card->wandev.lock,&smp_flags); handle_front_end_state(tmp_card); wan_spin_unlock_irq(&tmp_card->wandev.lock,&smp_flags); } else { handle_front_end_state(tmp_card); } } } } return; } /**SECTION*************************************************************** * * HARDWARE Interrupt Handlers * ***********************************************************************/ /*============================================================================ * wpfw_isr * * Main interrupt service routine. * Determin the interrupt received and handle it. * */ #if 0 static u32 aft_shared_irq=0; static u32 aft_master_dev=0xF; #endif #if 0 static int gdma_cnt=0; #endif #define EC_IRQ_TIMEOUT (HZ/32) static WAN_IRQ_RETVAL wp_aft_global_isr (sdla_t* card) { u32 reg_sec=0,reg=0; u32 a108_reg=0, a56k_reg=0, serial_reg=0; u32 fifo_port_intr=0; u32 dma_port_intr=0; u32 wdt_port_intr=0; u32 tdmv_port_intr=0; u32 status_port_intr=0; u32 fe_intr=0; u32 max_ports=IS_BRI_CARD(card)?MAX_BRI_LINES:8; WAN_IRQ_RETVAL_DECL(irq_ret); if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ DEBUG_TEST("%s: Card down, ignoring interrupt!!!!!!!\n", card->devname); WAN_IRQ_RETURN(irq_ret); } #ifdef AFT_IRQ_STAT_DEBUG card->wandev.stats.rx_errors++; #endif if (tdm_check > 0){ card->wandev.stats.rx_errors=tdm_check; } #ifdef AFT_IRQ_DEBUG card->wandev.stats.rx_packets++; if (SYSTEM_TICKS-card->u.aft.gtimeout >= HZ){ card->wandev.stats.tx_packets=card->wandev.stats.rx_packets; card->wandev.stats.rx_packets=0; card->u.aft.gtimeout=SYSTEM_TICKS; } #endif wan_set_bit(0,&card->in_isr); /* -----------------2/6/2003 9:02AM------------------ * Disable all chip Interrupts (offset 0x040) * -- "Transmit/Receive DMA Engine" interrupt disable * -- "FiFo/Line Abort Error" interrupt disable * --------------------------------------------------*/ __sdla_bus_read_4(card->hw,AFT_CHIP_CFG_REG, ®); reg_sec=reg; DEBUG_ISR("%s:ISR = 0x%X\n",card->devname,reg); if (wan_test_bit(AFT_CHIPCFG_FE_INTR_STAT_BIT,®)){ #ifdef AFT_IRQ_STAT_DEBUG card->wandev.stats.rx_dropped++; #endif if (wan_test_bit(AFT_CHIPCFG_FE_INTR_CFG_BIT,®)) { DEBUG_ISR("%s: Got Front End Interrupt 0x%08X\n", card->devname,reg); WAN_IRQ_RETVAL_SET(irq_ret, WAN_IRQ_HANDLED); #ifdef AFT_IRQ_STAT_DEBUG card->wandev.stats.tx_dropped++; #endif fe_intr=1; #if defined (__LINUX__) || defined(__FreeBSD__) wan_set_bit(AFT_FE_INTR,&card->u.aft.port_task_cmd); WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); __aft_fe_intr_ctrl(card,0); #else if (card->wandev.fe_iface.check_isr && card->wandev.fe_iface.check_isr(&card->fe)){ front_end_interrupt(card,reg,0); } #endif }/* if (wan_test_bit(AFT_CHIPCFG_FE_INTR_CFG_BIT,®)) */ }/* if (wan_test_bit(AFT_CHIPCFG_FE_INTR_STAT_BIT,®)) */ /* New Octasic implementarion May 16 2006 */ #if defined(CONFIG_WANPIPE_HWEC) if (card->wandev.ec_dev && wanpipe_ec_isr(card->wandev.ec_dev)){ if (!wan_test_bit(AFT_FE_EC_POLL,&card->u.aft.port_task_cmd)){ /* All work is done from ec_poll routine!!! */ wan_set_bit(AFT_FE_EC_POLL,&card->u.aft.port_task_cmd); WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); } } #endif if (card->u.aft.firm_id == AFT_DS_FE_CORE_ID || IS_BRI_CARD(card)) { __sdla_bus_read_4(card->hw,AFT_CHIP_STAT_REG, &a108_reg); fifo_port_intr = aft_chipcfg_a108_get_fifo_intr_stats(a108_reg); dma_port_intr = aft_chipcfg_a108_get_dma_intr_stats(a108_reg); wdt_port_intr = aft_chipcfg_a108_get_wdt_intr_stats(a108_reg); tdmv_port_intr = aft_chipcfg_a108_get_tdmv_intr_stats(a108_reg); } else if (IS_SERIAL_CARD(card)) { __sdla_bus_read_4(card->hw,AFT_CHIP_STAT_REG, &serial_reg); #ifdef AFT_SERIAL_DEBUG if (serial_reg) { DEBUG_EVENT("%s: SERIAL ISR = 0x%08X\n", card->devname,serial_reg); } #endif fifo_port_intr = aft_chipcfg_a108_get_fifo_intr_stats(serial_reg); dma_port_intr = aft_chipcfg_a108_get_dma_intr_stats(serial_reg); wdt_port_intr = aft_chipcfg_serial_get_wdt_intr_stats(serial_reg); status_port_intr = aft_chipcfg_serial_get_status_intr_stats(serial_reg, card->wandev.comm_port); } else if(IS_56K_CARD(card)) { __sdla_bus_read_4(card->hw,AFT_CHIP_STAT_REG, &a56k_reg); fifo_port_intr = wan_test_bit(AFT_CHIPCFG_A56K_FIFO_INTR_BIT,&a56k_reg); dma_port_intr = wan_test_bit(AFT_CHIPCFG_A56K_DMA_INTR_BIT,&a56k_reg); wdt_port_intr = wan_test_bit(AFT_CHIPCFG_A56K_WDT_INTR_BIT,&a56k_reg); } else { fifo_port_intr = aft_chipcfg_get_hdlc_intr_stats(reg); dma_port_intr = aft_chipcfg_get_dma_intr_stats(reg); wdt_port_intr = aft_chipcfg_get_wdt_intr_stats(reg); tdmv_port_intr = aft_chipcfg_get_tdmv_intr_stats(reg); if (wan_test_bit(AFT_TDM_GLOBAL_ISR,&card->u.aft.chip_cfg_status)) { tdmv_port_intr&=0x01; } } DEBUG_ISR("%s: ISR: TDM=0x%08X DMA=0x%08X FIFO=0x%08X STAT=0x%08X WDT=0x%08X\n", card->devname,tdmv_port_intr,dma_port_intr,fifo_port_intr, status_port_intr,wdt_port_intr); if (tdmv_port_intr || dma_port_intr || fifo_port_intr || status_port_intr || wdt_port_intr) { /* Pass Through */ } else { /* No more interrupts for us */ goto aft_global_isr_exit; } if (wan_test_bit(AFT_LCFG_FIFO_INTR_BIT,&card->u.aft.lcfg_reg) && wan_test_bit(card->wandev.comm_port,&fifo_port_intr)){ #ifdef AFT_IRQ_STAT_DEBUG card->wandev.stats.multicast++; #endif wp_aft_fifo_per_port_isr(card); WAN_IRQ_RETVAL_SET(irq_ret, WAN_IRQ_HANDLED); } #if 1 if (wan_test_bit(AFT_LCFG_DMA_INTR_BIT,&card->u.aft.lcfg_reg) && wan_test_bit(card->wandev.comm_port,&dma_port_intr)){ WAN_IRQ_RETVAL_SET(irq_ret, WAN_IRQ_HANDLED); wp_aft_dma_per_port_isr(card); /* Only enable fifo interrupts after a first * successful DMA interrupt */ #ifdef AFT_IRQ_STAT_DEBUG card->wandev.stats.rx_length_errors++; #endif #if 1 if (wan_test_bit(0,&card->u.aft.comm_enabled) && !wan_test_bit(AFT_LCFG_FIFO_INTR_BIT,&card->u.aft.lcfg_reg)){ aft_fifo_intr_ctrl(card, 1); } #else #warning "FIFO Interrupt Disabled" #endif } #else #warning "NCDEBUG DMA IGNORED" #endif if (wan_test_bit(AFT_TDM_GLOBAL_ISR,&card->u.aft.chip_cfg_status)) { if (tdmv_port_intr && !wan_test_bit(AFT_CHIPCFG_A108_A104_TDM_FIFO_SYNC_BIT,®)) { int ring_buf_enabled=wan_test_bit(AFT_CHIPCFG_A108_A104_TDM_DMA_RINGBUF_BIT,®); sdla_t *tmp_card; int ring_rsync=0; void **card_list; int i; WAN_IRQ_RETVAL_SET(irq_ret, WAN_IRQ_HANDLED); #ifdef AFT_IRQ_STAT_DEBUG card->wandev.stats.rx_crc_errors++; #endif if (ring_buf_enabled) { if (card->adptr_type == A104_ADPTR_4TE1 && card->u.aft.firm_id == AFT_PMC_FE_CORE_ID) { wan_set_bit(AFT_CHIPCFG_A104_TDM_ACK_BIT,®); } else { wan_set_bit(AFT_CHIPCFG_A108_TDM_GLOBAL_RX_INTR_ACK,®); wan_set_bit(AFT_CHIPCFG_A108_TDM_GLOBAL_TX_INTR_ACK,®); } __sdla_bus_write_4(card->hw,AFT_CHIP_CFG_REG,reg); if (card->hw_iface.fe_test_bit(card->hw,1)) { DEBUG_EVENT("%s: Global TDM Ring Resync\n",card->devname); ring_rsync=1; card->hw_iface.fe_clear_bit(card->hw,1); } } card_list=__sdla_get_ptr_isr_array(card->hw); //FIXME: Use value pre card type for (i=0;iu.aft.lcfg_reg)) { #ifdef AFT_IRQ_STAT_DEBUG tmp_card->wandev.stats.rx_crc_errors++; #endif if (ring_buf_enabled) { if (ring_rsync) { aft_tdm_ring_rsync(tmp_card); } else { tmp_card->u.aft.tdm_rx_dma_toggle++; if (tmp_card->u.aft.tdm_rx_dma_toggle >= AFT_TDMV_CIRC_BUF_LEN) { tmp_card->u.aft.tdm_rx_dma_toggle=0; } tmp_card->u.aft.tdm_tx_dma_toggle++; if (tmp_card->u.aft.tdm_tx_dma_toggle >= AFT_TDMV_CIRC_BUF_LEN) { tmp_card->u.aft.tdm_tx_dma_toggle=0; } } } #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) if (tmp_card->wan_tdmv.sc) { aft_voice_span_rx_tx(tmp_card, ring_buf_enabled); }else #endif { wp_aft_tdmv_per_port_isr(tmp_card); } } } if (!ring_buf_enabled) { if (card->adptr_type == A104_ADPTR_4TE1 && card->u.aft.firm_id == AFT_PMC_FE_CORE_ID) { wan_set_bit(AFT_CHIPCFG_A104_TDM_ACK_BIT,®); } else { wan_set_bit(AFT_CHIPCFG_A108_TDM_GLOBAL_RX_INTR_ACK,®); wan_set_bit(AFT_CHIPCFG_A108_TDM_GLOBAL_TX_INTR_ACK,®); } __sdla_bus_write_4(card->hw,AFT_CHIP_CFG_REG,reg); } } } else { if (wan_test_bit(AFT_LCFG_TDMV_INTR_BIT,&card->u.aft.lcfg_reg) && wan_test_bit(card->wandev.comm_port,&tdmv_port_intr)){ WAN_IRQ_RETVAL_SET(irq_ret, WAN_IRQ_HANDLED); #ifdef AFT_IRQ_STAT_DEBUG card->wandev.stats.rx_crc_errors++; #endif #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) if (card->wan_tdmv.sc && !card->wandev.rtp_len && card->wandev.config_id != WANCONFIG_AFT_ANALOG) { u32 dmareg; aft_voice_span_rx_tx(card, 0); card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_DMA_CTRL_REG),&dmareg); wan_set_bit(AFT_DMACTRL_TDMV_RX_TOGGLE,&dmareg); wan_set_bit(AFT_DMACTRL_TDMV_TX_TOGGLE,&dmareg); card->hw_iface.bus_write_4(card->hw, AFT_PORT_REG(card,AFT_DMA_CTRL_REG),dmareg); } else #endif { wp_aft_tdmv_per_port_isr(card); } } } if (status_port_intr) { wp_aft_serial_status_isr(card, status_port_intr); } if (wan_test_bit(card->wandev.comm_port,&wdt_port_intr)){ WAN_IRQ_RETVAL_SET(irq_ret, WAN_IRQ_HANDLED); wp_aft_wdt_per_port_isr(card,1); card->u.aft.wdt_tx_cnt=SYSTEM_TICKS; #ifdef AFT_IRQ_STAT_DEBUG card->wandev.stats.rx_fifo_errors++; #endif } #ifdef AFT_WDT_ENABLE else if (card->wandev.state == WAN_CONNECTED && SYSTEM_TICKS-card->u.aft.wdt_tx_cnt > (HZ>>2)){ wp_aft_wdt_per_port_isr(card,0); card->u.aft.wdt_tx_cnt=SYSTEM_TICKS; #ifdef AFT_IRQ_STAT_DEBUG card->wandev.stats.tx_aborted_errors++; #endif } #endif /* -----------------2/6/2003 10:36AM----------------- * Finish of the interupt handler * --------------------------------------------------*/ #if AFT_SECURITY_CHECK reg=reg_sec; if (wan_test_bit(AFT_CHIPCFG_SECURITY_STAT_BIT,®)){ WAN_IRQ_RETVAL_SET(irq_ret, WAN_IRQ_HANDLED); if (++card->u.aft.chip_security_cnt > AFT_MAX_CHIP_SECURITY_CNT){ DEBUG_EVENT("%s: Critical: AFT Chip Security Compromised: Disabling Driver!(%08X)\n", card->devname, reg); DEBUG_EVENT("%s: Please call Sangoma Tech Support (www.sangoma.com)!\n", card->devname); aft_critical_shutdown(card); } } else if (aft_hwdev[card->wandev.card_type].aft_check_ec_security(card)){ WAN_IRQ_RETVAL_SET(irq_ret, WAN_IRQ_HANDLED); if (++card->u.aft.chip_security_cnt > AFT_MAX_CHIP_SECURITY_CNT){ DEBUG_EVENT("%s: Critical: Echo Canceller Chip Security Compromised: Disabling Driver!\n", card->devname); DEBUG_EVENT("%s: Please call Sangoma Tech Support (www.sangoma.com)!\n", card->devname); card->u.aft.chip_security_cnt=0; aft_critical_shutdown(card); } } else if (card->u.aft.firm_id == AFT_DS_FE_CORE_ID && card->wandev.state == WAN_CONNECTED && SYSTEM_TICKS-card->u.aft.sec_chk_cnt > HZ) { u32 lcfg_reg; card->u.aft.sec_chk_cnt=SYSTEM_TICKS; __sdla_bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), &lcfg_reg); card->u.aft.lcfg_reg=lcfg_reg; if (wan_test_bit(AFT_LCFG_TX_FE_SYNC_STAT_BIT,&lcfg_reg) || wan_test_bit(AFT_LCFG_RX_FE_SYNC_STAT_BIT,&lcfg_reg)){ if (++card->u.aft.chip_security_cnt > AFT_MAX_CHIP_SECURITY_CNT){ DEBUG_EVENT("%s: Critical: A108 Lost Sync with Front End: Disabling Driver (0x%08X : A108S=0x%08X)!\n", card->devname, lcfg_reg,a108_reg); DEBUG_EVENT("%s: Please call Sangoma Tech Support (www.sangoma.com)!\n", card->devname); aft_critical_shutdown(card); } } else { card->u.aft.chip_security_cnt=0; } } else { card->u.aft.chip_security_cnt=0; } #endif DEBUG_TEST("---- ISR end.-------------------\n"); aft_global_isr_exit: wan_clear_bit(0,&card->in_isr); WAN_IRQ_RETURN(irq_ret); } static void wp_aft_serial_status_isr(sdla_t *card, u32 serial_intr_status) { u32 reg; __sdla_bus_read_4(card->hw, AFT_PORT_REG(card,AFT_SERIAL_LINE_CFG_REG), ®); if (card->u.aft.serial_status == reg) { /* No change in status */ return; } card->u.aft.serial_status=reg; if (card->wandev.ignore_front_end_status == WANOPT_YES) { return; } if (wan_test_bit(AFT_CHIPCFG_SERIAL_CTS_STATUS_INTR_BIT,&serial_intr_status)) { if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: CTS ISR Status 0x%02X\n", card->devname, wan_test_bit(AFT_SERIAL_LCFG_CTS_BIT,®)); } } if (wan_test_bit(AFT_CHIPCFG_SERIAL_DCD_STATUS_INTR_BIT,&serial_intr_status)) { if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: DCS ISR Status 0x%02X\n", card->devname, wan_test_bit(AFT_SERIAL_LCFG_DCD_BIT,®)); } } if (wan_test_bit(AFT_CHIPCFG_SERIAL_RTS_STATUS_INTR_BIT,&serial_intr_status)) { if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: RTS ISR Status 0x%02X\n", card->devname, wan_test_bit(AFT_SERIAL_LCFG_RTS_BIT,®)); } } } static void __wp_aft_per_per_port_isr(sdla_t *card, u32 dma_rx_reg, u32 dma_tx_reg) { private_area_t *chan; u32 dma_tx_voice=0; int i; dma_rx_reg&=card->u.aft.active_ch_map; if (!dma_rx_reg) { goto isr_skb_rx; } dma_rx_reg &= card->u.aft.logic_ch_map; dma_rx_reg &= ~(card->u.aft.tdm_logic_ch_map); for (i=0; iu.aft.num_of_time_slots;i++){ if (wan_test_bit(i,&dma_rx_reg)) { chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; if (!chan){ DEBUG_EVENT("%s: Error: No Dev for Rx logical ch=%d\n", card->devname,i); continue; } if (!wan_test_bit(0,&chan->up)){ continue; } if (chan->channelized_cfg && !chan->hdlc_eng){ wan_set_bit(i,&dma_tx_voice); continue; } if (IS_BRI_CARD(card) && chan->dchan_time_slot >= 0){ continue; } #if 0 WAN_NETIF_STATS_INC_RX_FRAME_ERRORS(&chan->common); //chan->if_stats.rx_frame_errors++; #endif DEBUG_TEST("%s: RX Interrupt pend. \n", card->devname); aft_dma_rx_complete(card,chan,0); #if 0 if (chan->cfg.tdmv_master_if && !chan->tdmv_irq_cfg){ aft_channel_rxintr_ctrl(card,chan,1); DEBUG_EVENT("%s: Master dev %s Synched to master irq\n", card->devname,chan->if_name); chan->tdmv_irq_cfg=1; } #endif } } isr_skb_rx: dma_tx_reg&=card->u.aft.active_ch_map; dma_tx_reg&=~dma_tx_voice; if (dma_tx_reg == 0){ goto isr_skb_tx; } dma_tx_reg &= card->u.aft.logic_ch_map; dma_tx_reg &= ~(card->u.aft.tdm_logic_ch_map); for (i=0; iu.aft.num_of_time_slots ;i++){ if (wan_test_bit(i,&dma_tx_reg)) { chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; if (!chan){ DEBUG_EVENT("%s: Error: No Dev for Tx logical ch=%d\n", card->devname,i); continue; } if (chan->channelized_cfg && !chan->hdlc_eng){ continue; } if (IS_BRI_CARD(card) && chan->dchan_time_slot >= 0){ continue; } DEBUG_ISR("---- TX Interrupt pend. --\n"); aft_dma_tx_complete(card,chan,0,0); } } isr_skb_tx: DEBUG_ISR("---- ISR SKB TX end.-------------------\n"); return; } static void wp_aft_dma_per_port_isr(sdla_t *card) { int i; u32 dma_tx_reg=0,dma_rx_reg=0; #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) private_area_t *chan; #endif /* -----------------2/6/2003 9:37AM------------------ * Checking for Interrupt source: * 1. Receive DMA Engine * 2. Transmit DMA Engine * 3. Error conditions. * --------------------------------------------------*/ /* Zaptel optimization. Dont waist time looking at channels, when we know that only a single DCHAN will use this code */ #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) if (card->wan_tdmv.sc) { __sdla_bus_read_4(card->hw,AFT_PORT_REG(card,AFT_RX_DMA_INTR_PENDING_REG),&dma_rx_reg); __sdla_bus_read_4(card->hw,AFT_PORT_REG(card,AFT_TX_DMA_INTR_PENDING_REG),&dma_tx_reg); if (card->u.aft.tdmv_dchan) { chan=(private_area_t*)card->u.aft.dev_to_ch_map[card->u.aft.tdmv_dchan-1]; if (chan && wan_test_bit(0,&chan->up)) { aft_dma_rx_complete(card,chan,0); aft_dma_tx_complete(card,chan,0,0); } } return; } #endif /* Receive DMA Engine */ __sdla_bus_read_4(card->hw,AFT_PORT_REG(card,AFT_RX_DMA_INTR_PENDING_REG),&dma_rx_reg); __sdla_bus_read_4(card->hw,AFT_PORT_REG(card,AFT_TX_DMA_INTR_PENDING_REG),&dma_tx_reg); DEBUG_TEST("Line: %d: dma_rx_reg: 0x%X\n", __LINE__, dma_rx_reg); if (IS_BRI_CARD(card)) { void **card_list=__sdla_get_ptr_isr_array(card->hw); sdla_t *tmp_card; for (i=0;iwandev.critical) && !wan_test_bit(AFT_LCFG_TDMV_INTR_BIT,&tmp_card->u.aft.lcfg_reg)) { __wp_aft_per_per_port_isr(tmp_card,dma_rx_reg,dma_tx_reg); } } } else { __wp_aft_per_per_port_isr(card,dma_rx_reg,dma_tx_reg); } } static void wp_aft_tdmv_per_port_isr(sdla_t *card) { int i; private_area_t *chan; #if 0 DEBUG_EVENT("%s: TDMV Interrupt LogicCh=%i\n", card->devname,card->u.aft.num_of_time_slots); #endif /* -----------------2/6/2003 9:37AM------------------ * Checking for Interrupt source: * 1. Receive DMA Engine * 2. Transmit DMA Engine * 3. Error conditions. * --------------------------------------------------*/ for (i=0; iu.aft.num_of_time_slots;i++){ if (!wan_test_bit(i,&card->u.aft.tdm_logic_ch_map)){ continue; } chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; if (!chan){ DEBUG_EVENT("%s: Error: No Dev for Rx logical ch=%d\n", card->devname,i); continue; } if (!wan_test_bit(0,&chan->up)){ continue; } if (IS_BRI_CARD(card) && chan->dchan_time_slot >= 0){ continue; } if (chan->channelized_cfg && !chan->hdlc_eng){ aft_dma_rx_tdmv(card,chan); } #if 0 WAN_NETIF_STATS_INC_RX_FRAME_ERRORS(&chan->common); //chan->if_stats.rx_frame_errors++; #endif DEBUG_ISR("%s: RX Interrupt pend. \n", card->devname); } } static void __wp_aft_wdt_per_port_isr (sdla_t *card, int wdt_intr, int *wdt_disable, int *timeout) { int i; /* If TDM interrupt does not start in time * we have to re-start it */ if (card->rsync_timeout){ if (!IS_BRI_CARD(card)) { if (SYSTEM_TICKS - card->rsync_timeout > 2*HZ) { card->rsync_timeout=0; if (card->fe.fe_status == FE_CONNECTED) { DEBUG_EVENT("%s: TDM IRQ Timeout \n", card->devname); wan_set_bit(AFT_FE_RESTART,&card->u.aft.port_task_cmd); WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); } } } else { if (SYSTEM_TICKS - card->rsync_timeout > 1*HZ) { int x; void **card_list=__sdla_get_ptr_isr_array(card->hw); sdla_t *first_card=NULL; card->rsync_timeout=0; for (x=0;xu.aft.lcfg_reg)) { break; } first_card=NULL; } if (first_card) { DEBUG_EVENT("%s: BRI TDM IRQ Timeout \n", first_card->devname); if (!wan_test_bit(AFT_FE_RESTART,&first_card->u.aft.port_task_cmd)) { wan_set_bit(AFT_FE_RESTART,&first_card->u.aft.port_task_cmd); WAN_TASKQ_SCHEDULE((&first_card->u.aft.port_task)); } } } } return; } for (i=0; iu.aft.num_of_time_slots;i++){ private_area_t *chan; if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ continue; } chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; if (!chan){ continue; } if (!wan_test_bit(0,&chan->up) || wan_test_bit(0,&chan->interface_down)){ continue; } if (IS_BRI_CARD(card) && chan->dchan_time_slot >= 0){ continue; } #if 0 if (wdt_intr){ WAN_NETIF_STATS_INC_TX_DROPPED(&chan->common); //++chan->if_stats.tx_dropped; }else{ WAN_NETIF_STATS_INC_TX_ERRORS(&chan->common); //++chan->if_stats.tx_errors; } #endif if (card->wandev.state == WAN_CONNECTED){ if (chan->single_dma_chain){ *wdt_disable=1; continue; } #if 0 WAN_NETIF_STATS_INC_TX_ERRORS(&chan->common); //++chan->if_stats.tx_errors; #endif aft_dma_tx_complete (card,chan,1,0); } #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) else{ if (chan->tdmv_zaptel_cfg && wan_test_bit(0,&chan->up) && chan->cfg.tdmv_master_if){ /* If the line becomes disconnected * keep calling TDMV zaptel in order to * provide timing */ if (wdt_intr && chan->cfg.tdmv_master_if){ int i, err; void **card_list=__sdla_get_ptr_isr_array(card->hw); sdla_t *tmp_card; for (i=0;i<8;i++) { tmp_card=card_list[i]; if (!tmp_card) { continue; } if (tmp_card != card) { /* Only run timing from a first configured single card */ DEBUG_TEST("%s: Disabling zaptel timing ! \n",card->devname); return; } else { break; } } #if 0 WAN_NETIF_STATS_INC_TX_DROPPED(&chan->common); //++chan->if_stats.tx_dropped; #endif #if 1 *timeout=1; WAN_TDMV_CALL(rx_tx_span, (card), err); #else #warning "NCDEBUG: rx_tx_span disabled poll" #endif return; } } } #endif } return; } static void wp_aft_wdt_per_port_isr(sdla_t *card, int wdt_intr) { int wdt_disable = 0; int timeout=AFT_WDTCTRL_TIMEOUT; aft_wdt_reset(card); if (IS_BRI_CARD(card)) { int x; void **card_list=__sdla_get_ptr_isr_array(card->hw); sdla_t *first_card; for (x=0;xwandev.critical)) { __wp_aft_wdt_per_port_isr(first_card,wdt_intr,&wdt_disable,&timeout); } } } else { __wp_aft_wdt_per_port_isr(card,wdt_intr,&wdt_disable,&timeout); } #ifdef AFT_WDT_ENABLE /* Since this fucntion can be called via interrupt or * via interrupt poll, only re-enable wdt interrupt * if the function was called from the wdt_intr * not from wdt poll */ if (!wdt_disable && wdt_intr){ aft_wdt_set(card,timeout); } #endif return; } /**SECTION*********************************************************** * * WANPIPE Debugging Interfaces * ********************************************************************/ /*============================================================================= * process_udp_mgmt_pkt * * Process all "wanpipemon" debugger commands. This function * performs all debugging tasks: * * Line Tracing * Line/Hardware Statistics * Protocol Statistics * * "wanpipemon" utility is a user-space program that * is used to debug the WANPIPE product. * */ #if 1 static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev, private_area_t* chan, int local_dev ) { unsigned short buffer_length; wan_udp_pkt_t *wan_udp_pkt; wan_trace_t *trace_info=NULL; wan_udp_pkt = (wan_udp_pkt_t *)chan->udp_pkt_data; if (wan_atomic_read(&chan->udp_pkt_len) == 0){ return -ENODEV; } trace_info=&chan->trace_info; wan_udp_pkt = (wan_udp_pkt_t *)chan->udp_pkt_data; { netskb_t *skb; wan_udp_pkt->wan_udp_opp_flag = 0; switch(wan_udp_pkt->wan_udp_command) { case READ_CONFIGURATION: wan_udp_pkt->wan_udp_return_code = 0; wan_udp_pkt->wan_udp_data_len=0; break; case READ_CODE_VERSION: wan_udp_pkt->wan_udp_return_code = 0; wan_udp_pkt->wan_udp_data[0]=card->u.aft.firm_ver; wan_udp_pkt->wan_udp_data_len=1; break; case AFT_LINK_STATUS: wan_udp_pkt->wan_udp_return_code = 0; if (card->wandev.state == WAN_CONNECTED){ wan_udp_pkt->wan_udp_data[0]=1; }else{ wan_udp_pkt->wan_udp_data[0]=0; } wan_udp_pkt->wan_udp_data_len=1; break; case AFT_MODEM_STATUS: wan_udp_pkt->wan_udp_return_code = 0; wan_udp_pkt->wan_udp_data[0]=0; if (IS_SERIAL_CARD(card)) { if (wan_test_bit(AFT_SERIAL_LCFG_DCD_BIT,&card->u.aft.serial_status)) { wan_udp_pkt->wan_udp_data[0]|=0x08; } if (wan_test_bit(AFT_SERIAL_LCFG_CTS_BIT,&card->u.aft.serial_status)) { wan_udp_pkt->wan_udp_data[0]|=0x20; } } else { if (card->wandev.state == WAN_CONNECTED){ wan_udp_pkt->wan_udp_data[0]=0x28; }else{ wan_udp_pkt->wan_udp_data[0]=0; } } wan_udp_pkt->wan_udp_data_len=1; break; case DIGITAL_LOOPTEST: wan_udp_pkt->wan_udp_return_code = digital_loop_test(card,wan_udp_pkt); break; case READ_OPERATIONAL_STATS: wan_udp_pkt->wan_udp_return_code = 0; memcpy(wan_udp_pkt->wan_udp_data,&chan->opstats,sizeof(aft_op_stats_t)); wan_udp_pkt->wan_udp_data_len=sizeof(aft_op_stats_t); break; case FLUSH_OPERATIONAL_STATS: wan_udp_pkt->wan_udp_return_code = 0; memset(&chan->opstats,0,sizeof(aft_op_stats_t)); wan_udp_pkt->wan_udp_data_len=0; break; case READ_COMMS_ERROR_STATS: wan_udp_pkt->wan_udp_return_code = 0; memcpy(wan_udp_pkt->wan_udp_data,&chan->errstats,sizeof(aft_comm_err_stats_t)); wan_udp_pkt->wan_udp_data_len=sizeof(aft_comm_err_stats_t); break; case FLUSH_COMMS_ERROR_STATS: wan_udp_pkt->wan_udp_return_code = 0; memset(&chan->errstats,0,sizeof(aft_comm_err_stats_t)); wan_udp_pkt->wan_udp_data_len=0; break; case ENABLE_TRACING: wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; wan_udp_pkt->wan_udp_data_len = 0; if (!wan_test_bit(0,&trace_info->tracing_enabled)){ trace_info->trace_timeout = SYSTEM_TICKS; wan_trace_purge(trace_info); if (wan_udp_pkt->wan_udp_data[0] == 0){ wan_clear_bit(1,&trace_info->tracing_enabled); DEBUG_UDP("%s: ADSL L3 trace enabled!\n", card->devname); }else if (wan_udp_pkt->wan_udp_data[0] == 1){ wan_clear_bit(2,&trace_info->tracing_enabled); wan_set_bit(1,&trace_info->tracing_enabled); DEBUG_UDP("%s: ADSL L2 trace enabled!\n", card->devname); }else{ wan_clear_bit(1,&trace_info->tracing_enabled); wan_set_bit(2,&trace_info->tracing_enabled); DEBUG_UDP("%s: ADSL L1 trace enabled!\n", card->devname); } wan_set_bit (0,&trace_info->tracing_enabled); }else{ DEBUG_EVENT("%s: Error: ATM trace running!\n", card->devname); wan_udp_pkt->wan_udp_return_code = 2; } break; case DISABLE_TRACING: wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; if(wan_test_bit(0,&trace_info->tracing_enabled)) { wan_clear_bit(0,&trace_info->tracing_enabled); wan_clear_bit(1,&trace_info->tracing_enabled); wan_clear_bit(2,&trace_info->tracing_enabled); wan_trace_purge(trace_info); DEBUG_UDP("%s: Disabling AFT trace\n", card->devname); }else{ /* set return code to line trace already disabled */ wan_udp_pkt->wan_udp_return_code = 1; } break; case GET_TRACE_INFO: if(wan_test_bit(0,&trace_info->tracing_enabled)){ trace_info->trace_timeout = SYSTEM_TICKS; }else{ DEBUG_EVENT("%s: Error ATM trace not enabled\n", card->devname); /* set return code */ wan_udp_pkt->wan_udp_return_code = 1; break; } buffer_length = 0; wan_udp_pkt->wan_udp_atm_num_frames = 0; wan_udp_pkt->wan_udp_atm_ismoredata = 0; #if defined(__FreeBSD__) || defined(__OpenBSD__) while (wan_skb_queue_len(&trace_info->trace_queue)){ WAN_IFQ_POLL(&trace_info->trace_queue, skb); if (skb == NULL){ DEBUG_EVENT("%s: No more trace packets in trace queue!\n", card->devname); break; } if ((WAN_MAX_DATA_SIZE - buffer_length) < skb->m_pkthdr.len){ /* indicate there are more frames on board & exit */ wan_udp_pkt->wan_udp_atm_ismoredata = 0x01; break; } m_copydata(skb, 0, skb->m_pkthdr.len, &wan_udp_pkt->wan_udp_data[buffer_length]); buffer_length += skb->m_pkthdr.len; WAN_IFQ_DEQUEUE(&trace_info->trace_queue, skb); if (skb){ wan_skb_free(skb); } wan_udp_pkt->wan_udp_atm_num_frames++; } #elif defined(__LINUX__) while ((skb=skb_dequeue(&trace_info->trace_queue)) != NULL){ if((MAX_TRACE_BUFFER - buffer_length) < wan_skb_len(skb)){ /* indicate there are more frames on board & exit */ wan_udp_pkt->wan_udp_atm_ismoredata = 0x01; if (buffer_length != 0){ wan_skb_queue_head(&trace_info->trace_queue, skb); }else{ /* If rx buffer length is greater than the * whole udp buffer copy only the trace * header and drop the trace packet */ memcpy(&wan_udp_pkt->wan_udp_atm_data[buffer_length], wan_skb_data(skb), sizeof(wan_trace_pkt_t)); buffer_length = sizeof(wan_trace_pkt_t); wan_udp_pkt->wan_udp_atm_num_frames++; wan_skb_free(skb); } break; } memcpy(&wan_udp_pkt->wan_udp_atm_data[buffer_length], wan_skb_data(skb), wan_skb_len(skb)); buffer_length += wan_skb_len(skb); wan_skb_free(skb); wan_udp_pkt->wan_udp_atm_num_frames++; } #endif /* set the data length and return code */ wan_udp_pkt->wan_udp_data_len = buffer_length; wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; break; case ROUTER_UP_TIME: wan_getcurrenttime(&chan->router_up_time, NULL); chan->router_up_time -= chan->router_start_time; *(unsigned long *)&wan_udp_pkt->wan_udp_data = chan->router_up_time; wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long); wan_udp_pkt->wan_udp_return_code = 0; break; case WAN_GET_MEDIA_TYPE: if (card->wandev.fe_iface.get_fe_media){ wan_udp_pkt->wan_udp_data[0] = card->wandev.fe_iface.get_fe_media(&card->fe); wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char); }else{ wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; } break; #if 0 case WAN_FE_GET_STAT: case WAN_FE_SET_LB_MODE: case WAN_FE_FLUSH_PMON: case WAN_FE_GET_CFG: case WAN_FE_SET_DEBUG_MODE: case WAN_FE_TX_MODE: if (IS_TE1_CARD(card)){ wan_smp_flag_t smp_flags; card->hw_iface.hw_lock(card->hw,&smp_flags); card->wandev.fe_iface.process_udp( &card->fe, &wan_udp_pkt->wan_udp_cmd, &wan_udp_pkt->wan_udp_data[0]); card->hw_iface.hw_unlock(card->hw,&smp_flags); }else{ wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; } break; #endif case WAN_GET_PROTOCOL: wan_udp_pkt->wan_udp_aft_num_frames = card->wandev.config_id; wan_udp_pkt->wan_udp_return_code = CMD_OK; wan_udp_pkt->wan_udp_data_len = 1; break; case WAN_GET_PLATFORM: wan_udp_pkt->wan_udp_data[0] = WAN_PLATFORM_ID; wan_udp_pkt->wan_udp_return_code = CMD_OK; wan_udp_pkt->wan_udp_data_len = 1; break; case WAN_GET_MASTER_DEV_NAME: wan_udp_pkt->wan_udp_data_len = 0; wan_udp_pkt->wan_udp_return_code = 0xCD; break; case AFT_HWEC_STATUS: *(unsigned long *)&wan_udp_pkt->wan_udp_data[0] = card->wandev.fe_ec_map; wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long); wan_udp_pkt->wan_udp_return_code = 0; break; default: if ((wan_udp_pkt->wan_udp_command & 0xF0) == WAN_FE_UDP_CMD_START){ /* FE udp calls */ wan_smp_flag_t smp_flags,smp_flags1; card->hw_iface.hw_lock(card->hw,&smp_flags); wan_spin_lock_irq(&card->wandev.lock,&smp_flags1); card->wandev.fe_iface.process_udp( &card->fe, &wan_udp_pkt->wan_udp_cmd, &wan_udp_pkt->wan_udp_data[0]); wan_spin_unlock_irq(&card->wandev.lock,&smp_flags1); card->hw_iface.hw_unlock(card->hw,&smp_flags); break; } wan_udp_pkt->wan_udp_data_len = 0; wan_udp_pkt->wan_udp_return_code = 0xCD; if (WAN_NET_RATELIMIT()){ DEBUG_EVENT( "%s: Warning, Illegal UDP command attempted from network: %x\n", card->devname,wan_udp_pkt->wan_udp_command); } break; } /* end of switch */ } /* end of else */ /* Fill UDP TTL */ wan_udp_pkt->wan_ip_ttl= card->wandev.ttl; wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; return 1; } #endif /**SECTION************************************************************* * * TASK Functions and Triggers * **********************************************************************/ /*============================================================================ * port_set_state * * Set PORT state. * */ static void port_set_state (sdla_t *card, int state) { struct wan_dev_le *devle; netdevice_t *dev; if (card->wandev.state != state) { #if 0 switch (state) { case WAN_CONNECTED: DEBUG_EVENT( "%s: Front End Link connected!\n", card->devname); break; case WAN_CONNECTING: DEBUG_EVENT( "%s: Front End Link connecting...\n", card->devname); break; case WAN_DISCONNECTED: DEBUG_EVENT( "%s: Front End Link disconnected!\n", card->devname); break; } #endif card->wandev.state = state; WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ dev = WAN_DEVLE2DEV(devle); if (!dev) continue; set_chan_state(card, dev, state); } } } /*============================================================ * callback_front_end_state * * Called by front end code to indicate that state has * changed. We will call the poll task to update the state. */ static void callback_front_end_state(void *card_id) { sdla_t *card = (sdla_t*)card_id; if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ return; } /* Call the poll task to update the state */ wan_set_bit(AFT_FE_POLL,&card->u.aft.port_task_cmd); WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); return; } /*============================================================ * handle_front_end_state * * Front end state indicates the physical medium that * the Z80 backend connects to. * * S514-1/2/3: V32/RS232/FT1 Front End * Front end state is determined via * Modem/Status. * S514-4/5/7/8: 56K/T1/E1 Front End * Front end state is determined via * link status interrupt received * from the front end hardware. * * If the front end state handler is enabed by the * user. The interface state will follow the * front end state. I.E. If the front end goes down * the protocol and interface will be declared down. * * If the front end state is UP, then the interface * and protocol will be up ONLY if the protocol is * also UP. * * Therefore, we must have three state variables * 1. Front End State (card->wandev.front_end_status) * 2. Protocol State (card->wandev.state) * 3. Interface State (dev->flags & IFF_UP) * */ static void handle_front_end_state(void *card_id) { sdla_t *card = (sdla_t*)card_id; if (!wan_test_bit(AFT_CHIP_CONFIGURED,&card->u.aft.chip_cfg_status) && card->fe.fe_status == FE_CONNECTED) { DEBUG_TEST("%s: Skipping Front Front End State = %x\n", card->devname,card->fe.fe_status); wan_set_bit(AFT_FRONT_END_UP,&card->u.aft.chip_cfg_status); return; } if (card->fe.fe_status == FE_CONNECTED || card->wandev.ignore_front_end_status == WANOPT_YES){ if (card->wandev.state != WAN_CONNECTED){ #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) if (card->wan_tdmv.sc){ int err; WAN_TDMV_CALL(state, (card, WAN_CONNECTED), err); } #endif /* WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); */ if (card->tdmv_conf.span_no && !wan_test_bit(0,&card->u.aft.tdmv_master_if_up)){ DEBUG_EVENT("%s: Skipping AFT Communication wait for MasterIF\n", card->devname); return; } if (!IS_BRI_CARD(card) || !wan_test_bit(0,&card->u.aft.comm_enabled)) { enable_data_error_intr(card); } port_set_state(card,WAN_CONNECTED); wan_set_bit(AFT_FE_LED,&card->u.aft.port_task_cmd); aft_handle_clock_master(card); } }else{ if (card->wandev.state == WAN_CONNECTED){ port_set_state(card,WAN_DISCONNECTED); if (!IS_BRI_CARD(card)) { /* Never disable interrupts for BRI since all cards are on same timslot map */ disable_data_error_intr(card,LINK_DOWN); } wan_set_bit(AFT_FE_LED,&card->u.aft.port_task_cmd); /* We are already in the poll task here so * no need to schedule. because next check in the * poll routine would be the AFT_FE_LED */ /* WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); */ #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) if (card->wan_tdmv.sc){ int err; WAN_TDMV_CALL(state, (card, WAN_DISCONNECTED), err); } #endif aft_handle_clock_master(card); } } } unsigned char aft_read_cpld(sdla_t *card, unsigned short cpld_off) { return aft_hwdev[card->wandev.card_type].aft_read_cpld(card,cpld_off); } int aft_write_cpld(void *pcard, unsigned short off,unsigned char data) { sdla_t *card = (sdla_t *)pcard; return aft_hwdev[card->wandev.card_type].aft_write_cpld(card,off,data); } static unsigned char aft_write_ec (void *pcard, unsigned short off, unsigned char value) { /*sdla_t *card = (sdla_t*)pcard;*/ DEBUG_TEST("%s: Write Octasic Offset %04X Value %02X!\n", card->devname, off, value); return 0; } /*============================================================================ * Read from Octasic board */ static unsigned char aft_read_ec (void *pcard, unsigned short off) { /*sdla_t *card = (sdla_t*)pcard;*/ unsigned char value = 0x00; DEBUG_TEST("%s: Read Octasic offset %04X Value %02X (temp)!\n", card->devname, off, value); return value; } static int aft_read(sdla_t *card, wan_cmd_api_t *api_cmd) { WAN_ASSERT(card == NULL); WAN_ASSERT(api_cmd == NULL); if(api_cmd->len == 1){ if (api_cmd->offset <= 0x3C){ card->hw_iface.pci_read_config_byte( card->hw, api_cmd->offset, (u8*)&api_cmd->data[0]); }else{ card->hw_iface.bus_read_1( card->hw, api_cmd->offset, (u8*)&api_cmd->data[0]); } }else if (api_cmd->len == 2){ if (api_cmd->offset <= 0x3C){ card->hw_iface.pci_read_config_word( card->hw, api_cmd->offset, (u16*)&api_cmd->data[0]); }else{ card->hw_iface.bus_read_2( card->hw, api_cmd->offset, (u16*)&api_cmd->data[0]); } }else if (api_cmd->len == 4){ if (api_cmd->offset <= 0x3C){ card->hw_iface.pci_read_config_dword(card->hw, api_cmd->offset, (u32*)&api_cmd->data[0]); }else{ WAN_ASSERT(card->hw_iface.bus_read_4 == NULL); card->hw_iface.bus_read_4( card->hw, api_cmd->offset, (u32*)&api_cmd->data[0]); } }else{ card->hw_iface.peek(card->hw, api_cmd->offset, &api_cmd->data[0], api_cmd->len); } DEBUG_REG("%s: Reading Bar%d Offset=0x%X Data=%08X Len=%d\n", card->devname, api_cmd->bar, api_cmd->offset, *(u32*)&api_cmd->data[0], api_cmd->len); return 0; } static int aft_fe_read(sdla_t *card, wan_cmd_api_t *api_cmd) { wan_smp_flag_t smp_flags; card->hw_iface.hw_lock(card->hw,&smp_flags); api_cmd->data[0] = (u8)card->fe.read_fe_reg(card, (int)api_cmd->offset); card->hw_iface.hw_unlock(card->hw,&smp_flags); #ifdef DEB_XILINX DEBUG_EVENT("%s: Reading Bar%d Offset=0x%X Len=%d Val=%02X\n", card->devname,api_cmd->bar,api_cmd->offset,api_cmd->len, api_cmd->data[0]); #endif return 0; } static int aft_write(sdla_t *card, wan_cmd_api_t *api_cmd) { if (api_cmd->len == 1){ card->hw_iface.bus_write_1( card->hw, api_cmd->offset, *(u8*)&api_cmd->data[0]); DEBUG_REG("%s: Write Offset=0x%08X Data=0x%02X\n", card->devname,api_cmd->offset, *(u8*)&api_cmd->data[0]); }else if (api_cmd->len == 2){ card->hw_iface.bus_write_2( card->hw, api_cmd->offset, *(u16*)&api_cmd->data[0]); DEBUG_REG("%s: Write Offset=0x%08X Data=0x%04X\n", card->devname,api_cmd->offset, *(unsigned short*)&api_cmd->data[0]); }else if (api_cmd->len == 4){ card->hw_iface.bus_write_4( card->hw, api_cmd->offset, *(unsigned int*)&api_cmd->data[0]); DEBUG_REG("ADEBUG: %s: Write Offset=0x%08X Data=0x%08X\n", card->devname,api_cmd->offset, *(u32*)&api_cmd->data[0]); }else{ card->hw_iface.poke( card->hw, api_cmd->offset, (u8*)&api_cmd->data[0], api_cmd->len); #if 0 memcpy_toio((unsigned char*)vector, (unsigned char*)&api_cmd->data[0], api_cmd->len); #endif } return 0; } static int aft_fe_write(sdla_t *card, wan_cmd_api_t *api_cmd) { wan_smp_flag_t smp_flags; #ifdef DEB_XILINX DEBUG_EVENT("%s: Writting Bar%d Offset=0x%X Len=%d Val=%02X\n", card->devname, api_cmd->bar, api_cmd->offset, api_cmd->len, api_cmd->data[0]); #endif card->hw_iface.hw_lock(card->hw,&smp_flags); card->fe.write_fe_reg (card, (int)api_cmd->offset, (int)api_cmd->data[0]); card->hw_iface.hw_unlock(card->hw,&smp_flags); return 0; } static int aft_write_bios(sdla_t *card, wan_cmd_api_t *api_cmd) { #ifdef DEB_XILINX DEBUG_EVENT("Setting PCI 0xX=0x%08lX 0x3C=0x%08X\n", (card->wandev.S514_cpu_no[0] == SDLA_CPU_A) ? 0x10 : 0x14, card->u.aft.bar,card->wandev.irq); #endif card->hw_iface.pci_write_config_dword(card->hw, (card->wandev.S514_cpu_no[0] == SDLA_CPU_A) ? 0x10 : 0x14, card->u.aft.bar); card->hw_iface.pci_write_config_dword(card->hw, 0x3C, card->wandev.irq); card->hw_iface.pci_write_config_dword(card->hw, 0x0C, 0x0000ff00); return 0; } #if 0 extern int OctDrvIoctl(sdla_t*, int cmd, void*); #endif static int aft_hwec(sdla_t *card, wan_cmd_api_t *api_cmd) { #if 0 if (api_cmd->offset){ /* Use direct read/write to/from octasic chip */ if (api_cmd->len){ /* Write */ aft_write_ec (card, api_cmd->offset, api_cmd->data[0]); }else{ /* Read */ api_cmd->data[0] = aft_read_ec (card, api_cmd->offset); api_cmd->len = 1; } }else #endif { #if 0 OctDrvIoctl(card, api_cmd->cmd, api_cmd->data); #endif } return 0; } static int aft_devel_ioctl(sdla_t *card, struct ifreq *ifr) { wan_cmd_api_t api_cmd; int err = -EINVAL; if (!ifr || !ifr->ifr_data){ DEBUG_EVENT("%s: Error: No ifr or ifr_data\n",__FUNCTION__); return -EFAULT; } if (WAN_COPY_FROM_USER(&api_cmd,ifr->ifr_data,sizeof(wan_cmd_api_t))){ return -EFAULT; } switch(api_cmd.cmd){ case SIOC_WAN_READ_REG: err=aft_read(card, &api_cmd); break; case SIOC_WAN_WRITE_REG: err=aft_write(card, &api_cmd); break; case SIOC_WAN_FE_READ_REG: err=aft_fe_read(card, &api_cmd); break; case SIOC_WAN_FE_WRITE_REG: err=aft_fe_write(card, &api_cmd); break; case SIOC_WAN_SET_PCI_BIOS: err=aft_write_bios(card, &api_cmd); break; case SIOC_WAN_EC_REG: err = aft_hwec(card, &api_cmd); break; } if (WAN_COPY_TO_USER(ifr->ifr_data,&api_cmd,sizeof(wan_cmd_api_t))){ return -EFAULT; } return err; } /*========================================= * enable_data_error_intr * * Description: * * Run only after the front end comes * up from down state. * * Clean the DMA Tx/Rx pending interrupts. * (Ignore since we will reconfigure * all dma descriptors. DMA controler * was already disabled on link down) * * For all channels clean Tx/Rx Fifo * * Enable DMA controler * (This starts the fifo cleaning * process) * * For all channels reprogram Tx/Rx DMA * descriptors. * * Clean the Tx/Rx Error pending interrupts. * (Since dma fifo's are now empty) * * Enable global DMA and Error interrutps. * */ static void enable_data_error_intr(sdla_t *card) { u32 reg; int i,err; int card_use_cnt; card->hw_iface.getcfg(card->hw, SDLA_HWCPU_USEDCNT, &card_use_cnt); DEBUG_TEST("%s: %s() Card Port =%i Use Cnt = %i \n", card->devname,__FUNCTION__,card->wandev.comm_port,card_use_cnt); card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); if (wan_test_bit(AFT_LCFG_FE_IFACE_RESET_BIT,®)){ DEBUG_EVENT("%s: Warning: Skipping data enable wait for cfg!\n", card->devname); return; } #if 0 aft_list_dma_chain_regs(card); #endif if (card->tdmv_conf.span_no && !wan_test_bit(0,&card->u.aft.tdmv_master_if_up)){ DEBUG_EVENT("%s: Critical error: Enable Card while Master If Not up!\n", card->devname); } if (wan_test_bit(0,&card->u.aft.comm_enabled)){ disable_data_error_intr(card,LINK_DOWN); } aft_wdt_reset(card); if (!IS_BRI_CARD(card) || (IS_BRI_CARD(card) && card_use_cnt == 1)) { /* Clean Tx/Rx DMA interrupts */ card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_TX_DMA_INTR_PENDING_REG), ®); card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_RX_DMA_INTR_PENDING_REG), ®); } err=aft_hwdev[card->wandev.card_type].aft_test_sync(card,0); if (err){ card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); DEBUG_EVENT("%s: Error: Front End Interface out of sync! (0x%X)\n", card->devname,reg); /*FIXME: How to recover from here, should never happen */ } if (card->tdmv_conf.span_no){ card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); wan_set_bit(AFT_LCFG_TDMV_INTR_BIT,®); card->hw_iface.bus_write_4(card->hw, AFT_PORT_REG(card,AFT_LINE_CFG_REG), reg); } for (i=0; iu.aft.num_of_time_slots;i++){ private_area_t *chan; if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ continue; } chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; if (!chan){ continue; } if (!wan_test_bit(0,&chan->up)){ continue; } if (IS_BRI_CARD(card) && chan->dchan_time_slot >= 0){ continue; } DEBUG_TEST("%s: 1) Free Used DMA CHAINS %s\n", card->devname,chan->if_name); aft_free_rx_complete_list(chan); aft_free_rx_descriptors(chan); DEBUG_TEST("%s: 1) Free UNUSED DMA CHAINS %s\n", card->devname,chan->if_name); wan_clear_bit(TX_INTR_PENDING,&chan->dma_chain_status); if (chan->channelized_cfg && !chan->hdlc_eng){ aft_tx_dma_voice_handler((unsigned long)chan,0,1); }else{ aft_tx_dma_chain_handler((unsigned long)chan,0,1); } aft_free_tx_descriptors(chan); DEBUG_TEST("%s: 2) Init interface fifo no wait %s\n", card->devname,chan->if_name); aft_tslot_sync_ctrl(card,chan,0); aft_init_rx_dev_fifo(card, chan, WP_NO_WAIT); aft_init_tx_dev_fifo(card, chan, WP_NO_WAIT); } /* Enable Global DMA controler, in order to start the * fifo cleaning */ card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),®); wan_set_bit(AFT_DMACTRL_GLOBAL_INTR_BIT,®); card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); /* For all channels clean Tx/Rx fifos */ for (i=0; iu.aft.num_of_time_slots;i++){ private_area_t *chan; if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ continue; } chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; if (!chan){ continue; } if (!wan_test_bit(0,&chan->up)){ continue; } if (IS_BRI_CARD(card) && chan->dchan_time_slot >= 0){ continue; } DEBUG_TEST("%s: 3) Init interface fifo %s Logic Ch=%li\n", card->devname,chan->if_name,chan->logic_ch_num); aft_init_rx_dev_fifo(card, chan, WP_WAIT); aft_init_tx_dev_fifo(card, chan, WP_WAIT); DEBUG_TEST("%s: 4) Clearing Fifo and idle_flag %s Logic Ch=%li\n", card->devname,chan->if_name,chan->logic_ch_num); wan_clear_bit(0,&chan->idle_start); } #if 0 aft_list_dma_chain_regs(card); #endif /* For all channels, reprogram Tx/Rx DMA descriptors. * For Tx also make sure that the BUSY flag is clear * and previoulsy Tx packet is deallocated */ for (i=0; iu.aft.num_of_time_slots;i++){ private_area_t *chan; if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ continue; } chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; if (!chan){ continue; } if (!wan_test_bit(0,&chan->up)){ continue; } if (IS_BRI_CARD(card) && chan->dchan_time_slot >= 0){ continue; } DEBUG_TEST("%s: 4) Init interface %s\n", card->devname,chan->if_name); chan->dma_index=0; memset(chan->dma_history,0,sizeof(chan->dma_history)); aft_reset_rx_chain_cnt(chan); #if 0 aft_list_descriptors(chan); #endif aft_dma_rx(card,chan); aft_tslot_sync_ctrl(card,chan,1); DEBUG_TEST("%s: DMA RX SETUP %s\n", card->devname,chan->if_name); #if 0 aft_list_descriptors(chan); #endif } /* Clean Tx/Rx Error interrupts, since fifos are now * empty, and Tx fifo may generate an underrun which * we want to ignore :) */ card->u.aft.tdm_rx_dma_toggle=0; card->u.aft.tdm_tx_dma_toggle=0; for (i=0; iu.aft.num_of_time_slots;i++){ private_area_t *chan; if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ continue; } chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; if (!chan){ continue; } memset(&chan->swring,0,sizeof(chan->swring)); if (!wan_test_bit(0,&chan->up)){ continue; } if (IS_BRI_CARD(card) && chan->dchan_time_slot >= 0){ continue; } if (!chan->hdlc_eng){ aft_reset_tx_chain_cnt(chan); aft_dma_tx(card,chan); } if (chan->cfg.ss7_enable){ aft_clear_ss7_force_rx(card,chan); } if (chan->tdmv_zaptel_cfg && !chan->hdlc_eng){ aft_dma_rx_tdmv(card,chan); } } card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_RX_FIFO_INTR_PENDING_REG), ®); card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_TX_FIFO_INTR_PENDING_REG), ®); /* Enable Global DMA and Error Interrupts */ card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); wan_set_bit(AFT_LCFG_DMA_INTR_BIT,®); wan_clear_bit(AFT_LCFG_FIFO_INTR_BIT,®); if (card->tdmv_conf.span_no){ wan_set_bit(AFT_LCFG_TDMV_INTR_BIT,®); } card->hw_iface.bus_write_4(card->hw, AFT_PORT_REG(card,AFT_LINE_CFG_REG), reg); card->u.aft.lcfg_reg=reg; wan_set_bit(0,&card->u.aft.comm_enabled); DEBUG_EVENT("%s: AFT communications enabled!\n", card->devname); /* Enable Channelized Driver if configured */ if (card->tdmv_conf.span_no) { card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_RX_FIFO_INTR_PENDING_REG), ®); card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_TX_FIFO_INTR_PENDING_REG), ®); #if 1 if (wan_test_bit(AFT_TDM_GLOBAL_ISR,&card->u.aft.chip_cfg_status)) { card->hw_iface.bus_read_4(card->hw,AFT_CHIP_CFG_REG,®); /* Reset Global Fifo for the whole card */ wan_set_bit(AFT_CHIPCFG_A108_A104_TDM_FIFO_SYNC_BIT,®); card->hw_iface.bus_write_4(card->hw,AFT_CHIP_CFG_REG,reg); WP_DELAY(1000); /* Clear Global Card Fifo reset */ wan_clear_bit(AFT_CHIPCFG_A108_A104_TDM_FIFO_SYNC_BIT,®); /* Enable TDM Quad DMA Ring buffer */ if (wan_test_bit(AFT_TDM_RING_BUF,&card->u.aft.chip_cfg_status)) { wan_set_bit(AFT_CHIPCFG_A108_A104_TDM_DMA_RINGBUF_BIT,®); card->hw_iface.fe_set_bit(card->hw,1); }else{ wan_clear_bit(AFT_CHIPCFG_A108_A104_TDM_DMA_RINGBUF_BIT,®); } #if 1 /* Global Acknowledge TDM Interrupt (Kickstart) */ if (card->adptr_type == A104_ADPTR_4TE1 && card->u.aft.firm_id == AFT_PMC_FE_CORE_ID) { wan_set_bit(AFT_CHIPCFG_A104_TDM_ACK_BIT,®); } else { wan_set_bit(AFT_CHIPCFG_A108_TDM_GLOBAL_RX_INTR_ACK,®); wan_set_bit(AFT_CHIPCFG_A108_TDM_GLOBAL_TX_INTR_ACK,®); } #endif card->hw_iface.bus_write_4(card->hw,AFT_CHIP_CFG_REG,reg); card->rsync_timeout=SYSTEM_TICKS; DEBUG_EVENT("%s: AFT Global TDM Intr\n", card->devname); } else { card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_DMA_CTRL_REG),®); wan_set_bit(AFT_DMACTRL_TDMV_RX_TOGGLE,®); wan_set_bit(AFT_DMACTRL_TDMV_TX_TOGGLE,®); card->hw_iface.bus_write_4(card->hw, AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); if (wan_test_bit(AFT_TDM_SW_RING_BUF,&card->u.aft.chip_cfg_status)) { DEBUG_EVENT("%s: AFT Per Port TDM Intr (swring)\n",card->devname); } else { DEBUG_EVENT("%s: AFT Per Port TDM Intr\n",card->devname); } } #endif }/* if (card->u.aft.cfg.tdmv_span_no) */ #ifdef AFT_WDT_ENABLE aft_wdt_set(card,AFT_WDTCTRL_TIMEOUT); #endif DEBUG_TEST("%s: %s() end: reg=0x%X!\n" ,card->devname,__FUNCTION__,reg); AFT_FUNC_DEBUG(); } static void disable_data_error_intr(sdla_t *card, unsigned char event) { u32 reg; int card_use_cnt; card->hw_iface.getcfg(card->hw, SDLA_HWCPU_USEDCNT, &card_use_cnt); if(IS_BRI_CARD(card) && card_use_cnt > 1){ return; } DEBUG_TEST("%s: Event = %s\n",__FUNCTION__, event==DEVICE_DOWN?"Device Down": "Link Down"); DEBUG_EVENT("%s: AFT communications disabled! %d\n", card->devname, card_use_cnt); aft_wdt_reset(card); card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); wan_clear_bit(AFT_LCFG_DMA_INTR_BIT,®); wan_clear_bit(AFT_LCFG_FIFO_INTR_BIT,®); wan_clear_bit(AFT_LCFG_TDMV_INTR_BIT,®); if (IS_BRI_CARD(card)) { if (card_use_cnt == 1 && event==DEVICE_DOWN){ /* Disable Front End Interface */ wan_set_bit(AFT_LCFG_FE_IFACE_RESET_BIT,®); } }else{ if (event==DEVICE_DOWN){ /* Disable Front End Interface */ wan_set_bit(AFT_LCFG_FE_IFACE_RESET_BIT,®); } } card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG), reg); card->u.aft.lcfg_reg=reg; card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),®); wan_clear_bit(AFT_DMACTRL_GLOBAL_INTR_BIT,®); card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); if (event!=DEVICE_DOWN){ if (card->tdmv_conf.span_no){ DEBUG_EVENT("%s: Starting TDMV 1ms Timer\n", card->devname); #ifdef AFT_WDT_ENABLE aft_wdt_set(card,1); #endif } } wan_clear_bit(0,&card->u.aft.comm_enabled); } /*============================================================================ * Update communications error and general packet statistics. */ static int update_comms_stats(sdla_t* card) { /* 1. On the first timer interrupt, update T1/E1 alarms * and PMON counters (only for T1/E1 card) (TE1) */ /* TE1 Update T1/E1 alarms */ if (IS_TE1_CARD(card) && card->hw) { wan_smp_flag_t smp_flags; card->hw_iface.hw_lock(card->hw,&smp_flags); if (card->wandev.fe_iface.read_alarm) { card->wandev.fe_iface.read_alarm(&card->fe, WAN_FE_ALARM_READ|WAN_FE_ALARM_UPDATE); } /* TE1 Update T1/E1 perfomance counters */ #if 0 #warning "PMON DISABLED DUE TO ERROR" #else if (card->wandev.fe_iface.read_pmon) { wan_smp_flag_t flags; wan_spin_lock_irq(&card->wandev.lock,&flags); card->wandev.fe_iface.read_pmon(&card->fe, 0); wan_spin_unlock_irq(&card->wandev.lock,&flags); } #endif card->hw_iface.hw_unlock(card->hw,&smp_flags); } return 0; } static void aft_rx_fifo_over_recover(sdla_t *card, private_area_t *chan) { if (chan->channelized_cfg && !chan->hdlc_eng){ return; } #if 0 if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s:%s Rx Fifo Recovery!\n", card->devname,chan->if_name); } #endif aft_channel_rxdma_ctrl(card, chan, 0); aft_tslot_sync_ctrl(card,chan,0); aft_free_rx_complete_list(chan); aft_free_rx_descriptors(chan); aft_init_rx_dev_fifo(card, chan, WP_NO_WAIT); aft_channel_rxdma_ctrl(card, chan, 1); aft_init_rx_dev_fifo(card, chan, WP_WAIT); chan->dma_index=0; memset(chan->dma_history,0,sizeof(chan->dma_history)); aft_reset_rx_chain_cnt(chan); aft_dma_rx(card,chan); aft_tslot_sync_ctrl(card,chan,1); wanpipe_wake_stack(chan); } static void aft_tx_fifo_under_recover (sdla_t *card, private_area_t *chan) { if (chan->channelized_cfg && !chan->hdlc_eng){ return; } #if 0 if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s:%s Tx Fifo Recovery!\n", card->devname,chan->if_name); } #endif /* Enable DMA controler, in order to start the * fifo cleaning */ aft_channel_txdma_ctrl(card, chan, 0); #if 0 aft_list_tx_descriptors(chan); #endif aft_dma_tx_complete(card,chan,0, 1); aft_free_tx_descriptors(chan); aft_init_tx_dev_fifo(card,chan,WP_NO_WAIT); aft_channel_txdma_ctrl(card, chan, 1); aft_init_tx_dev_fifo(card,chan,WP_WAIT); wan_clear_bit(0,&chan->idle_start); aft_reset_tx_chain_cnt(chan); aft_dma_tx(card,chan); wanpipe_wake_stack(chan); } static int set_chan_state(sdla_t* card, netdevice_t* dev, int state) { private_area_t *chan = wan_netif_priv(dev); private_area_t *ch_ptr; if (!chan){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: %s:%d No chan ptr!\n", card->devname,__FUNCTION__,__LINE__); } return -EINVAL; } chan->common.state = state; for (ch_ptr=chan; ch_ptr != NULL; ch_ptr=ch_ptr->next){ ch_ptr->common.state=state; if (ch_ptr->tdmv_zaptel_cfg) { continue; } if (ch_ptr->common.usedby == TDM_VOICE_API || ch_ptr->common.usedby == TDM_VOICE_DCHAN) { #ifdef AFT_TDM_API_SUPPORT if (is_tdm_api(ch_ptr,&ch_ptr->wp_tdm_api_dev)) { wanpipe_tdm_api_update_state(&ch_ptr->wp_tdm_api_dev, state); } #endif } #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG if (ch_ptr->common.usedby == ANNEXG && ch_ptr->annexg_dev){ if (state == WAN_CONNECTED){ if (IS_FUNC_CALL(lapb_protocol,lapb_link_up)){ lapb_protocol.lapb_link_up(ch_ptr->annexg_dev); } } else { if (IS_FUNC_CALL(lapb_protocol,lapb_link_down)){ lapb_protocol.lapb_link_down(ch_ptr->annexg_dev); } } } #endif } if (state == WAN_CONNECTED){ wan_clear_bit(0,&chan->idle_start); WAN_NETIF_START_QUEUE(dev); chan->opstats.link_active_count++; WAN_NETIF_CARRIER_ON(dev); WAN_NETIF_WAKE_QUEUE(dev); }else{ chan->opstats.link_inactive_modem_count++; WAN_NETIF_CARRIER_OFF(dev); WAN_NETIF_STOP_QUEUE(dev); } #if defined(__LINUX__) # if !defined(CONFIG_PRODUCT_WANPIPE_GENERIC) if (chan->common.usedby == API) { wan_update_api_state(chan); } #endif #endif if (chan->common.usedby == STACK){ if (state == WAN_CONNECTED){ wanpipe_lip_connect(chan,0); }else{ wanpipe_lip_disconnect(chan,0); } } #if defined(NETGRAPH) if (chan->common.usedby == WP_NETGRAPH){ wan_ng_link_state(&chan->common, state); } #endif return 0; } /**SECTION************************************************************* * * Protocol API Support Functions * **********************************************************************/ static int protocol_init (sdla_t *card, netdevice_t *dev, private_area_t *chan, wanif_conf_t* conf) { chan->common.protocol = conf->protocol; DEBUG_TEST("%s: Protocol init 0x%X PPP=0x0%x FR=0x0%X\n", wan_netif_name(dev), chan->common.protocol, WANCONFIG_PPP, WANCONFIG_FR); #ifndef CONFIG_PRODUCT_WANPIPE_GENERIC DEBUG_EVENT("%s: AFT Driver doesn't directly support any protocols!\n", chan->if_name); return -1; #else if (chan->common.protocol == WANCONFIG_PPP || chan->common.protocol == WANCONFIG_CHDLC){ struct ifreq ifr; struct if_settings ifsettings; wanpipe_generic_register(card, dev, wan_netif_name(dev)); chan->common.prot_ptr = dev; if (chan->common.protocol == WANCONFIG_CHDLC){ DEBUG_EVENT("%s: Starting Kernel CISCO HDLC protocol\n", chan->if_name); ifsettings.type = IF_PROTO_CISCO; }else{ DEBUG_EVENT("%s: Starting Kernel Sync PPP protocol\n", chan->if_name); ifsettings.type = IF_PROTO_PPP; } ifr.ifr_data = (caddr_t)&ifsettings; if (wp_lite_set_proto(dev, &ifr)){ wanpipe_generic_unregister(dev); return -EINVAL; } }else if (chan->common.protocol == WANCONFIG_GENERIC){ chan->common.prot_ptr = dev; }else{ DEBUG_EVENT("%s:%s: Unsupported protocol %d\n", card->devname,chan->if_name,chan->common.protocol); return -EPROTONOSUPPORT; } #endif return 0; } static int protocol_stop (sdla_t *card, netdevice_t *dev) { private_area_t *chan=wan_netif_priv(dev); int err = 0; if (!chan) return 0; return err; } static int protocol_shutdown (sdla_t *card, netdevice_t *dev) { private_area_t *chan=wan_netif_priv(dev); if (!chan) return 0; #ifndef CONFIG_PRODUCT_WANPIPE_GENERIC return 0; #else if (chan->common.protocol == WANCONFIG_PPP || chan->common.protocol == WANCONFIG_CHDLC){ chan->common.prot_ptr = NULL; wanpipe_generic_unregister(dev); }else if (chan->common.protocol == WANCONFIG_GENERIC){ DEBUG_EVENT("%s:%s Protocol shutdown... \n", card->devname, chan->if_name); } #endif return 0; } void protocol_recv(sdla_t *card, private_area_t *chan, netskb_t *skb) { #ifdef CONFIG_PRODUCT_WANPIPE_GENERIC if (chan->common.protocol == WANCONFIG_PPP || chan->common.protocol == WANCONFIG_CHDLC){ wanpipe_generic_input(chan->common.dev, skb); return 0; } #if defined(__LINUX__) if (chan->common.protocol == WANCONFIG_GENERIC){ skb->protocol = htons(ETH_P_HDLC); skb->dev = chan->common.dev; wan_skb_reset_mac_header(skb); netif_rx(skb); return 0; } #endif #endif #if defined(__LINUX__) skb->protocol = htons(ETH_P_IP); skb->dev = chan->common.dev; wan_skb_reset_mac_header(skb); netif_rx(skb); #elif defined(__FreeBSD__) wan_skb_set_csum(skb,0); if (wan_iface.input && wan_iface.input(chan->common.dev, skb) != 0){ WAN_NETIF_STATS_INC_RX_DROPPED(&chan->common); //++chan->if_stats.rx_dropped; wan_skb_free(skb); return; } #else DEBUG_EVENT("%s: Action not supported (IP)!\n", card->devname); wan_skb_free(skb); #endif return; } /**SECTION************************************************************* * * TE1 Config Code * **********************************************************************/ static int aft_global_chip_configuration(sdla_t *card, wandev_conf_t* conf) { int err=0; err = aft_hwdev[card->wandev.card_type].aft_global_chip_config(card); return err; } static int aft_global_chip_disable(sdla_t *card) { aft_hwdev[card->wandev.card_type].aft_global_chip_unconfig(card); return 0; } /*========================================================= * aft_chip_configure * */ static int aft_chip_configure(sdla_t *card, wandev_conf_t* conf) { return aft_hwdev[card->wandev.card_type].aft_chip_config(card, conf); } static int aft_chip_unconfigure(sdla_t *card) { u32 reg=0; AFT_FUNC_DEBUG(); wan_set_bit(CARD_DOWN,&card->wandev.critical); aft_hwdev[card->wandev.card_type].aft_chip_unconfig(card); card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_LINE_CFG_REG),&card->u.aft.lcfg_reg); card->u.aft.lcfg_reg=reg; return 0; } static int aft_dev_configure(sdla_t *card, private_area_t *chan, wanif_conf_t* conf) { chan->logic_ch_num=-1; /* Channel definition section. If not channels defined * return error */ if (chan->time_slot_map == 0){ DEBUG_EVENT("%s: Invalid Channel Selection 0x%X\n", card->devname,chan->time_slot_map); return -EINVAL; } DEBUG_EVENT("%s: Active Ch Map :0x%08X\n", card->devname,chan->time_slot_map); DEBUG_TEST("%s:%d: GOT Logic ch %ld Base 0x%X Size=0x%X\n", __FUNCTION__,__LINE__,chan->logic_ch_num, chan->fifo_base_addr, chan->fifo_size_code); return aft_hwdev[card->wandev.card_type].aft_chan_config(card,chan); } static void aft_dev_unconfigure(sdla_t *card, private_area_t *chan) { aft_hwdev[card->wandev.card_type].aft_chan_unconfig(card,chan); return ; } #define BIT_DEV_ADDR_CLEAR 0x600 /**SECTION************************************************************* * * TE1 Tx Functions * DMA Chains * **********************************************************************/ /*=============================================== * aft_tx_dma_voice_handler * */ static void aft_tx_dma_voice_handler(unsigned long data, int wdt, int reset) { private_area_t *chan = (private_area_t *)data; sdla_t *card = chan->card; u32 reg,dma_descr,dma_status; wan_dma_descr_t *dma_chain; if (wan_test_and_set_bit(TX_HANDLER_BUSY,&chan->dma_status)){ DEBUG_EVENT("%s: SMP Critical in %s\n", chan->if_name,__FUNCTION__); return; } dma_chain = &chan->tx_dma_chain_table[0]; if (reset){ wan_clear_bit(0,&dma_chain->init); dma_descr=(chan->logic_ch_num<<4) + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); card->hw_iface.bus_write_4(card->hw,dma_descr,0); goto aft_tx_dma_voice_handler_exit; } /* If the current DMA chain is in use,then * all chains are busy */ if (!wan_test_bit(0,&dma_chain->init)){ goto aft_tx_dma_voice_handler_exit; } dma_descr=(chan->logic_ch_num<<4) + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_descr,®); /* If GO bit is set, then the current DMA chain * is in process of being transmitted, thus * all are busy */ if (wan_test_bit(AFT_TXDMA_HI_GO_BIT,®)){ goto aft_tx_dma_voice_handler_exit; } dma_status = aft_txdma_hi_get_dma_status(reg); if (reg & AFT_TXDMA_HI_DMA_LENGTH_MASK){ chan->errstats.Tx_dma_len_nonzero++; chan->errstats.Tx_dma_errors++; } if (dma_status){ DEBUG_TEST("%s:%s: Tx DMA Descriptor=0x%X\n", card->devname,chan->if_name,reg); /* Checking Tx DMA PCI error status. Has to be '0's */ if (dma_status){ chan->errstats.Tx_pci_errors++; if (wan_test_bit(AFT_TXDMA_HIDMASTATUS_PCI_M_ABRT,&dma_status)){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s:%s: Tx Error: Abort from Master: pci fatal error!\n", card->devname,chan->if_name); } } if (wan_test_bit(AFT_TXDMA_HIDMASTATUS_PCI_T_ABRT,&dma_status)){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s:%s: Tx Error: Abort from Target: pci fatal error!\n", card->devname,chan->if_name); } } if (wan_test_bit(AFT_TXDMA_HIDMASTATUS_PCI_DS_TOUT,&dma_status)){ DEBUG_TEST("%s:%s: Tx Warning: PCI Latency Timeout!\n", card->devname,chan->if_name); chan->errstats.Tx_pci_latency++; goto aft_tx_dma_voice_handler_exit; } if (wan_test_bit(AFT_TXDMA_HIDMASTATUS_PCI_RETRY,&dma_status)){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s:%s: Tx Error: 'Retry' exceeds maximum (64k): pci fatal error!\n", card->devname,chan->if_name); } } } WAN_NETIF_STATS_INC_TX_ERRORS(&chan->common); //chan->if_stats.tx_errors++; } chan->opstats.Data_frames_Tx_count++; chan->opstats.Data_bytes_Tx_count+=wan_skb_len(dma_chain->skb); WAN_NETIF_STATS_INC_TX_PACKETS(&chan->common); //chan->if_stats.tx_packets++; WAN_NETIF_STATS_INC_TX_BYTES(&chan->common,wan_skb_len(dma_chain->skb)); //chan->if_stats.tx_bytes+=wan_skb_len(dma_chain->skb); wan_clear_bit(0,&dma_chain->init); aft_tx_dma_voice_handler_exit: wan_clear_bit(TX_HANDLER_BUSY,&chan->dma_status); return; } /*=============================================== * aft_tx_dma_chain_handler * */ static void aft_tx_dma_chain_handler(unsigned long data, int wdt, int reset) { private_area_t *chan = (private_area_t *)data; sdla_t *card = chan->card; u32 reg,dma_descr; wan_dma_descr_t *dma_chain; if (wan_test_and_set_bit(TX_HANDLER_BUSY,&chan->dma_status)){ DEBUG_EVENT("%s: SMP Critical in %s\n", chan->if_name,__FUNCTION__); return; } dma_chain = &chan->tx_dma_chain_table[chan->tx_pending_chain_indx]; for (;;){ /* If the current DMA chain is in use,then * all chains are busy */ if (!wan_test_bit(0,&dma_chain->init)){ break; } dma_descr=(chan->logic_ch_num<<4) + (chan->tx_pending_chain_indx*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_descr,®); /* If GO bit is set, then the current DMA chain * is in process of being transmitted, thus * all are busy */ if (wan_test_bit(AFT_TXDMA_HI_GO_BIT,®)){ break; } if (!wan_test_bit(AFT_TXDMA_HI_INTR_DISABLE_BIT,®)){ wan_clear_bit(TX_INTR_PENDING,&chan->dma_chain_status); if (wdt){ DEBUG_TEST("%s:%s TX WDT Timer got Interrtup pkt!\n", card->devname,chan->if_name); } } DEBUG_TEST("%s: TX DMA Handler Chain %d\n",chan->if_name,dma_chain->index); if (chan->hdlc_eng){ if (dma_chain->skb == chan->tx_hdlc_rpt_skb) { if (wan_skb_queue_len(&chan->wp_tx_hdlc_rpt_list) == 0) { wan_skb_queue_tail(&chan->wp_tx_hdlc_rpt_list,dma_chain->skb); dma_chain->skb=NULL; } else { /* Drop down to init where packet will freed */ } chan->tx_hdlc_rpt_skb=NULL; } else if (dma_chain->skb){ wan_skb_set_csum(dma_chain->skb, reg); wan_skb_queue_tail(&chan->wp_tx_complete_list,dma_chain->skb); dma_chain->skb=NULL; } } else { if (dma_chain->skb != chan->tx_idle_skb){ wan_skb_set_csum(dma_chain->skb, reg); aft_tx_post_complete(chan->card,chan,dma_chain->skb); if (chan->channelized_cfg && !chan->hdlc_eng){ /* Voice code uses the rx buffer to * transmit! So put the rx buffer back * into the rx queue */ aft_init_requeue_free_skb(chan, dma_chain->skb); }else{ wan_skb_free(dma_chain->skb); } dma_chain->skb=NULL; } } aft_tx_dma_chain_init(chan,dma_chain); if (chan->single_dma_chain){ break; } if (++chan->tx_pending_chain_indx >= MAX_AFT_DMA_CHAINS){ chan->tx_pending_chain_indx=0; } dma_chain = &chan->tx_dma_chain_table[chan->tx_pending_chain_indx]; } wan_clear_bit(TX_HANDLER_BUSY,&chan->dma_status); if (wan_skb_queue_len(&chan->wp_tx_complete_list)){ WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); } return; } /*=============================================== * aft_dma_chain_tx * */ static int aft_dma_chain_tx(wan_dma_descr_t *dma_chain,private_area_t *chan, int intr,int fifo) { #define dma_descr dma_chain->dma_descr #define reg dma_chain->reg #define dma_ch_indx dma_chain->index #define len_align dma_chain->len_align #define card chan->card unsigned int len = dma_chain->dma_len; unsigned int ss7_ctrl=0; dma_descr=(chan->logic_ch_num<<4) + (dma_ch_indx*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); DEBUG_DMA("%s: %s:%s: LogicCh=%ld ChIndex=%d DmaDesc=0x%x set\n", __FUNCTION__, card->devname, chan->if_name, chan->logic_ch_num,dma_ch_indx,dma_descr); card->hw_iface.bus_read_4(card->hw,dma_descr,®); if (wan_test_bit(AFT_TXDMA_HI_GO_BIT,®)){ DEBUG_EVENT("%s: Error: TxDMA GO Ready bit set on dma (chain=0x%X) Desc=0x%X Tx 0x%X\n", card->devname,dma_descr,dma_ch_indx,reg); /* Nothing we can do here, just reset descriptor and keep going */ card->hw_iface.bus_write_4(card->hw,dma_descr,0); card->hw_iface.bus_read_4(card->hw,dma_descr,®); } dma_descr=(chan->logic_ch_num<<4) + (dma_ch_indx*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_TX_DMA_LO_DESCR_BASE_REG); /* Write the pointer of the data packet to the * DMA address register */ reg=dma_chain->dma_addr; if (chan->cfg.ss7_enable){ ss7_ctrl=wan_skb_csum(dma_chain->skb); wan_skb_set_csum(dma_chain->skb,0); if (ss7_ctrl&AFT_SS7_CTRL_LEN_MASK){ len-=4; len+=ss7_ctrl&AFT_SS7_CTRL_LEN_MASK; } if (!wan_test_bit(AFT_SS7_CTRL_TYPE_BIT,&ss7_ctrl)){ /*FISU*/ if (chan->cfg.ss7_mode == WANOPT_SS7_MODE_4096){ len-=WANOPT_SS7_FISU_4096_SZ; }else{ len-=WANOPT_SS7_FISU_128_SZ; } }else{ /*LSSU*/ len-=chan->cfg.ss7_lssu_size; } } /* Set the 32bit alignment of the data length. * Used to pad the tx packet to the 32 bit * boundary */ aft_txdma_lo_set_alignment(®,len); len_align=0; if (len&0x03){ len_align=1; } DEBUG_DMA("%s: %s:%s: TXDMA_LO=0x%X PhyAddr=0x%X DmaDescr=0x%X Len=%d\n", __FUNCTION__,card->devname,chan->if_name, reg,dma_chain->dma_addr,dma_descr,len); card->hw_iface.bus_write_4(card->hw,dma_descr,reg); dma_descr=(chan->logic_ch_num<<4) + (dma_ch_indx*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); reg=0; if (chan->cfg.ss7_enable){ if (wan_test_bit(AFT_SS7_CTRL_TYPE_BIT,&ss7_ctrl)){ wan_set_bit(AFT_TXDMA_HI_SS7_FISU_OR_LSSU_BIT,®); }else{ wan_clear_bit(AFT_TXDMA_HI_SS7_FISU_OR_LSSU_BIT,®); } if (wan_test_bit(AFT_SS7_CTRL_FORCE_BIT,&ss7_ctrl)){ wan_set_bit(AFT_TXDMA_HI_SS7_FI_LS_FORCE_TX_BIT,®); }else{ wan_clear_bit(AFT_TXDMA_HI_SS7_FI_LS_FORCE_TX_BIT,®); } } aft_txdma_hi_set_dma_length(®,len,len_align); if (chan->single_dma_chain){ wan_clear_bit(AFT_TXDMA_HI_LAST_DESC_BIT,®); wan_clear_bit(AFT_TXDMA_HI_INTR_DISABLE_BIT,®); if (chan->channelized_cfg && !chan->hdlc_eng){ wan_set_bit(AFT_TXDMA_HI_LAST_DESC_BIT,®); } }else{ wan_set_bit(AFT_TXDMA_HI_LAST_DESC_BIT,®); if (intr){ DEBUG_TEST("%s: Setting Interrupt on index=%d\n", chan->if_name,dma_ch_indx); wan_clear_bit(AFT_TXDMA_HI_INTR_DISABLE_BIT,®); }else{ wan_set_bit(AFT_TXDMA_HI_INTR_DISABLE_BIT,®); } } if (chan->hdlc_eng){ /* Only enable the Frame Start/Stop on * non-transparent hdlc configuration */ wan_set_bit(AFT_TXDMA_HI_START_BIT,®); wan_set_bit(AFT_TXDMA_HI_EOF_BIT,®); }else{ /* Used for transparent time slot * synchronization */ if (chan->tslot_sync){ wan_set_bit(AFT_TXDMA_HI_START_BIT,®); } } wan_set_bit(AFT_TXDMA_HI_GO_BIT,®); if (fifo){ /* Clear fifo command */ wan_set_bit(AFT_TXDMA_HI_DMA_CMD_BIT,®); } DEBUG_DMA("%s:: %s:%s: TXDMA_HI=0x%X DmaDescr=0x%X Len=%d Intr=%d\n", __FUNCTION__,card->devname,chan->if_name, reg,dma_descr,len,intr); card->hw_iface.bus_write_4(card->hw,dma_descr,reg); #if 1 ++chan->tx_attempts; #endif return 0; #undef dma_descr #undef reg #undef dma_ch_indx #undef len_align #undef card } /*=============================================== * aft_dma_chain_init * */ static void aft_tx_dma_chain_init(private_area_t *chan, wan_dma_descr_t *dma_chain) { #define card chan->card card->hw_iface.busdma_sync( card->hw, dma_chain, 1, 1, SDLA_DMA_POSTWRITE); card->hw_iface.busdma_unmap( card->hw, dma_chain, SDLA_DMA_POSTWRITE); if (dma_chain->skb){ if (!chan->hdlc_eng){ if (dma_chain->skb != chan->tx_idle_skb){ if (chan->channelized_cfg && !chan->hdlc_eng){ aft_init_requeue_free_skb(chan, dma_chain->skb); }else{ wan_skb_free(dma_chain->skb); } } dma_chain->skb=NULL; }else{ wan_skb_free(dma_chain->skb); dma_chain->skb=NULL; } } wan_clear_bit(0,&dma_chain->init); #undef card } static void aft_rx_dma_chain_init(private_area_t *chan, wan_dma_descr_t *dma_chain) { #define card chan->card card->hw_iface.busdma_sync( card->hw, dma_chain, 1, 1, SDLA_DMA_POSTREAD); card->hw_iface.busdma_unmap( card->hw, dma_chain, SDLA_DMA_POSTREAD); if (dma_chain->skb){ aft_init_requeue_free_skb(chan,dma_chain->skb); dma_chain->skb = NULL; } wan_clear_bit(0,&dma_chain->init); #undef card } static int aft_dma_voice_tx(sdla_t *card, private_area_t *chan) { int err=0; wan_dma_descr_t *dma_chain; u32 reg, dma_ram_desc; if (wan_test_and_set_bit(TX_DMA_BUSY,&chan->dma_status)){ DEBUG_EVENT("%s: SMP Critical in %s\n", chan->if_name,__FUNCTION__); return -EBUSY; } dma_chain = &chan->tx_dma_chain_table[0]; DEBUG_DMA("%s: %s:%s:: Chain %d Used %ld\n", __FUNCTION__,card->devname,chan->if_name, dma_chain->index,dma_chain->init); /* If the current DMA chain is in use,then * all chains are busy */ if (wan_test_and_set_bit(0,&dma_chain->init)){ err=-EBUSY; goto aft_dma_voice_tx_exit; } if (!dma_chain->skb){ unsigned char *buf; /* Take already preallocated buffer from rx queue. * We are only using a single buffer for rx and tx */ dma_chain->skb=wan_skb_dequeue(&chan->wp_rx_free_list); if (!dma_chain->skb){ DEBUG_EVENT("%s: Warning Tx chain = %d: no free tx bufs\n", chan->if_name,dma_chain->index); wan_clear_bit(0,&dma_chain->init); err=-EINVAL; goto aft_dma_voice_tx_exit; } wan_skb_init(dma_chain->skb,16); wan_skb_trim(dma_chain->skb,0); /*NC: We must set the initial value of the * frist DMA TX transfer to 2*MTU. This is * to avoid potential Tx FIFO underrun. * * This is equivalent of transmitting twice * very fist time. */ buf=wan_skb_put(dma_chain->skb,chan->mtu*2); memset(buf,chan->idle_flag,chan->mtu*2); /* A-DMA */ card->hw_iface.busdma_map( card->hw, dma_chain, wan_skb_data(dma_chain->skb), wan_skb_len(dma_chain->skb), chan->dma_mru, SDLA_DMA_PREWRITE); card->hw_iface.busdma_sync( card->hw, dma_chain, 1, 1, SDLA_DMA_PREWRITE); } dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); aft_dmachain_set_tx_dma_addr(®,1); card->hw_iface.bus_write_4(card->hw,dma_ram_desc,reg); /* We set inital TX DMA with FIFO Reset option. This funciton * will ONLY run once in TDM mode. After the inital TX the * DMA Reload will be used to tx the Voice frame */ err=aft_dma_chain_tx(dma_chain,chan,1,1); if (err){ DEBUG_EVENT("%s: Tx dma chain %d overrun error: should never happen!\n", chan->if_name,dma_chain->index); /* Drop the tx packet here */ aft_tx_dma_chain_init(chan,dma_chain); WAN_NETIF_STATS_INC_TX_ERRORS(&chan->common); //chan->if_stats.tx_errors++; err=-EINVAL; goto aft_dma_voice_tx_exit; } aft_dma_voice_tx_exit: wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); return 0; } /*=============================================== * aft_dma_tx * */ static int aft_dma_tx (sdla_t *card,private_area_t *chan) { int err=0, intr=0, cnt=0; wan_dma_descr_t *dma_chain; netskb_t *skb=NULL; if (chan->channelized_cfg && !chan->hdlc_eng){ return aft_dma_voice_tx(card,chan); } if (wan_test_and_set_bit(TX_DMA_BUSY,&chan->dma_status)){ DEBUG_EVENT("%s: SMP Critical in %s\n", chan->if_name,__FUNCTION__); return -EBUSY; } if (chan->tx_chain_indx >= MAX_AFT_DMA_CHAINS){ DEBUG_EVENT("%s: MAJOR ERROR: TE1 Tx: Dma tx chain = %d\n", chan->if_name,chan->tx_chain_indx); return -EBUSY; } /* The cnt is not used, its used only as a * sanity check. The code below should break * out of the loop before MAX_TX_BUF runs out! */ for (cnt=0;cnttx_dma_chain_table[chan->tx_chain_indx]; /* FIXME: Reset TX Watchdog */ /* aft_reset_tx_watchdog(card); */ /* If the current DMA chain is in use,then * all chains are busy */ if (wan_test_and_set_bit(0,&dma_chain->init)){ wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); break; } if(!chan->lip_atm){ skb=wan_skb_dequeue(&chan->wp_tx_pending_list); }else{ skb=atm_tx_skb_dequeue(&chan->wp_tx_pending_list, chan->tx_idle_skb, chan->if_name); } if (!skb){ if (!chan->hdlc_eng){ skb=chan->tx_idle_skb; if (!skb){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: Critical Error: Transparent tx no skb!\n", chan->if_name); } break; } WAN_NETIF_STATS_INC_TX_CARRIER_ERRORS(&chan->common); } else { if (chan->cfg.hdlc_repeat) { /* Pull the latest repeat frame out of the repeat queue */ for (;;) { skb=wan_skb_dequeue(&chan->wp_tx_hdlc_rpt_list); if (!skb) { break; } if (wan_skb_queue_len(&chan->wp_tx_hdlc_rpt_list)){ wan_skb_free(skb); } else { break; } } if (skb) { chan->tx_hdlc_rpt_skb=skb; } else { WAN_NETIF_STATS_INC_TX_CARRIER_ERRORS(&chan->common); /* Pass throught to no skb condition */ } } if (!skb) { wan_clear_bit(0,&dma_chain->init); wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); break; } } } if ((unsigned long)wan_skb_data(skb) & 0x03){ err=aft_realign_skb_pkt(chan,skb); if (err){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: Tx Error: Non Aligned packet %p: dropping...\n", chan->if_name,wan_skb_data(skb)); } wan_skb_free(skb); aft_tx_dma_chain_init(chan,dma_chain); WAN_NETIF_STATS_INC_TX_ERRORS(&chan->common); //chan->if_stats.tx_errors++; chan->opstats.Tx_Data_discard_lgth_err_count++; continue; } } if (!chan->hdlc_eng && (wan_skb_len(skb)%4)){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: Tx Error: Tx Length %i not 32bit aligned: dropping...\n", chan->if_name,wan_skb_len(skb)); } wan_skb_free(skb); aft_tx_dma_chain_init(chan,dma_chain); WAN_NETIF_STATS_INC_TX_ERRORS(&chan->common); //chan->if_stats.tx_errors++; chan->opstats.Tx_Data_discard_lgth_err_count++; continue; } dma_chain->skb=skb; /* A-DMA */ card->hw_iface.busdma_map( card->hw, dma_chain, wan_skb_data(dma_chain->skb), wan_skb_len(dma_chain->skb), wan_skb_len(dma_chain->skb), SDLA_DMA_PREWRITE); card->hw_iface.busdma_sync( card->hw, dma_chain, 1, chan->single_dma_chain, SDLA_DMA_PREWRITE); DEBUG_TEST("%s: DMA Chain %d: Cur=%d Pend=%d\n", chan->if_name,dma_chain->index, chan->tx_chain_indx,chan->tx_pending_chain_indx); intr=0; if (!wan_test_bit(TX_INTR_PENDING,&chan->dma_chain_status)){ int pending_indx=chan->tx_pending_chain_indx; if (chan->tx_chain_indx >= pending_indx){ intr = ((MAX_AFT_DMA_CHAINS-(chan->tx_chain_indx - pending_indx))<=2); }else{ intr = ((pending_indx - chan->tx_chain_indx)<=2); } if (intr){ DEBUG_TEST("%s: Setting tx interrupt on chain=%d\n", chan->if_name,dma_chain->index); wan_set_bit(TX_INTR_PENDING,&chan->dma_chain_status); } } err=aft_dma_chain_tx(dma_chain,chan,intr,0); if (err){ DEBUG_EVENT("%s: Tx dma chain %d overrun error: should never happen!\n", chan->if_name,dma_chain->index); #if 0 aft_list_tx_descriptors(chan); aft_critical_shutdown(card); break; #endif /* Drop the tx packet here */ aft_tx_dma_chain_init(chan,dma_chain); WAN_NETIF_STATS_INC_TX_ERRORS(&chan->common); //chan->if_stats.tx_errors++; break; } if (skb){ wan_capture_trace_packet(card, &chan->trace_info, skb, TRC_OUTGOING_FRM); } if (chan->single_dma_chain){ break; }else{ if (++chan->tx_chain_indx >= MAX_AFT_DMA_CHAINS){ chan->tx_chain_indx=0; } } } wan_clear_bit(TX_DMA_BUSY,&chan->dma_status); return 0; } /**SECTION************************************************************* * * TE1 Rx Functions * DMA Chains * **********************************************************************/ static int aft_dma_chain_rx(wan_dma_descr_t *dma_chain, private_area_t *chan, int intr, int fifo) { #define dma_descr dma_chain->dma_descr #define reg dma_chain->reg #define len dma_chain->dma_len #define dma_ch_indx dma_chain->index #define len_align dma_chain->len_align #define card chan->card /* Write the pointer of the data packet to the * DMA address register */ reg=dma_chain->dma_addr; /* Set the 32bit alignment of the data length. * Since we are setting up for rx, set this value * to Zero */ aft_rxdma_lo_set_alignment(®,0); dma_descr=(chan->logic_ch_num<<4) + (dma_ch_indx*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_RX_DMA_LO_DESCR_BASE_REG); DEBUG_DMA("%s: %s:%s: RxDMA_LO(%ld) = 0x%X, PhyAddr:%X DmaDescr=0x%X (%p)\n", __FUNCTION__,card->devname,chan->if_name, chan->logic_ch_num,reg, dma_chain->dma_addr, dma_descr,dma_chain); card->hw_iface.bus_write_4(card->hw,dma_descr,reg); dma_descr=(chan->logic_ch_num<<4) + (dma_ch_indx*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); reg =0; if (chan->single_dma_chain){ wan_clear_bit(AFT_RXDMA_HI_LAST_DESC_BIT,®); wan_clear_bit(AFT_RXDMA_HI_INTR_DISABLE_BIT,®); if (chan->channelized_cfg && !chan->hdlc_eng){ wan_set_bit(AFT_RXDMA_HI_LAST_DESC_BIT,®); } }else{ wan_set_bit(AFT_RXDMA_HI_LAST_DESC_BIT,®); #if AFT_IFT_INTR_ENABLE wan_set_bit(AFT_RXDMA_HI_IFT_INTR_ENB_BIT,®); #else wan_clear_bit(AFT_RXDMA_HI_IFT_INTR_ENB_BIT,®); #endif if (intr){ DEBUG_TEST("%s: Setting Rx Interrupt on index=%d\n", chan->if_name,dma_ch_indx); wan_clear_bit(AFT_RXDMA_HI_INTR_DISABLE_BIT,®); }else{ wan_set_bit(AFT_RXDMA_HI_INTR_DISABLE_BIT,®); } } if (chan->hdlc_eng){ aft_rxdma_hi_set_dma_length(®,chan->dma_mru,1); }else{ aft_rxdma_hi_set_dma_length(®,chan->mru,0); } wan_set_bit(AFT_RXDMA_HI_GO_BIT,®); if (fifo){ wan_set_bit(AFT_RXDMA_HI_DMA_CMD_BIT,®); } DEBUG_DMA("%s: %s:%s: RXDMA_HI(%ld) = 0x%X, DmaDescr=0x%X\n", __FUNCTION__,card->devname,chan->if_name, chan->logic_ch_num,reg,dma_descr); card->hw_iface.bus_write_4(card->hw,dma_descr,reg); return 0; #undef dma_descr #undef reg #undef len #undef dma_ch_indx #undef len_align #undef card } static int aft_dma_voice_rx(sdla_t *card, private_area_t *chan) { int err=0; wan_dma_descr_t *dma_chain; u32 reg, dma_ram_desc; if (wan_test_and_set_bit(RX_DMA_BUSY,&chan->dma_status)){ DEBUG_EVENT("%s: SMP Critical in %s\n", chan->if_name,__FUNCTION__); return -EBUSY; } dma_chain = &chan->rx_dma_chain_table[0]; DEBUG_DMA("%s: %s:%s: Chain %d Used %ld\n", __FUNCTION__,card->devname,chan->if_name, dma_chain->index,dma_chain->init); /* If the current DMA chain is in use,then * all chains are busy */ if (wan_test_and_set_bit(0,&dma_chain->init)){ DEBUG_TEST("%s: Warning: %s():%d dma chain busy %d!\n", card->devname, __FUNCTION__, __LINE__, dma_chain->index); err=-EBUSY; goto aft_dma_single_chain_rx_exit; } /* This will only be done on the first time. The dma_chain * skb will be re-used all the time, thus no need for * rx_free_list any more */ if (!dma_chain->skb){ dma_chain->skb=wan_skb_dequeue(&chan->wp_rx_free_list); if (!dma_chain->skb){ DEBUG_EVENT("%s: Warning Rx Voice chain = %d: no free rx bufs\n", chan->if_name,dma_chain->index); wan_clear_bit(0,&dma_chain->init); err=-EINVAL; goto aft_dma_single_chain_rx_exit; } wan_skb_init(dma_chain->skb,16); wan_skb_trim(dma_chain->skb,0); /* A-DMA */ card->hw_iface.busdma_map( card->hw, dma_chain, wan_skb_tail(dma_chain->skb), chan->dma_mru, chan->dma_mru, SDLA_DMA_PREREAD); card->hw_iface.busdma_sync( card->hw, dma_chain, MAX_AFT_DMA_CHAINS, chan->single_dma_chain, SDLA_DMA_PREREAD); DEBUG_DMA("%s: RXDMA PHY = 0x%08X VIRT = %p \n", chan->if_name, dma_chain->dma_addr,wan_skb_tail(dma_chain->skb)+dma_chain->dma_offset); }else{ wan_skb_init(dma_chain->skb,16); wan_skb_trim(dma_chain->skb,0); } dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); aft_dmachain_set_rx_dma_addr(®,1); card->hw_iface.bus_write_4(card->hw,dma_ram_desc,reg); err=aft_dma_chain_rx(dma_chain,chan,1,1); if (err){ DEBUG_EVENT("%s: Rx dma chain %d overrun error: should never happen!\n", chan->if_name,dma_chain->index); aft_rx_dma_chain_init(chan,dma_chain); WAN_NETIF_STATS_INC_RX_ERRORS(&chan->common); //chan->if_stats.rx_errors++; } aft_dma_single_chain_rx_exit: wan_clear_bit(RX_DMA_BUSY,&chan->dma_status); return err; } static int aft_dma_rx(sdla_t *card, private_area_t *chan) { int err=0, intr=0; wan_dma_descr_t *dma_chain; int cur_dma_ptr, i,max_dma_cnt,free_queue_len; u32 reg, dma_ram_desc; if (chan->channelized_cfg && !chan->hdlc_eng){ return aft_dma_voice_rx(card,chan); } if (wan_test_and_set_bit(RX_DMA_BUSY,&chan->dma_status)){ DEBUG_EVENT("%s: SMP Critical in %s\n", chan->if_name,__FUNCTION__); return -EBUSY; } free_queue_len=wan_skb_queue_len(&chan->wp_rx_free_list); if (!chan->single_dma_chain && free_queue_len < MAX_AFT_DMA_CHAINS){ aft_free_rx_complete_list(chan); free_queue_len=wan_skb_queue_len(&chan->wp_rx_free_list); if (free_queue_len < MAX_AFT_DMA_CHAINS){ DEBUG_EVENT("%s: %s() CRITICAL ERROR: No free rx buffers\n", card->devname,__FUNCTION__); goto te1rx_skip; } } dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); cur_dma_ptr=aft_dmachain_get_rx_dma_addr(reg); #if 0 aft_chain_history(chan,chan->rx_chain_indx, cur_dma_ptr, chan->rx_pending_chain_indx,1); #endif max_dma_cnt = MAX_AFT_DMA_CHAINS; if (!chan->single_dma_chain && free_queue_len < max_dma_cnt){ max_dma_cnt = free_queue_len; } DEBUG_RX("%s: (line: %d) DMA RX: CBoardPtr=%d Driver=%d MaxDMA=%d\n", card->devname, __LINE__, cur_dma_ptr,chan->rx_chain_indx,max_dma_cnt); for (i=0;irx_dma_chain_table[chan->rx_chain_indx]; /* If the current DMA chain is in use,then * all chains are busy */ if (wan_test_and_set_bit(0,&dma_chain->init)){ DEBUG_TEST("%s: Warning: %s():%d dma chain busy %d!\n", card->devname, __FUNCTION__, __LINE__, dma_chain->index); err=-EBUSY; break; } dma_chain->skb=wan_skb_dequeue(&chan->wp_rx_free_list); if (!dma_chain->skb){ /* If this ever happends, it means that wp_bh is stuck for some * reason, thus start using the completed buffers, thus * overflow the data */ dma_chain->skb=wan_skb_dequeue(&chan->wp_rx_complete_list); if (dma_chain->skb) { WAN_NETIF_STATS_INC_RX_DROPPED(&chan->common); //chan->if_stats.rx_dropped++; wan_skb_init(dma_chain->skb,16); wan_skb_trim(dma_chain->skb,0); }else{ DEBUG_EVENT("%s: Critical Rx chain = %d: no free rx bufs (Free=%i Comp=%i)\n", chan->if_name,dma_chain->index, wan_skb_queue_len(&chan->wp_rx_free_list), wan_skb_queue_len(&chan->wp_rx_complete_list)); wan_clear_bit(0,&dma_chain->init); aft_critical_shutdown(card); err=-EINVAL; break; } } card->hw_iface.busdma_map( card->hw, dma_chain, wan_skb_tail(dma_chain->skb), chan->dma_mru, chan->dma_mru, SDLA_DMA_PREREAD); card->hw_iface.busdma_sync( card->hw, dma_chain, 1, chan->single_dma_chain, SDLA_DMA_PREREAD); intr=0; if (!wan_test_bit(RX_INTR_PENDING,&chan->dma_chain_status)){ free_queue_len--; if (free_queue_len <= 2){ DEBUG_TEST("%s: DBG: Setting intr queue size low\n", card->devname); intr=1; }else{ if (chan->rx_chain_indx >= cur_dma_ptr){ intr = ((MAX_AFT_DMA_CHAINS - (chan->rx_chain_indx-cur_dma_ptr)) <=4); }else{ intr = ((cur_dma_ptr - chan->rx_chain_indx)<=4); } } if (intr){ DEBUG_TEST("%s: Setting Rx interrupt on chain=%d\n", chan->if_name,dma_chain->index); wan_set_bit(RX_INTR_PENDING,&chan->dma_chain_status); } } DEBUG_TEST("%s: Setting Buffer on Rx Chain = %d Intr=%d\n", chan->if_name,dma_chain->index, intr); err=aft_dma_chain_rx(dma_chain,chan,intr,0); if (err){ DEBUG_EVENT("%s: Rx dma chain %d overrun error: should never happen!\n", chan->if_name,dma_chain->index); aft_rx_dma_chain_init(chan,dma_chain); WAN_NETIF_STATS_INC_RX_ERRORS(&chan->common); //chan->if_stats.rx_errors++; break; } if (chan->single_dma_chain){ break; }else{ if (++chan->rx_chain_indx >= MAX_AFT_DMA_CHAINS){ chan->rx_chain_indx=0; } } } #if 0 aft_chain_history(chan,chan->rx_chain_indx, cur_dma_ptr, chan->rx_pending_chain_indx,2); if (chan->rx_chain_indx == cur_dma_ptr && chan->rx_pending_chain_indx == cur_dma_ptr && cur_dma_ptr != 0){ DEBUG_EVENT("%s :Location 1 Listing Descr!\n", chan->if_name); aft_list_descriptors(chan); } #endif aft_rx_cur_go_test(chan); te1rx_skip: wan_clear_bit(RX_DMA_BUSY,&chan->dma_status); return err; } /*=============================================== * aft_rx_dma_chain_handler * */ /*N1*/ static int aft_rx_dma_chain_handler(private_area_t *chan, int reset) { sdla_t *card = chan->card; u32 reg,dma_descr; wp_rx_element_t *rx_el; wan_dma_descr_t *dma_chain; int i,max_dma_cnt, cur_dma_ptr; int rx_data_available=0; u32 dma_ram_desc; if (wan_test_and_set_bit(RX_HANDLER_BUSY,&chan->dma_status)){ DEBUG_EVENT("%s: SMP Critical in %s\n", chan->if_name,__FUNCTION__); return rx_data_available; } dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); cur_dma_ptr=aft_dmachain_get_rx_dma_addr(reg); max_dma_cnt = MAX_AFT_DMA_CHAINS; DEBUG_RX("%s: (line: %d) DMA RX: CBoardPtr=%d Driver=%d MaxDMA=%d\n", card->devname, __LINE__, cur_dma_ptr, chan->rx_chain_indx,max_dma_cnt); #if 0 aft_chain_history(chan,chan->rx_chain_indx, cur_dma_ptr, chan->rx_pending_chain_indx,3); #endif for (i=0;irx_dma_chain_table[chan->rx_pending_chain_indx]; if (i>0 && chan->rx_pending_chain_indx == cur_dma_ptr){ break; } if (!dma_chain){ DEBUG_EVENT("%s:%d Assertion Error !!!!\n", __FUNCTION__,__LINE__); break; } /* If the current DMA chain is in use,then * all chains are busy */ if (!wan_test_bit(0,&dma_chain->init)){ DEBUG_TEST("%s: Warning (%s) Pending chain %d empty!\n", chan->if_name,__FUNCTION__,dma_chain->index); break; } dma_descr=(chan->logic_ch_num<<4) + (dma_chain->index*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_descr,®); /* If GO bit is set, then the current DMA chain * is in process of being transmitted, thus * all are busy */ if (wan_test_bit(AFT_RXDMA_HI_GO_BIT,®)){ if (wan_test_bit(WP_FIFO_ERROR_BIT, &chan->pkt_error)){ break; } #if 0 if (chan->single_dma_chain){ DEBUG_EVENT("%s: CRITICAL (%s) Pending chain %d Go bit still set!\n", chan->if_name,__FUNCTION__,dma_chain->index); WAN_NETIF_STATS_INC_RX_ERRORS(&chan->common); //++chan->if_stats.rx_errors; }else{ DEBUG_TEST("%s: Warning (%s) Pending chain %d Go bit still set!\n", chan->if_name,__FUNCTION__,dma_chain->index); } #endif break; } if (!wan_test_bit(AFT_RXDMA_HI_INTR_DISABLE_BIT,®)){ wan_clear_bit(RX_INTR_PENDING,&chan->dma_chain_status); } if (sizeof(wp_rx_element_t) > wan_skb_headroom(dma_chain->skb)){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: Rx error: rx_el=%u > max head room=%u\n", chan->if_name, (u32)sizeof(wp_rx_element_t), (u32)wan_skb_headroom(dma_chain->skb)); } aft_init_requeue_free_skb(chan, dma_chain->skb); WAN_NETIF_STATS_INC_RX_ERRORS(&chan->common); //++chan->if_stats.rx_errors; goto rx_hndlr_skip_rx; }else{ rx_el=(wp_rx_element_t *)wan_skb_push(dma_chain->skb, sizeof(wp_rx_element_t)); memset(rx_el,0,sizeof(wp_rx_element_t)); } #if 0 WAN_NETIF_STATS_INC_RX_FRAME_ERRORS(&chan->common); //chan->if_stats.rx_frame_errors++; #endif /* Reading Rx DMA descriptor information */ dma_descr=(chan->logic_ch_num<<4) +(dma_chain->index*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_RX_DMA_LO_DESCR_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_descr, &rx_el->align); rx_el->align&=AFT_RXDMA_LO_ALIGN_MASK; dma_descr=(chan->logic_ch_num<<4) +(dma_chain->index*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_descr, &rx_el->reg); /* New for FreeBSD/Solaris */ rx_el->len=rx_el->reg&AFT_RXDMA_HI_DMA_LENGTH_MASK; if (chan->hdlc_eng){ /* In HDLC mode, calculate rx length based * on alignment value, received from DMA */ rx_el->len=((((chan->dma_mru>>2)-1)-rx_el->len)<<2) - (~(rx_el->align)&AFT_RXDMA_LO_ALIGN_MASK); }else{ /* In Transparent mode, our RX buffer will always be * aligned to the 32bit (word) boundary, because * the RX buffers are all of equal length */ rx_el->len=(((chan->mru>>2)-rx_el->len)<<2) - (~(0x03)&AFT_RXDMA_LO_ALIGN_MASK); } rx_el->pkt_error= dma_chain->pkt_error; rx_el->dma_addr = dma_chain->dma_addr; /* A-DMA */ card->hw_iface.busdma_sync( card->hw, dma_chain, 1, chan->single_dma_chain, SDLA_DMA_POSTREAD); dma_chain->dma_len = rx_el->len; /* update real dma len*/ card->hw_iface.busdma_unmap( card->hw, dma_chain, SDLA_DMA_POSTREAD); #if defined(__FreeBSD__) wan_skb_put(dma_chain->skb, rx_el->len); #endif wan_skb_queue_tail(&chan->wp_rx_complete_list,dma_chain->skb); rx_data_available=1; DEBUG_TEST("%s: RxInt Pending chain %d Rxlist=%d LO:0x%X HI:0x%X Len=%i!\n", chan->if_name,dma_chain->index, wan_skb_queue_len(&chan->wp_rx_complete_list), rx_el->align,rx_el->reg, rx_el->len); rx_hndlr_skip_rx: dma_chain->skb=NULL; dma_chain->pkt_error=0; wan_clear_bit(0,&dma_chain->init); if (chan->single_dma_chain){ break; } if (++chan->rx_pending_chain_indx >= MAX_AFT_DMA_CHAINS){ chan->rx_pending_chain_indx=0; } } if (reset){ goto reset_skip_rx_setup; } aft_dma_rx(card,chan); if (wan_skb_queue_len(&chan->wp_rx_complete_list)){ DEBUG_TEST("%s: Rx Queued list triggering\n",chan->if_name); WAN_TASKLET_SCHEDULE((&chan->common.bh_task)); } reset_skip_rx_setup: wan_clear_bit(RX_HANDLER_BUSY,&chan->dma_status); return rx_data_available; } static int aft_dma_rx_complete(sdla_t *card, private_area_t *chan, int reset) { if (chan->cfg.ss7_enable){ aft_clear_ss7_force_rx(card,chan); } return aft_rx_dma_chain_handler(chan,reset); } /*=============================================== * TE1 DMA Chains Utility Funcitons * */ static void aft_index_tx_rx_dma_chains(private_area_t *chan) { int i; for (i=0;itx_dma_chain_table[i].index=i; chan->rx_dma_chain_table[i].index=i; } } static void aft_init_tx_rx_dma_descr(private_area_t *chan) { int i; u32 reg=0; sdla_t *card=chan->card; unsigned long tx_dma_descr,rx_dma_descr; unsigned int dma_cnt=MAX_AFT_DMA_CHAINS; if (chan->single_dma_chain){ dma_cnt=1; } if (IS_BRI_CARD(card) && chan->dchan_time_slot >= 0){ return; } for (i=0;ilogic_ch_num<<4) + (i*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); rx_dma_descr=(chan->logic_ch_num<<4) + (i*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); card->hw_iface.bus_write_4(card->hw,tx_dma_descr,reg); card->hw_iface.bus_write_4(card->hw,rx_dma_descr,reg); aft_tx_dma_chain_init(chan,&chan->tx_dma_chain_table[i]); aft_rx_dma_chain_init(chan,&chan->rx_dma_chain_table[i]); } } static void aft_free_rx_complete_list(private_area_t *chan) { void *skb; while((skb=wan_skb_dequeue(&chan->wp_rx_complete_list)) != NULL){ DEBUG_TEST("%s: aft_free_rx_complete_list dropped\n", chan->if_name); WAN_NETIF_STATS_INC_RX_DROPPED(&chan->common); //chan->if_stats.rx_dropped++; aft_init_requeue_free_skb(chan, skb); } } static void aft_rx_cur_go_test(private_area_t *chan) { #if 0 u32 reg,cur_dma_ptr; sdla_t *card=chan->card; wan_dma_descr_t *dma_chain; u32 dma_descr; int i; u32 dma_ram_desc; unsigned int dma_cnt=MAX_AFT_DMA_CHAINS; dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); cur_dma_ptr=aft_dmachain_get_rx_dma_addr(reg); dma_descr=(chan->logic_ch_num<<4) +(cur_dma_ptr*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_descr,®); if (!wan_test_bit(AFT_RXDMA_HI_GO_BIT,®)){ DEBUG_EVENT("%s: CRITICAL Cur =%d not Got bit set!\n", chan->if_name, cur_dma_ptr); aft_list_descriptors(chan); } #endif } #if 0 static void aft_list_descriptors(private_area_t *chan) { u32 reg,cur_dma_ptr,lo_reg; sdla_t *card=chan->card; wan_dma_descr_t *dma_chain; u32 dma_descr; int i; u32 dma_ram_desc; unsigned int dma_cnt=MAX_AFT_DMA_CHAINS; dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); cur_dma_ptr=aft_dmachain_get_rx_dma_addr(reg); DEBUG_TEST("%s: RX Chain DMA List: End=%d Begin=%d Cur=%d \n", chan->if_name, chan->rx_chain_indx, chan->rx_pending_chain_indx, cur_dma_ptr); if (chan->single_dma_chain){ dma_cnt=1; } for (i=0;irx_dma_chain_table[i]; if (!dma_chain){ DEBUG_EVENT("%s:%d Assertion Error !!!!\n", __FUNCTION__,__LINE__); break; } dma_descr=(chan->logic_ch_num<<4) +(dma_chain->index*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_descr,®); dma_descr=(chan->logic_ch_num<<4) +(dma_chain->index*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_RX_DMA_LO_DESCR_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_descr,&lo_reg); DEBUG_EVENT("%s: RX DMA=%d : Go=%u Intr=%u Used=%lu A=0%X R=0x%X L=0x%08X C=%i\n", chan->if_name, dma_chain->index, wan_test_bit(AFT_RXDMA_HI_GO_BIT,®), !wan_test_bit(AFT_RXDMA_HI_INTR_DISABLE_BIT,®), dma_chain->init,dma_descr,reg,lo_reg,(lo_reg&0x1FF)/128); } } #endif #if 0 static void aft_list_tx_descriptors(private_area_t *chan) { u32 reg,cur_dma_ptr,lo_reg; sdla_t *card=chan->card; wan_dma_descr_t *dma_chain; u32 dma_descr; int i; u32 dma_ram_desc; unsigned int dma_cnt=MAX_AFT_DMA_CHAINS; dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); cur_dma_ptr=aft_dmachain_get_tx_dma_addr(reg); DEBUG_TEST("%s: TX Chain DMA List: Cur(End)=%d, Pend(Begin)=%d HWCur=%d\n", chan->if_name, chan->tx_chain_indx, chan->tx_pending_chain_indx, cur_dma_ptr); if (chan->single_dma_chain){ dma_cnt=1; } for (i=0;itx_dma_chain_table[i]; if (!dma_chain){ DEBUG_EVENT("%s:%d Assertion Error !!!!\n", __FUNCTION__,__LINE__); break; } dma_descr=(chan->logic_ch_num<<4) + (dma_chain->index*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_descr,®); dma_descr=(chan->logic_ch_num<<4) + (dma_chain->index*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_TX_DMA_LO_DESCR_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_descr,&lo_reg); DEBUG_EVENT("%s: TX DMA=%d : Go=%u Intr=%u Used=%lu A=0%X R=0x%08X L=0x%08X C=%i\n", chan->if_name, dma_chain->index, wan_test_bit(AFT_TXDMA_HI_GO_BIT,®), wan_test_bit(AFT_TXDMA_HI_INTR_DISABLE_BIT,®) ? 0:1, dma_chain->init, dma_descr, reg,lo_reg,(lo_reg&0x1FF)/128); } } #endif #if 0 static void aft_list_dma_chain_regs(sdla_t *card) { u32 reg; int i; u32 dma_ram_desc; for (i=0; iu.aft.num_of_time_slots;i++){ private_area_t *chan; if (!wan_test_bit(i,&card->u.aft.logic_ch_map)){ continue; } chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; if (!chan){ continue; } if (!wan_test_bit(0,&chan->up)){ continue; } dma_ram_desc=chan->logic_ch_num*4 + AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); DEBUG_EVENT("%s: DMA CHAIN: %i: 0x%08X\n", card->devname,i,reg); } } #endif static void aft_free_rx_descriptors(private_area_t *chan) { u32 reg; sdla_t *card=chan->card; wan_dma_descr_t *dma_chain; u32 dma_descr; int i; unsigned int dma_cnt=MAX_AFT_DMA_CHAINS; if (chan->single_dma_chain){ dma_cnt=1; } if (IS_BRI_CARD(card) && chan->dchan_time_slot >= 0){ return; } for (i=0;irx_dma_chain_table[i]; if (!dma_chain){ DEBUG_EVENT("%s:%d Assertion Error !!!!\n", __FUNCTION__,__LINE__); break; } dma_descr=(chan->logic_ch_num<<4) + (dma_chain->index*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_RX_DMA_HI_DESCR_BASE_REG); DEBUG_TEST("%s:%s: Rx: Freeing Descripors Ch=%ld Desc=0x%X\n", card->devname,chan->if_name,chan->logic_ch_num,dma_descr); card->hw_iface.bus_read_4(card->hw,dma_descr,®); /* If GO bit is set, then the current DMA chain * is in process of being transmitted, thus * all are busy */ reg=0; card->hw_iface.bus_write_4(card->hw,dma_descr,reg); card->hw_iface.busdma_sync( card->hw, dma_chain, 1, chan->single_dma_chain, SDLA_DMA_POSTREAD); card->hw_iface.busdma_unmap( card->hw, dma_chain, SDLA_DMA_POSTREAD); if (dma_chain->skb){ aft_init_requeue_free_skb(chan, dma_chain->skb); } dma_chain->skb=NULL; dma_chain->pkt_error=0; wan_clear_bit(0,&dma_chain->init); } } static void aft_reset_rx_chain_cnt(private_area_t *chan) { u32 dma_ram_desc,reg,cur_dma_ptr; sdla_t *card=chan->card; dma_ram_desc=chan->logic_ch_num*4+ AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); cur_dma_ptr=aft_dmachain_get_rx_dma_addr(reg); chan->rx_pending_chain_indx = chan->rx_chain_indx = cur_dma_ptr; DEBUG_TEST("%s: Setting Rx Index to %d\n", chan->if_name,cur_dma_ptr); } static void aft_reset_tx_chain_cnt(private_area_t *chan) { u32 dma_ram_desc,reg,cur_dma_ptr; sdla_t *card=chan->card; dma_ram_desc=chan->logic_ch_num*4+ AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); cur_dma_ptr=aft_dmachain_get_tx_dma_addr(reg); chan->tx_pending_chain_indx = chan->tx_chain_indx = cur_dma_ptr; DEBUG_TEST("%s: Setting Tx Index to %d\n", chan->if_name,cur_dma_ptr); } static void aft_free_tx_descriptors(private_area_t *chan) { u32 reg,dma_descr; sdla_t *card=chan->card; wan_dma_descr_t *dma_chain; int i; void *skb; unsigned int dma_cnt=MAX_AFT_DMA_CHAINS; if (chan->single_dma_chain){ dma_cnt=1; } if (IS_BRI_CARD(card) && chan->dchan_time_slot >= 0){ return; } DEBUG_TEST("%s:%s: Tx: Freeing Descripors\n",card->devname,chan->if_name); for (i=0;itx_dma_chain_table[i]; if (!dma_chain){ DEBUG_EVENT("%s:%d Assertion Error !!!!\n", __FUNCTION__,__LINE__); break; } dma_descr=(chan->logic_ch_num<<4) +(dma_chain->index*AFT_DMA_INDEX_OFFSET) + AFT_PORT_REG(card,AFT_TX_DMA_HI_DESCR_BASE_REG); DEBUG_TEST("%s:%s: Tx: Freeing Descripors Ch=%ld Desc=0x%X\n", card->devname,chan->if_name,chan->logic_ch_num,dma_descr); reg=0; card->hw_iface.bus_write_4(card->hw,dma_descr,reg); aft_tx_dma_chain_init(chan, dma_chain); } chan->tx_chain_indx = chan->tx_pending_chain_indx; while((skb=wan_skb_dequeue(&chan->wp_tx_complete_list)) != NULL){ wan_skb_free(skb); } } /*===================================================== * Chanalization/Logic Channel utilites * */ void aft_free_logical_channel_num (sdla_t *card, int logic_ch) { wan_clear_bit (logic_ch,&card->u.aft.logic_ch_map); card->u.aft.dev_to_ch_map[logic_ch]=NULL; if (logic_ch >= card->u.aft.top_logic_ch){ int i; card->u.aft.top_logic_ch=AFT_DEFLT_ACTIVE_CH; for (i=0;iu.aft.num_of_time_slots;i++){ if (card->u.aft.dev_to_ch_map[i]){ card->u.aft.top_logic_ch=i; } } aft_dma_max_logic_ch(card); } } void aft_dma_max_logic_ch(sdla_t *card) { u32 reg; u32 max_logic_ch; reg=0; card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),®); max_logic_ch = aft_dmactrl_get_max_logic_ch(reg); DEBUG_TEST("%s: Maximum Logic Ch (current %i) set to %d \n", card->devname, max_logic_ch, card->u.aft.top_logic_ch); if (card->u.aft.top_logic_ch > max_logic_ch) { aft_dmactrl_set_max_logic_ch(®,card->u.aft.top_logic_ch); card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); } } static int aft_tslot_sync_ctrl(sdla_t *card, private_area_t *chan, int mode) { u32 dma_ram_reg,reg; if (chan->hdlc_eng){ return 0; } dma_ram_reg=AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); dma_ram_reg+=(chan->logic_ch_num*4); card->hw_iface.bus_read_4(card->hw, dma_ram_reg, ®); if (mode){ wan_set_bit(AFT_DMACHAIN_RX_SYNC_BIT,®); }else{ wan_clear_bit(AFT_DMACHAIN_RX_SYNC_BIT,®); } card->hw_iface.bus_write_4(card->hw, dma_ram_reg, reg); return 0; } static int aft_read_security(sdla_t *card) { int adptr_security; wan_smp_flag_t flags,smp_flags; if (card->adptr_subtype == AFT_SUBTYPE_SHARK){ /* Shark cards are always channelized */ card->u.aft.security_id=0x01; return 0; } card->hw_iface.hw_lock(card->hw,&smp_flags); wan_spin_lock_irq(&card->wandev.lock,&flags); adptr_security=aft_read_cpld(card,0x09); wan_spin_unlock_irq(&card->wandev.lock,&flags); card->hw_iface.hw_unlock(card->hw,&smp_flags); adptr_security=(adptr_security>>2)&0x03; card->u.aft.security_id=adptr_security; if (adptr_security == 0x00){ DEBUG_EVENT("%s: AFT Security: UnChannelised\n", card->devname); }else if (adptr_security == 0x01){ DEBUG_EVENT("%s: AFT Security: Channelised\n", card->devname); }else{ DEBUG_EVENT("%s: AFT Security: Unknown\n", card->devname); return -EINVAL; } card->u.aft.security_cnt=0; return 0; } static int aft_front_end_mismatch_check(sdla_t * card) { u32 reg; if (card->u.aft.firm_id == AFT_PMC_FE_CORE_ID) { card->hw_iface.bus_read_4(card->hw,AFT_CHIP_CFG_REG, ®); if (IS_T1_CARD(card)){ if (wan_test_bit(AFT_CHIPCFG_TE1_CFG_BIT,®)){ DEBUG_EVENT("%s: Global Cfg Error: Initial front end cfg: E1\n", card->devname); return -EINVAL; } }else{ if (!wan_test_bit(AFT_CHIPCFG_TE1_CFG_BIT,®)){ DEBUG_EVENT("%s: Global Cfg Error: Initial front end cfg: T1\n", card->devname); return -EINVAL; } } } return 0; } static int aft_realign_skb_pkt(private_area_t *chan, netskb_t *skb) { unsigned char *data=wan_skb_data(skb); int len = wan_skb_len(skb); if (len > chan->dma_mru){ DEBUG_EVENT("%s: Critical error: Tx unalign pkt(%d) > MTU buf(%d)!\n", chan->if_name,len,chan->dma_mru); return -ENOMEM; } if (!chan->tx_realign_buf){ chan->tx_realign_buf=wan_malloc(chan->dma_mru); if (!chan->tx_realign_buf){ DEBUG_EVENT("%s: Error: Failed to allocate tx memory buf\n", chan->if_name); return -ENOMEM; }else{ DEBUG_EVENT("%s: AFT Realign buffer allocated Len=%d\n", chan->if_name,chan->dma_mru); } } memcpy(chan->tx_realign_buf,data,len); wan_skb_init(skb,0); wan_skb_trim(skb,0); if (wan_skb_tailroom(skb) < len){ DEBUG_EVENT("%s: Critical error: Tx unalign pkt tail room(%i) < unalign len(%i)!\n", chan->if_name,wan_skb_tailroom(skb),len); return -ENOMEM; } data=wan_skb_put(skb,len); if ((unsigned long)data & 0x03){ /* At this point pkt should be realigned. If not * there is something really wrong! */ return -EINVAL; } memcpy(data,chan->tx_realign_buf,len); chan->opstats.Data_frames_Tx_realign_count++; return 0; } void aft_wdt_set(sdla_t *card, unsigned char val) { u8 reg; u32 wdt_ctrl_reg=AFT_WDT_1TO4_CTRL_REG+card->wandev.comm_port; if (card->wandev.comm_port > 3) { wdt_ctrl_reg=AFT_WDT_4TO8_CTRL_REG+(card->wandev.comm_port%4); } card->hw_iface.bus_read_1(card->hw,wdt_ctrl_reg, ®); aft_wdt_ctrl_set(®,val); card->hw_iface.bus_write_1(card->hw,wdt_ctrl_reg, reg); } void aft_wdt_reset(sdla_t *card) { u8 reg; u32 wdt_ctrl_reg=AFT_WDT_1TO4_CTRL_REG+card->wandev.comm_port; if (card->wandev.comm_port > 3) { wdt_ctrl_reg=AFT_WDT_4TO8_CTRL_REG+(card->wandev.comm_port%4); } card->hw_iface.bus_read_1(card->hw, wdt_ctrl_reg, ®); aft_wdt_ctrl_reset(®); card->hw_iface.bus_write_1(card->hw, wdt_ctrl_reg, reg); } #if defined(__LINUX__) # if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)) static void aft_port_task (void * card_ptr) # else static void aft_port_task (struct work_struct *work) # endif #else static void aft_port_task (void * card_ptr, int arg) #endif { #if defined(__LINUX__) # if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) sdla_t *card = (sdla_t *)container_of(work, sdla_t, u.aft.port_task); # else sdla_t *card = (sdla_t *)card_ptr; # endif #else sdla_t *card = (sdla_t *)card_ptr; #endif wan_smp_flag_t smp_flags; wan_set_bit(CARD_PORT_TASK_RUNNING,&card->wandev.critical); if (wan_test_bit(CARD_PORT_TASK_DOWN,&card->wandev.critical)){ wan_clear_bit(CARD_PORT_TASK_RUNNING,&card->wandev.critical); return; } if (wan_test_bit(CARD_DOWN,&card->wandev.critical)){ wan_clear_bit(CARD_PORT_TASK_RUNNING,&card->wandev.critical); return; } DEBUG_56K("%s: PORT TASK: 0x%X\n", card->devname,card->u.aft.port_task_cmd); #ifdef AFT_IRQ_STAT_DEBUG card->wandev.stats.rx_missed_errors++; #endif if (wan_test_bit(AFT_FE_INTR,&card->u.aft.port_task_cmd)){ DEBUG_TEST("%s: PORT TASK: FE INTER\n", card->devname); card->hw_iface.hw_lock(card->hw,&smp_flags); aft_fe_intr_ctrl(card, 0); front_end_interrupt(card,0,1); wan_clear_bit(AFT_FE_INTR,&card->u.aft.port_task_cmd); aft_fe_intr_ctrl(card, 1); card->hw_iface.hw_unlock(card->hw,&smp_flags); } if (wan_test_bit(AFT_FE_POLL,&card->u.aft.port_task_cmd)){ wan_smp_flag_t smp_irq_flags; DEBUG_TEST("%s: PORT TASK: FE POLL\n", card->devname); card->hw_iface.hw_lock(card->hw,&smp_flags); aft_fe_intr_ctrl(card, 0); if (card->wandev.fe_iface.polling){ card->wandev.fe_iface.polling(&card->fe); } wan_spin_lock_irq(&card->wandev.lock,&smp_irq_flags); handle_front_end_state(card); wan_spin_unlock_irq(&card->wandev.lock,&smp_irq_flags); wan_clear_bit(AFT_FE_POLL,&card->u.aft.port_task_cmd); aft_fe_intr_ctrl(card, 1); card->hw_iface.hw_unlock(card->hw,&smp_flags); } if (wan_test_bit(AFT_FE_LED,&card->u.aft.port_task_cmd)){ DEBUG_TEST("%s: PORT TASK: FE LED\n", card->devname); card->hw_iface.hw_lock(card->hw,&smp_flags); aft_fe_intr_ctrl(card, 0); if (card->wandev.state == WAN_CONNECTED){ aft_hwdev[card->wandev.card_type].aft_led_ctrl(card, WAN_AFT_RED, 0,WAN_AFT_OFF); aft_hwdev[card->wandev.card_type].aft_led_ctrl(card, WAN_AFT_GREEN, 0, WAN_AFT_ON); }else{ aft_hwdev[card->wandev.card_type].aft_led_ctrl(card, WAN_AFT_RED, 0,WAN_AFT_ON); aft_hwdev[card->wandev.card_type].aft_led_ctrl(card, WAN_AFT_GREEN, 0, WAN_AFT_OFF); } wan_clear_bit(AFT_FE_LED,&card->u.aft.port_task_cmd); aft_fe_intr_ctrl(card, 1); card->hw_iface.hw_unlock(card->hw,&smp_flags); } #ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE if (wan_test_bit(AFT_FE_TDM_RBS,&card->u.aft.port_task_cmd)){ int err; DEBUG_TEST("%s: PORT TASK: FE RBS\n", card->devname); card->hw_iface.hw_lock(card->hw,&smp_flags); WAN_TDMV_CALL(rbsbits_poll, (&card->wan_tdmv, card), err); wan_clear_bit(AFT_FE_TDM_RBS,&card->u.aft.port_task_cmd); card->hw_iface.hw_unlock(card->hw,&smp_flags); } #endif #if defined(CONFIG_WANPIPE_HWEC) if (wan_test_bit(AFT_FE_EC_POLL,&card->u.aft.port_task_cmd)){ DEBUG_TEST("%s: PORT TASK: FE EC INTR\n", card->devname); if (card->wandev.ec_dev){ int pending = 0; pending = wanpipe_ec_poll(card->wandev.ec_dev, card); /* Aug 10, 2007 ** If EC poll return 1 (pending), re-schedule port_task again ** (more dtmf events are available) */ if (pending == 1){ WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); }else{ wan_clear_bit(AFT_FE_EC_POLL,&card->u.aft.port_task_cmd); } } } #endif if (wan_test_bit(AFT_FE_RESTART,&card->u.aft.port_task_cmd)){ wan_clear_bit(AFT_FE_RESTART,&card->u.aft.port_task_cmd); if (IS_BRI_CARD(card)) { DEBUG_EVENT("%s: BRI IRQ Restart\n", card->devname); wan_spin_lock_irq(&card->wandev.lock,&smp_flags); wan_clear_bit(0,&card->u.aft.comm_enabled); enable_data_error_intr(card); wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); } else if (card->fe.fe_status == FE_CONNECTED) { DEBUG_EVENT("%s: TDM IRQ Restart\n", card->devname); wan_spin_lock_irq(&card->wandev.lock,&smp_flags); card->fe.fe_status = FE_DISCONNECTED; handle_front_end_state(card); /* BRI has special behaviour, we need to make sure * that restart will trigger interrupts */ wan_clear_bit(0,&card->u.aft.comm_enabled); card->fe.fe_status = FE_CONNECTED; handle_front_end_state(card); wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); } } #if defined(AFT_RTP_SUPPORT) if (wan_test_bit(AFT_RTP_TAP_Q,&card->u.aft.port_task_cmd)){ netskb_t *skb; wan_clear_bit(AFT_FE_RESTART,&card->u.aft.port_task_cmd); while ((skb=wan_skb_dequeue(&card->u.aft.rtp_tap_list))) { dev_queue_xmit(skb); } } #endif wan_clear_bit(CARD_PORT_TASK_RUNNING,&card->wandev.critical); return; } void __aft_fe_intr_ctrl(sdla_t *card, int status) { u32 reg; /* if fe_no_intr is set then only allow disabling of fe interrupt */ if (!card->fe_no_intr || !status){ card->hw_iface.bus_read_4(card->hw,AFT_CHIP_CFG_REG,®); if (status){ wan_set_bit(AFT_CHIPCFG_FE_INTR_CFG_BIT,®); }else{ wan_clear_bit(AFT_CHIPCFG_FE_INTR_CFG_BIT,®); } card->hw_iface.bus_write_4(card->hw,AFT_CHIP_CFG_REG,reg); } } void aft_fe_intr_ctrl(sdla_t *card, int status) { wan_smp_flag_t smp_flags; wan_spin_lock_irq(&card->wandev.lock,&smp_flags); __aft_fe_intr_ctrl(card,status); wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); } static void aft_data_mux_cfg(sdla_t *card) { if (!card->u.aft.cfg.data_mux_map){ card->u.aft.cfg.data_mux_map=AFT_DEFAULT_DATA_MUX_MAP; } card->hw_iface.bus_write_4(card->hw, AFT_DATA_MUX_REG, card->u.aft.cfg.data_mux_map); DEBUG_EVENT("%s: AFT Data Mux Bit Map: 0x%08X\n", card->devname,card->u.aft.cfg.data_mux_map); } static void aft_data_mux_get_cfg(sdla_t *card) { card->hw_iface.bus_read_4(card->hw, AFT_DATA_MUX_REG, &card->u.aft.cfg.data_mux_map); } static int aft_hdlc_repeat_mangle(sdla_t *card,private_area_t *chan, netskb_t *skb, netskb_t **rskb) { unsigned char *buf; api_tx_hdr_t *tx_hdr = (api_tx_hdr_t *)wan_skb_data(skb); if (tx_hdr->wp_api_tx_hdr_hdlc_rpt_len == 0 || tx_hdr->wp_api_tx_hdr_hdlc_rpt_len > 8) { return -1; } *rskb=wan_skb_alloc(128); if (!rskb) { return -1; } buf=wan_skb_put(*rskb,tx_hdr->wp_api_tx_hdr_hdlc_rpt_len); memcpy(buf,tx_hdr->wp_api_tx_hdr_hdlc_rpt_data,tx_hdr->wp_api_tx_hdr_hdlc_rpt_len); wan_skb_pull(skb,sizeof(api_tx_hdr_t)); return 0; } static int aft_ss7_tx_mangle(sdla_t *card,private_area_t *chan, netskb_t *skb) { int ss7_len=0,len=0; unsigned int ss7_ctrl=0; unsigned char *buf; api_tx_hdr_t *tx_hdr = &chan->tx_api_hdr; memcpy(&chan->tx_api_hdr,wan_skb_data(skb),sizeof(api_tx_hdr_t)); wan_skb_pull(skb,sizeof(api_tx_hdr_t)); if (!chan->tx_ss7_realign_buf){ chan->tx_ss7_realign_buf=wan_malloc(chan->dma_mru); if (!chan->tx_ss7_realign_buf){ DEBUG_EVENT("%s: Error: Failed to allocate ss7 tx memory buf\n", chan->if_name); return -ENOMEM; }else{ DEBUG_TEST("%s: AFT SS7 Realign buffer allocated Len=%d\n", chan->if_name,chan->dma_mru); } } memset(chan->tx_ss7_realign_buf,0,chan->dma_mru); memcpy(chan->tx_ss7_realign_buf,wan_skb_data(skb),wan_skb_len(skb)); len=wan_skb_len(skb); /* Align the end of the frame to 32 byte boundary */ ss7_ctrl=(len%4)&AFT_SS7_CTRL_LEN_MASK; if (ss7_ctrl != 0){ len-=len%4; len+=4; } if (tx_hdr->hdr_u.ss7.type == WANOPT_SS7_FISU){ if (chan->cfg.ss7_mode == WANOPT_SS7_MODE_4096){ ss7_len=WANOPT_SS7_FISU_4096_SZ; }else{ ss7_len=WANOPT_SS7_FISU_128_SZ; } wan_clear_bit(AFT_SS7_CTRL_TYPE_BIT,&ss7_ctrl); }else{ ss7_len=chan->cfg.ss7_lssu_size; wan_set_bit(AFT_SS7_CTRL_TYPE_BIT,&ss7_ctrl); } if (tx_hdr->hdr_u.ss7.force_tx){ wan_set_bit(AFT_SS7_CTRL_FORCE_BIT,&ss7_ctrl); }else{ wan_clear_bit(AFT_SS7_CTRL_FORCE_BIT,&ss7_ctrl); } DEBUG_TEST("%s: SS7 DATA = 0x%X 0x%X 0x%X\n", chan->if_name, tx_hdr->hdr_u.ss7.data[0], tx_hdr->hdr_u.ss7.data[1], tx_hdr->hdr_u.ss7.data[2]); memcpy(&chan->tx_ss7_realign_buf[len],tx_hdr->hdr_u.ss7.data,ss7_len); len+=ss7_len; wan_skb_init(skb,0); wan_skb_trim(skb,0); if (wan_skb_tailroom(skb) < len){ DEBUG_EVENT("%s: Critical error: SS7 Tx unalign pkt tail room(%i) < len(%i)!\n", chan->if_name,wan_skb_tailroom(skb),len); return -ENOMEM; } buf=wan_skb_put(skb,len); memcpy(buf,chan->tx_ss7_realign_buf,len); wan_skb_set_csum(skb, ss7_ctrl); #if 0 debug_print_skb_pkt(chan->if_name, wan_skb_data(skb), wan_skb_len(skb), 0); #endif return 0; } #if 0 static void aft_chain_history(private_area_t *chan,u8 end, u8 cur, u8 begin, u8 loc) { dma_history_t *dma_hist = &chan->dma_history[chan->dma_index]; dma_hist->loc=loc; dma_hist->end=end; dma_hist->cur=cur; dma_hist->begin=begin; dma_hist->status=0; if (end > begin){ if (cur > end || cur < begin){ DEBUG_TEST("%s: Rx: Critical: RxPendChain=%d HWDMA=%d RxEndChain=%d\n", chan->if_name,begin,cur,end); dma_hist->status=1; } }else if (end < begin){ if (cur < begin && cur > end){ DEBUG_TEST("%s: Rx: Critical: RxEndChain=%d HWDMA=%d RxPendingChain=%d\n", chan->if_name,begin,cur,end); dma_hist->status=1; } } if (++chan->dma_index >= MAX_DMA_HIST_SIZE){ chan->dma_index=0; } } #endif #if 0 static void aft_display_chain_history(private_area_t *chan) { int start=chan->dma_index; int i; dma_history_t *dma_hist = &chan->dma_history[start]; for (i=0;iloc == 0){ continue; } DEBUG_EVENT("%s: Loc=%02i End=%02d Cur=%02d Beg=%02d St=%s\n", chan->if_name, dma_hist->loc, dma_hist->end, dma_hist->cur, dma_hist->begin, dma_hist->status?"Error":"Ok"); start++; if (start >= MAX_DMA_HIST_SIZE){ start=0; } dma_hist = &chan->dma_history[start]; } } #endif /* * ****************************************************************** * Proc FS function */ static int wan_aft_get_info(void* pcard, struct seq_file *m, int *stop_cnt) { sdla_t *card = (sdla_t*)pcard; if (card->wandev.fe_iface.update_alarm_info){ m->count = WAN_FECALL( &card->wandev, update_alarm_info, (&card->fe, m, stop_cnt)); } if (card->wandev.fe_iface.update_pmon_info){ m->count = WAN_FECALL( &card->wandev, update_pmon_info, (&card->fe, m, stop_cnt)); } return m->count; } static int aft_tdmv_init(sdla_t *card, wandev_conf_t *conf) { int err; int valid_firmware_ver=AFT_TDMV_FRM_VER; err=0; DEBUG_EVENT("%s: TDMV Span = %d : %s\n", card->devname, card->tdmv_conf.span_no, card->tdmv_conf.span_no?"Enabled":"Disabled"); #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) DEBUG_EVENT("%s: TDMV Dummy = %s\n", card->devname, (conf->tdmv_conf.sdla_tdmv_dummy_enable == WANOPT_YES)? "Enabled":"Disabled"); /* Initialize sdla_tdmv_dummy field */ card->sdla_tdmv_dummy = NULL; /* If SDLA TDMV DUMMY option is enabled, register for zaptel timing */ if (conf->tdmv_conf.sdla_tdmv_dummy_enable == WANOPT_YES) { int used_cnt; card->hw_iface.getcfg(card->hw, SDLA_HWCPU_USEDCNT, &used_cnt); if (used_cnt > 1) { DEBUG_EVENT("%s: Error: TDMV Dummy must be configured for first TDM SPAN device\n", card->devname); return -EINVAL; } card->sdla_tdmv_dummy = sdla_tdmv_dummy_register(); if (card->sdla_tdmv_dummy == NULL) { DEBUG_EVENT("%s: Failed to register sdla_tdmv_dummy\n", card->devname); return -EINVAL; } } #else if (conf->tdmv_conf.sdla_tdmv_dummy_enable == WANOPT_YES) { DEBUG_EVENT("%s: TDMV Dummy support not compiled in \n", card->devname); return -EINVAL; } #endif if (card->tdmv_conf.span_no) { if (card->wandev.config_id == WANCONFIG_AFT_ANALOG) { valid_firmware_ver=AFT_MIN_ANALOG_FRMW_VER; } if (card->u.aft.firm_ver < valid_firmware_ver){ DEBUG_EVENT("%s: Error: Obselete AFT Firmware version: %X\n", card->devname,card->u.aft.firm_ver); DEBUG_EVENT("%s: Error: AFT TDMV Support depends on Firmware Ver >= %X\n", card->devname,valid_firmware_ver); return -EINVAL; } } return 0; } /************************************************************** * TDMV VOICE Functions **************************************************************/ #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) static int aft_tdmv_free(sdla_t *card) { if (card->tdmv_conf.span_no && card->wan_tdmv.sc){ int err; WAN_TDMV_CALL(remove, (card), err); } return 0; } #endif static int aft_tdmv_if_init(sdla_t *card, private_area_t *chan, wanif_conf_t *conf) { if (!chan->channelized_cfg){ return 0; } if (!card->tdmv_conf.span_no){ DEBUG_EVENT("%s: Error: TDMV Span No is not set!\n", card->devname); return -EINVAL; } if (chan->cfg.tdmv_master_if){ DEBUG_EVENT("%s: Configuring TDMV Master dev %s\n", card->devname,chan->if_name); /* Initialize a TDM bottom half handler * Optionally used */ WAN_TASKLET_INIT((&chan->common.bh_task),0,wp_tdm_bh,chan); } if (conf->hdlc_streaming == 0){ int err; err=0; aft_hwdev[card->wandev.card_type].aft_fifo_adjust(card,AFT_TDMV_FIFO_LEVEL); if (chan->common.usedby == TDM_VOICE) { #ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE WAN_TDMV_CALL(check_mtu, (card, conf->active_ch, &chan->mtu), err); if (err){ DEBUG_EVENT("Error: TMDV mtu check failed!"); return -EINVAL; } #endif } if (chan->common.usedby == TDM_VOICE_API) { /* If AFT DUMMY is enabled all devices must be configured * with same MTU */ if (aft_tdmapi_mtu_check(card, &chan->mtu) != 0){ switch (chan->mtu) { case 8: case 16: break; case 40: case 80: if (!wan_test_bit(AFT_TDM_GLOBAL_ISR,&card->u.aft.chip_cfg_status)) { /* If Global TDM Feature is not enable then 40 and 80 bytes TDM are not available */ chan->mtu=16; } break; default: chan->mtu=16; break; } } } chan->mru = chan->mtu; card->u.aft.tdmv_mtu = chan->mtu; if (chan->tdmv_zaptel_cfg){ chan->cfg.data_mux=1; } conf->hdlc_streaming=0; chan->tx_realign_buf = NULL; #ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE card->wan_tdmv.brt_enable=0; #endif }else{ chan->cfg.data_mux=0; } #ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE if (chan->tdmv_zaptel_cfg){ int channel; /* The TDMV drivers always starts from number * ZERO. Wanpipe driver doesn't allow timeslot * ZERO. Thus, the active_ch map must me adjusted * before calling tdmv_reg */ if (IS_E1_CARD(card)){ conf->active_ch=conf->active_ch>>1; } if(IS_BRI_CARD(card)){ if(chan->dchan_time_slot >= 0){ conf->active_ch = 0x4<<(WAN_FE_LINENO(&card->fe)*2); /* For the d-chan MUST set ONLY bit 2!! */ } } WAN_TDMV_CALL(reg, (card, &conf->tdmv, conf->active_ch, conf->hwec.enable, chan->common.dev), channel); if (channel < 0){ DEBUG_EVENT("%s: Error: Failed to register TDMV channel!\n", chan->if_name); return -EINVAL; } chan->tdmv_chan=channel; if (card->u.aft.tdmv_dchan_cfg_on_master && chan->cfg.tdmv_master_if){ u32 orig_ch=conf->active_ch; conf->active_ch=card->u.aft.tdmv_dchan_cfg_on_master; WAN_TDMV_CALL(reg, (card, &conf->tdmv, conf->active_ch, conf->hwec.enable, chan->common.dev), channel); if (channel < 0){ DEBUG_EVENT("%s: Error: Failed to register TDMV channel!\n", chan->if_name); return -EINVAL; } card->u.aft.tdmv_chan=channel; card->u.aft.tdmv_dchan_active_ch=conf->active_ch; conf->active_ch=orig_ch; } } #endif return 0; } static int aft_tdmv_if_free(sdla_t *card, private_area_t *chan) { #ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE if (chan->tdmv_zaptel_cfg){ int err; WAN_TDMV_CALL(unreg, (card, chan->time_slot_map), err); if (err){ return err; } if (card->u.aft.tdmv_dchan_cfg_on_master && chan->cfg.tdmv_master_if){ DEBUG_EVENT("%s: Card Unregistering DCHAN\n", card->devname); WAN_TDMV_CALL(unreg, (card, card->u.aft.tdmv_dchan_active_ch), err); card->u.aft.tdmv_dchan_cfg_on_master=0; } } #endif return 0; } #if 0 /* NCDEBUG */ static int gtmp_cnt=0; static void aft_set_channel(sdla_t *card, int ch) { wan_dma_descr_t *tx_dma_chain; u8 *buf; private_area_t *chan=(private_area_t*)card->u.aft.dev_to_ch_map[ch]; if (!chan) return; tx_dma_chain = &chan->tx_dma_chain_table[0]; if (!tx_dma_chain){ return; } buf = (u8*)wan_skb_data(tx_dma_chain->skb); buf[0]=gtmp_cnt++; buf[1]=gtmp_cnt++; buf[2]=gtmp_cnt++; buf[3]=gtmp_cnt++; buf[4]=gtmp_cnt++; buf[5]=gtmp_cnt++; buf[6]=gtmp_cnt++; buf[7]=gtmp_cnt++; card->wandev.stats.tx_packets++; } #endif #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) static int aft_voice_span_rx_tx(sdla_t *card, int rotate) { int err; err=0; if (card->wan_tdmv.sc){ if (rotate) { WAN_TDMV_CALL(buf_rotate, (card,AFT_TDMV_CIRC_BUF,AFT_TDMV_BUF_MASK), err); } if (!card->wandev.ec_enable || card->wandev.ec_enable_map == 0){ WAN_TDMV_CALL(ec_span, (card), err); } WAN_TDMV_CALL(rx_tx_span, (card), err); WAN_TDMV_CALL(is_rbsbits, (&card->wan_tdmv), err); if (err == 1){ wan_set_bit(AFT_FE_TDM_RBS,&card->u.aft.port_task_cmd); WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); } #if !defined(AFT_IRQ_DEBUG) card->wandev.stats.rx_packets++; card->wandev.stats.tx_packets++; #endif } return 0; } #endif static int aft_dma_rx_tdmv(sdla_t *card, private_area_t *chan) { int err; u32 rx_offset=0; u32 tx_offset=0; wan_dma_descr_t *tx_dma_chain; wan_dma_descr_t *rx_dma_chain; u8 *txbuf, *rxbuf; tx_dma_chain = &chan->tx_dma_chain_table[0]; rx_dma_chain = &chan->rx_dma_chain_table[0]; if (!tx_dma_chain || !rx_dma_chain){ DEBUG_EVENT("%s: %s:%d ASSERT ERROR TxDma=%p RxDma=%p\n", card->devname,__FUNCTION__,__LINE__, tx_dma_chain,rx_dma_chain); return -EINVAL; } if (!rx_dma_chain->skb || !tx_dma_chain->skb){ DEBUG_TEST("%s: %s:%d ASSERT ERROR TxSkb=%p RxSkb=%p\n", card->devname,__FUNCTION__,__LINE__, rx_dma_chain->skb,tx_dma_chain->skb); return -EINVAL; } rxbuf = (unsigned char*)rx_dma_chain->dma_virt+rx_offset; txbuf = (unsigned char*)tx_dma_chain->dma_virt+tx_offset; if (wan_test_bit(AFT_TDM_RING_BUF,&card->u.aft.chip_cfg_status)) { rx_offset= AFT_TDMV_CIRC_BUF * card->u.aft.tdm_rx_dma_toggle; tx_offset= AFT_TDMV_CIRC_BUF * card->u.aft.tdm_tx_dma_toggle; rxbuf = (unsigned char*)rx_dma_chain->dma_virt+rx_offset; txbuf = (unsigned char*)tx_dma_chain->dma_virt+tx_offset; } else if (wan_test_bit(AFT_TDM_SW_RING_BUF,&card->u.aft.chip_cfg_status)) { chan->swring.rx_toggle = (chan->swring.rx_toggle + 1) % AFT_DMA_RING_MAX; memcpy(chan->swring.rbuf[chan->swring.rx_toggle].rxdata, rxbuf, chan->mtu); rxbuf= chan->swring.rbuf[chan->swring.rx_toggle].rxdata; memcpy(txbuf, chan->swring.rbuf[chan->swring.tx_toggle].txdata, chan->mtu); chan->swring.tx_toggle = (chan->swring.tx_toggle + 1) % AFT_DMA_RING_MAX; txbuf = chan->swring.rbuf[chan->swring.tx_toggle].txdata; } err=0; #if 0 /*Measure the round trip delay*/ if (!chan->tdmv_rx_delay_cfg){ int i; unsigned char *buf=rx_dma_chain->dma_virt+offset; for (i=0;i<8;i++){ if (buf[i]==0x55){ chan->tdmv_rx_delay_cfg=1; DEBUG_EVENT("%s: Chan=%ld Delay=%d\n", chan->if_name,chan->logic_ch_num, chan->tdmv_rx_delay); break; } chan->tdmv_rx_delay++; } } #endif if (chan->tdmv_zaptel_cfg){ #ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE if (card->wan_tdmv.sc){ #if 0 defined(AFT_TDMV_BH_ENABLE) wan_dma_descr_t *tx_bh_dma_chain = &chan->tx_dma_chain_table[1]; wan_dma_descr_t *rx_bh_dma_chain = &chan->rx_dma_chain_table[1]; if (!rx_bh_dma_chain->skb){ rx_bh_dma_chain->skb=wan_skb_dequeue(&chan->wp_rx_free_list); if (!rx_bh_dma_chain->skb){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: Critical TDM BH no free skb\n", chan->if_name); goto aft_tdm_bh_skip; } } wan_skb_init(rx_bh_dma_chain->skb,16); wan_skb_trim(rx_bh_dma_chain->skb,0); } if (!tx_bh_dma_chain->skb){ tx_bh_dma_chain->skb=wan_skb_dequeue(&chan->wp_rx_free_list); if (!tx_bh_dma_chain->skb){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: Critical TDM BH no free skb\n", chan->if_name); goto aft_tdm_bh_skip; } } wan_skb_init(tx_bh_dma_chain->skb,16); wan_skb_trim(tx_bh_dma_chain->skb,0); } memcpy(wan_skb_data(rx_bh_dma_chain->skb), wan_skb_data(rx_dma_chain->skb),8); memcpy(wan_skb_data(tx_dma_chain->skb), wan_skb_data(tx_bh_dma_chain->skb),8); rx_dma_chain=rx_bh_dma_chain; tx_dma_chain=tx_bh_dma_chain; aft_tdm_bh_skip: #endif DEBUG_TEST ("%s: Calling Rx Chan=%i TdmvChan=%i\n", card->devname,chan->logic_ch_num, chan->tdmv_chan); if (card->wandev.rtp_len && card->wandev.rtp_tap) { card->wandev.rtp_tap(card, IS_T1_CARD(card) ? chan->first_time_slot : chan->first_time_slot-1, rxbuf, txbuf, chan->mtu); } #if 1 WAN_TDMV_CALL(rx_chan, (&card->wan_tdmv,chan->tdmv_chan, rxbuf, txbuf), err); #else #warning "NCDEBUG rx_chan disabled irq" #endif #if 0 if (((u8*)(rx_dma_chain->dma_virt+offset))[0] != 0xFF && ((u8*)(rx_dma_chain->dma_virt+offset))[0] != 0x7F && tx_debug_cnt < 100){ DEBUG_EVENT("%s: %02X %02X %02X %02X %02X %02X %02X %02X\n", card->devname, ((u8*)(rx_dma_chain->dma_virt+offset))[0], ((u8*)(rx_dma_chain->dma_virt+offset))[1], ((u8*)(rx_dma_chain->dma_virt+offset))[2], ((u8*)(rx_dma_chain->dma_virt+offset))[3], ((u8*)(rx_dma_chain->dma_virt+offset))[4], ((u8*)(rx_dma_chain->dma_virt+offset))[5], ((u8*)(rx_dma_chain->dma_virt+offset))[6], ((u8*)(rx_dma_chain->dma_virt+offset))[7]); tx_debug_cnt++; } #endif }else{ return 1; } #endif }else{ #ifdef AFT_TDM_API_SUPPORT wanpipe_tdm_api_rx_tx(&chan->wp_tdm_api_dev, rxbuf, txbuf, chan->mtu); #endif } if (chan->cfg.tdmv_master_if){ u32 reg; int err; err=0; #ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE if (chan->tdmv_zaptel_cfg){ DEBUG_TEST ("%s: Calling Master Rx Tx Chan=%i\n", card->devname,chan->logic_ch_num); #if 0 defined(AFT_TDMV_BH_ENABLE) #warning "AFT A104: TDM Driver compiled in BH mode!" if (WAN_TASKLET_RUNNING((&chan->common.bh_task))){ if (WAN_NET_RATELIMIT()){ DEBUG_EVENT("%s: Critical Error: TDMV BH Overrun!\n", card->devname); } } WAN_WP_TASKLET_SCHEDULE_PER_CPU((&chan->common.bh_task), card->tdmv_conf.span_no); card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),®); wan_set_bit(AFT_DMACTRL_TDMV_RX_TOGGLE,®); wan_set_bit(AFT_DMACTRL_TDMV_TX_TOGGLE,®); card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); #else if (wan_test_bit(AFT_TDM_SW_RING_BUF,&card->u.aft.chip_cfg_status)) { if (!wan_test_bit(AFT_TDM_GLOBAL_ISR,&card->u.aft.chip_cfg_status)) { card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),®); wan_set_bit(AFT_DMACTRL_TDMV_RX_TOGGLE,®); wan_set_bit(AFT_DMACTRL_TDMV_TX_TOGGLE,®); card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); } } #if 1 card->hw_iface.busdma_sync( card->hw, &chan->tx_dma_chain_table[0], MAX_AFT_DMA_CHAINS, chan->single_dma_chain, SDLA_DMA_POSTREAD); WAN_TDMV_CALL(rx_tx_span, (card), err); card->hw_iface.busdma_sync( card->hw, &chan->tx_dma_chain_table[0], MAX_AFT_DMA_CHAINS, chan->single_dma_chain, SDLA_DMA_PREWRITE); card->hw_iface.busdma_sync( card->hw, &chan->rx_dma_chain_table[0], MAX_AFT_DMA_CHAINS, chan->single_dma_chain, SDLA_DMA_PREREAD); #else #warning "NCDEBUG: rx_tx_span disabled irq" #endif if (!wan_test_bit(AFT_TDM_SW_RING_BUF,&card->u.aft.chip_cfg_status) && !wan_test_bit(AFT_TDM_GLOBAL_ISR,&card->u.aft.chip_cfg_status)) { card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),®); wan_set_bit(AFT_DMACTRL_TDMV_RX_TOGGLE,®); wan_set_bit(AFT_DMACTRL_TDMV_TX_TOGGLE,®); card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); } if (card->wan_tdmv.sc){ WAN_TDMV_CALL(is_rbsbits, (&card->wan_tdmv), err); if (err == 1){ wan_set_bit(AFT_FE_TDM_RBS,&card->u.aft.port_task_cmd); WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); } } #endif }else{ #else if (!chan->tdmv_zaptel_cfg){ #endif #ifdef CONFIG_PRODUCT_WANPIPE_TDM_VOICE if (card->sdla_tdmv_dummy) { err = sdla_tdmv_dummy_tick(card->sdla_tdmv_dummy); } #endif if (!wan_test_bit(AFT_TDM_GLOBAL_ISR,&card->u.aft.chip_cfg_status)) { card->hw_iface.bus_read_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),®); wan_set_bit(AFT_DMACTRL_TDMV_RX_TOGGLE,®); wan_set_bit(AFT_DMACTRL_TDMV_TX_TOGGLE,®); card->hw_iface.bus_write_4(card->hw,AFT_PORT_REG(card,AFT_DMA_CTRL_REG),reg); } if (card->wandev.fe_iface.watchdog) { err = card->wandev.fe_iface.watchdog(&card->fe); } } DEBUG_TEST("%s: Master device tx rx %i!\n", card->devname,chan->logic_ch_num); } if (card->wandev.state == WAN_CONNECTED) { chan->opstats.Data_frames_Rx_count++; chan->opstats.Data_bytes_Rx_count+=chan->mru; chan->opstats.Data_frames_Tx_count++; chan->opstats.Data_bytes_Tx_count+=chan->mtu; WAN_NETIF_STATS_INC_RX_PACKETS(&chan->common); //chan->if_stats.rx_packets++; WAN_NETIF_STATS_INC_RX_BYTES(&chan->common,chan->mru); //chan->if_stats.rx_bytes += chan->mru; WAN_NETIF_STATS_INC_TX_PACKETS(&chan->common); //chan->if_stats.tx_packets++; WAN_NETIF_STATS_INC_TX_BYTES(&chan->common,chan->mtu); //chan->if_stats.tx_bytes += chan->mtu; } return 0; } static int aft_fifo_intr_ctrl(sdla_t *card, int ctrl) { u32 reg; card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_RX_FIFO_INTR_PENDING_REG), ®); card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_TX_FIFO_INTR_PENDING_REG), ®); card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); if (ctrl){ wan_set_bit(AFT_LCFG_FIFO_INTR_BIT,®); }else{ wan_clear_bit(AFT_LCFG_FIFO_INTR_BIT,®); } card->hw_iface.bus_write_4(card->hw, AFT_PORT_REG(card,AFT_LINE_CFG_REG), reg); card->u.aft.lcfg_reg=reg; if (!ctrl){ card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_RX_FIFO_INTR_PENDING_REG), ®); card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_TX_FIFO_INTR_PENDING_REG), ®); } return 0; } static int aft_tdm_intr_ctrl(sdla_t *card, int ctrl) { u32 reg; card->hw_iface.bus_read_4(card->hw, AFT_PORT_REG(card,AFT_LINE_CFG_REG), ®); if (ctrl){ wan_set_bit(AFT_LCFG_TDMV_INTR_BIT,®); }else{ wan_clear_bit(AFT_LCFG_TDMV_INTR_BIT,®); } card->hw_iface.bus_write_4(card->hw, AFT_PORT_REG(card,AFT_LINE_CFG_REG), reg); card->u.aft.lcfg_reg=reg; return 0; } #if defined(AFT_API_SUPPORT) static int wan_aft_api_ioctl(sdla_t *card, private_area_t *chan, char *user_data) { api_tx_hdr_t tx_hdr; wan_event_ctrl_t event_ctrl; int err = -EINVAL; if (WAN_COPY_FROM_USER(&tx_hdr, user_data, sizeof(api_tx_hdr_t))){ DEBUG_EVENT("%s: Failed to copy data from user space!\n", card->devname); return -EFAULT; } memset(&event_ctrl, 0, sizeof(wan_event_ctrl_t)); switch(tx_hdr.wp_api_tx_hdr_event_type){ case WP_API_EVENT_DTMF: DEBUG_TEST("%s: %s HW DTMF events!\n", card->devname, (tx_hdr.wp_api_tx_hdr_event_mode==WP_API_EVENT_ENABLE)? "Enable": "Disable"); event_ctrl.type = WAN_EVENT_EC_DTMF; event_ctrl.ts_map = tx_hdr.wp_api_tx_hdr_event_channel; if (tx_hdr.wp_api_tx_hdr_event_mode == WP_API_EVENT_ENABLE){ event_ctrl.mode = WAN_EVENT_ENABLE; }else{ event_ctrl.mode = WAN_EVENT_DISABLE; } err = aft_event_ctrl(chan, &event_ctrl); break; case WP_API_EVENT_RM_DTMF: DEBUG_TEST("%s: %s RM DTMF events!\n", card->devname, (tx_hdr.wp_api_tx_hdr_event_mode==WP_API_EVENT_ENABLE)? "Enable": "Disable"); event_ctrl.type = WAN_EVENT_RM_DTMF; event_ctrl.mod_no = tx_hdr.wp_api_tx_hdr_event_channel; if (tx_hdr.wp_api_tx_hdr_event_mode == WP_API_EVENT_ENABLE){ event_ctrl.mode = WAN_EVENT_ENABLE; }else{ event_ctrl.mode = WAN_EVENT_DISABLE; } err = aft_event_ctrl(chan, &event_ctrl); break; case WP_API_EVENT_RXHOOK: DEBUG_TEST("%s: %s OFFHOOK/ONHOOK events!\n", card->devname, (tx_hdr.wp_api_tx_hdr_event_mode==WP_API_EVENT_ENABLE)? "Enable": "Disable"); event_ctrl.type = WAN_EVENT_RM_LC; event_ctrl.mod_no = tx_hdr.wp_api_tx_hdr_event_channel; if (tx_hdr.wp_api_tx_hdr_event_mode == WP_API_EVENT_ENABLE){ event_ctrl.mode = WAN_EVENT_ENABLE; }else{ event_ctrl.mode = WAN_EVENT_DISABLE; } err = aft_event_ctrl(chan, &event_ctrl); break; case WP_API_EVENT_RING: DEBUG_TEST("%s: %s RING events!\n", card->devname, (tx_hdr.wp_api_tx_hdr_event_mode==WP_API_EVENT_ENABLE)? "Enable": "Disable"); event_ctrl.type = WAN_EVENT_RM_RING; event_ctrl.mod_no = tx_hdr.wp_api_tx_hdr_event_channel; if (tx_hdr.wp_api_tx_hdr_event_mode == WP_API_EVENT_ENABLE){ event_ctrl.mode = WAN_EVENT_ENABLE; }else{ event_ctrl.mode = WAN_EVENT_DISABLE; } err = aft_event_ctrl(chan, &event_ctrl); break; case WP_API_EVENT_TONE: DEBUG_TEST("%s: %s TONE events!\n", card->devname, (tx_hdr.wp_api_tx_hdr_event_mode==WP_API_EVENT_ENABLE)? "Enable": "Disable"); event_ctrl.type = WAN_EVENT_RM_TONE; event_ctrl.mod_no = tx_hdr.wp_api_tx_hdr_event_channel; switch(tx_hdr.wp_api_tx_hdr_event_tone){ case WP_API_EVENT_TONE_DIAL: event_ctrl.tone = WAN_EVENT_TONE_DIAL; break; case WP_API_EVENT_TONE_BUSY: event_ctrl.tone = WAN_EVENT_TONE_BUSY; break; case WP_API_EVENT_TONE_RING: event_ctrl.tone = WAN_EVENT_TONE_RING; break; case WP_API_EVENT_TONE_CONGESTION: event_ctrl.tone = WAN_EVENT_TONE_CONGESTION; break; default: if (tx_hdr.wp_api_tx_hdr_event_mode == WP_API_EVENT_ENABLE){ DEBUG_EVENT("%s: Unsupported tone type %d!\n", card->devname, tx_hdr.wp_api_tx_hdr_event_tone); return -EINVAL; } break; } if (tx_hdr.wp_api_tx_hdr_event_mode == WP_API_EVENT_ENABLE){ event_ctrl.mode = WAN_EVENT_ENABLE; }else{ event_ctrl.mode = WAN_EVENT_DISABLE; } err = aft_event_ctrl(chan, &event_ctrl); break; case WP_API_EVENT_TXSIG_KEWL: DEBUG_EVENT("%s: TXSIG KEWL for module %d!\n", card->devname, tx_hdr.wp_api_tx_hdr_event_channel); event_ctrl.type = WAN_EVENT_RM_TXSIG_KEWL; event_ctrl.mod_no = tx_hdr.wp_api_tx_hdr_event_channel; err = aft_event_ctrl(chan, &event_ctrl); break; case WP_API_EVENT_TXSIG_START: DEBUG_EVENT("%s: TXSIG START for module %d!\n", card->devname, tx_hdr.wp_api_tx_hdr_event_channel); event_ctrl.type = WAN_EVENT_RM_TXSIG_START; event_ctrl.mod_no = tx_hdr.wp_api_tx_hdr_event_channel; err = aft_event_ctrl(chan, &event_ctrl); break; case WP_API_EVENT_TXSIG_OFFHOOK: DEBUG_EVENT("%s: RM TXSIG OFFHOOK for module %d!\n", card->devname, tx_hdr.wp_api_tx_hdr_event_channel); event_ctrl.type = WAN_EVENT_RM_TXSIG_OFFHOOK; event_ctrl.mod_no = tx_hdr.wp_api_tx_hdr_event_channel; err = aft_event_ctrl(chan, &event_ctrl); break; case WP_API_EVENT_TXSIG_ONHOOK: DEBUG_EVENT("%s: RM TXSIG ONHOOK for module %d!\n", card->devname, tx_hdr.wp_api_tx_hdr_event_channel); event_ctrl.type = WAN_EVENT_RM_TXSIG_ONHOOK; event_ctrl.mod_no = tx_hdr.wp_api_tx_hdr_event_channel; err = aft_event_ctrl(chan, &event_ctrl); break; case WP_API_EVENT_ONHOOKTRANSFER: DEBUG_EVENT("%s: RM ONHOOKTRANSFER for module %d!\n", card->devname, tx_hdr.wp_api_tx_hdr_event_channel); event_ctrl.type = WAN_EVENT_RM_ONHOOKTRANSFER; event_ctrl.mod_no = tx_hdr.wp_api_tx_hdr_event_channel; event_ctrl.ohttimer = tx_hdr.wp_api_tx_hdr_event_ohttimer; err = aft_event_ctrl(chan, &event_ctrl); break; case WP_API_EVENT_SETPOLARITY: DEBUG_EVENT("%s: RM SETPOLARITY for module %d!\n", card->devname, tx_hdr.wp_api_tx_hdr_event_channel); event_ctrl.type = WAN_EVENT_RM_SETPOLARITY; event_ctrl.mod_no = tx_hdr.wp_api_tx_hdr_event_channel; event_ctrl.polarity = tx_hdr.wp_api_tx_hdr_event_polarity; err = aft_event_ctrl(chan, &event_ctrl); break; case WP_API_EVENT_RING_DETECT: DEBUG_EVENT("%s: %s: RM RING DETECT events for module %d!\n", card->devname, WP_API_EVENT_MODE_DECODE(tx_hdr.wp_api_tx_hdr_event_mode), tx_hdr.wp_api_tx_hdr_event_channel); event_ctrl.type = WAN_EVENT_RM_RING_DETECT; event_ctrl.mod_no = tx_hdr.wp_api_tx_hdr_event_channel; if (tx_hdr.wp_api_tx_hdr_event_mode == WP_API_EVENT_ENABLE){ event_ctrl.mode = WAN_EVENT_ENABLE; }else{ event_ctrl.mode = WAN_EVENT_DISABLE; } err = aft_event_ctrl(chan, &event_ctrl); break; default: DEBUG_EVENT("%s: Unknown event type %02X!\n", card->devname, tx_hdr.wp_api_tx_hdr_event_type); err = -EINVAL; break; } return err; } #endif #if defined(AFT_API_SUPPORT) static void wan_aft_api_dtmf (void* card_id, wan_event_t *event) { sdla_t *card = (sdla_t*)card_id; private_area_t *chan = NULL; netskb_t *new_skb = NULL; api_rx_hdr_t *rx_hdr; int i; if (event->type == WAN_EVENT_EC_DTMF){ DEBUG_TEST("%s: Received DTMF Event at AFT API (%d:%c:%s:%s)!\n", card->devname, event->channel, event->digit, (event->dtmf_port == WAN_EC_CHANNEL_PORT_ROUT)?"ROUT":"SOUT", (event->dtmf_type == WAN_EC_TONE_PRESENT)?"PRESENT":"STOP"); }else if (event->type == WAN_EVENT_RM_DTMF){ DEBUG_TEST("%s: Received DTMF Event at AFT API (%d:%c)!\n", card->devname, event->channel, event->digit); } for (i=0;iu.aft.num_of_time_slots;i++){ if (wan_test_bit(i,&card->u.aft.logic_ch_map)){ unsigned long ts_map; chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; ts_map = chan->time_slot_map; if (IS_T1_CARD(card) || IS_FXOFXS_CARD(card)){ /* Convert active_ch bit map to user */ ts_map = ts_map << 1; } if (wan_test_bit(event->channel,&ts_map)){ break; } chan = NULL; } } if (chan == NULL){ DEBUG_EVENT("%s: Failed to find channel device (channel=%d)!\n", card->devname, event->channel); return; } #if defined(__LINUX__) new_skb=wan_skb_alloc(sizeof(api_rx_element_t)); if (new_skb == NULL) return; rx_hdr=(api_rx_hdr_t*)wan_skb_put(new_skb,sizeof(api_rx_element_t)); memset(rx_hdr,0,sizeof(api_rx_hdr_t)); rx_hdr->error_flag = 0; rx_hdr->event_type = WP_API_EVENT_DTMF; rx_hdr->wp_api_rx_hdr_event_channel = event->channel; rx_hdr->wp_api_rx_hdr_event_dtmf_digit = event->digit; rx_hdr->wp_api_rx_hdr_event_dtmf_type = event->dtmf_type; rx_hdr->wp_api_rx_hdr_event_dtmf_port = event->dtmf_port; new_skb->protocol = htons(PVC_PROT); wan_skb_reset_mac_header(new_skb); new_skb->dev = chan->common.dev; new_skb->pkt_type = WAN_PACKET_DATA; //if (wan_api_rx_dtmf(chan,new_skb) != 0){ if (wan_api_rx(chan,new_skb) != 0){ DEBUG_EVENT("%s: Failed to send up DTMF event!\n", card->devname); wan_skb_free(new_skb); } #else DEBUG_EVENT("%s:%s: DTMF Event report is not supported!\n", card->devname, chan->if_name); new_skb = NULL; rx_hdr = NULL; #endif return; } #endif #if defined(AFT_API_SUPPORT) static void wan_aft_api_hook (void* card_id, wan_event_t *event) { sdla_t *card = (sdla_t*)card_id; private_area_t *chan = NULL; netskb_t *new_skb = NULL; api_rx_hdr_t *rx_hdr; int i; if (event->type != WAN_EVENT_RM_LC){ DEBUG_EVENT("ERROR: %s: Invalid Event type (%04X)!\n", card->devname, event->type); return; } DEBUG_EVENT("%s: Received %s (%d) Event at AFT API (%d)!\n", card->devname, WAN_EVENT_RXHOOK_DECODE(event->rxhook), event->rxhook, event->channel); for (i=0;iu.aft.num_of_time_slots;i++){ if (wan_test_bit(i,&card->u.aft.logic_ch_map)){ unsigned long ts_map; chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; ts_map = chan->time_slot_map; if (IS_T1_CARD(card) || IS_FXOFXS_CARD(card)){ /* Convert active_ch bit map to user */ ts_map = ts_map << 1; } if (wan_test_bit(event->channel,&ts_map)){ break; } chan = NULL; } } if (chan == NULL){ DEBUG_EVENT("%s: Failed to find channel device (channel=%d)!\n", card->devname, event->channel); return; } #if defined(__LINUX__) new_skb=wan_skb_alloc(sizeof(api_rx_element_t)); if (new_skb == NULL) return; rx_hdr=(api_rx_hdr_t*)wan_skb_put(new_skb,sizeof(api_rx_element_t)); memset(rx_hdr,0,sizeof(api_rx_hdr_t)); rx_hdr->error_flag = 0; rx_hdr->event_type = WP_API_EVENT_RXHOOK; rx_hdr->wp_api_rx_hdr_event_channel = event->channel; if (event->rxhook == WAN_EVENT_RXHOOK_OFF){ rx_hdr->wp_api_rx_hdr_event_rxhook_state = WP_API_EVENT_RXHOOK_OFF; }else if (event->rxhook == WAN_EVENT_RXHOOK_ON){ rx_hdr->wp_api_rx_hdr_event_rxhook_state = WP_API_EVENT_RXHOOK_ON; } new_skb->protocol = htons(PVC_PROT); wan_skb_reset_mac_header(new_skb); new_skb->dev = chan->common.dev; new_skb->pkt_type = WAN_PACKET_DATA; if (wan_api_rx(chan,new_skb) != 0){ DEBUG_EVENT("%s: Failed to send up HOOK event!\n", card->devname); wan_skb_free(new_skb); } #else DEBUG_EVENT("%s:%s: RXHOOK Event report is not supported!\n", card->devname, chan->if_name); new_skb = NULL; rx_hdr = NULL; #endif return; } #endif #if defined(AFT_API_SUPPORT) static void wan_aft_api_ringtrip (void* card_id, wan_event_t *event) { sdla_t *card = (sdla_t*)card_id; DEBUG_EVENT("%s: Unsupported event!\n", card->devname); return; } #endif #if defined(AFT_API_SUPPORT) static void wan_aft_api_ringdetect (void* card_id, wan_event_t *event) { sdla_t *card = (sdla_t*)card_id; private_area_t *chan = NULL; netskb_t *new_skb = NULL; api_rx_hdr_t *rx_hdr; int i; if (event->type != WAN_EVENT_RM_RING_DETECT){ DEBUG_EVENT("ERROR: %s: Invalid Event type (%04X)!\n", card->devname, event->type); return; } DEBUG_EVENT("%s: Received Ring Detect %s (%d) Event at AFT API (%d)!\n", card->devname, WAN_EVENT_RING_DECODE(event->ring_mode), event->ring_mode, event->channel); for (i=0;iu.aft.num_of_time_slots;i++){ if (wan_test_bit(i,&card->u.aft.logic_ch_map)){ unsigned long ts_map; chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; ts_map = chan->time_slot_map; if (IS_T1_CARD(card) || IS_FXOFXS_CARD(card)){ /* Convert active_ch bit map to user */ ts_map = ts_map << 1; } if (wan_test_bit(event->channel,&ts_map)){ break; } chan = NULL; } } if (chan == NULL){ DEBUG_EVENT("%s: Failed to find channel device (channel=%d)!\n", card->devname, event->channel); return; } #if defined(__LINUX__) new_skb=wan_skb_alloc(sizeof(api_rx_element_t)); if (new_skb == NULL) return; rx_hdr=(api_rx_hdr_t*)wan_skb_put(new_skb,sizeof(api_rx_element_t)); memset(rx_hdr,0,sizeof(api_rx_hdr_t)); rx_hdr->error_flag = 0; rx_hdr->event_type = WP_API_EVENT_RING_DETECT; rx_hdr->wp_api_rx_hdr_event_channel = event->channel; if (event->ring_mode == WAN_EVENT_RING_PRESENT){ rx_hdr->wp_api_rx_hdr_event_ringdetect_state = WAN_EVENT_RING_PRESENT; }else if (event->ring_mode == WAN_EVENT_RING_STOP){ rx_hdr->wp_api_rx_hdr_event_ringdetect_state = WAN_EVENT_RING_STOP; }else{ DEBUG_EVENT("%s: Invalid Rind Detect mode (%d)!\n", card->devname, event->ring_mode); wan_skb_free(new_skb); return ; } new_skb->protocol = htons(PVC_PROT); wan_skb_reset_mac_header(new_skb); new_skb->dev = chan->common.dev; new_skb->pkt_type = WAN_PACKET_DATA; if (wan_api_rx(chan,new_skb) != 0){ DEBUG_EVENT("%s: Failed to send up HOOK event!\n", card->devname); wan_skb_free(new_skb); } #else DEBUG_EVENT("%s:%s: RXHOOK Event report is not supported!\n", card->devname, chan->if_name); new_skb = NULL; rx_hdr = NULL; #endif return; } #endif #if 0 static void wp_tdmv_api_chan_rx_tx(sdla_t *card, private_area_t *chan, unsigned char *rxdata, unsigned char *txdata) { #if defined(__LINUX__) unsigned char *buf; if (!card->u.aft.tdmv_api_rx){ card->u.aft.tdmv_api_rx=wan_skb_alloc(card->u.aft.tdmv_mtu); if (!card->u.aft.tdmv_api_rx){ WAN_NETIF_STATS_INC_RX_ERRORS(&chan->common); //++chan->if_stats.rx_errors; goto wp_tdmv_api_rx_tx_chan_skip_rx; } } if (wan_skb_len(card->u.aft.tdmv_api_rx) > (card->u.aft.tdmv_mtu-chan->mru)){ /* CRITICAL ERROR: We cannot fit the all timeslots into this * packet */ WAN_NETIF_STATS_INC_RX_ERRORS(&chan->common); //++chan->if_stats.rx_errors; goto wp_tdmv_api_rx_tx_chan_skip_rx; } buf=wan_skb_put(card->u.aft.tdmv_api_rx, chan->mru); memcpy(buf,rxdata,chan->mru); WAN_NETIF_STATS_INC_RX_DROPPED(&chan->common); //++chan->if_stats.rx_dropped; wp_tdmv_api_rx_tx_chan_skip_rx: if (!card->u.aft.tdmv_api_tx){ card->u.aft.tdmv_api_tx=wan_skb_dequeue(&card->u.aft.tdmv_api_tx_list); if (!card->u.aft.tdmv_api_tx){ /* No tx packet, send idle frames */ WAN_NETIF_STATS_INC_TX_CARRIER_ERRORS(&chan->common); //++chan->if_stats.tx_carrier_errors; memset(txdata,chan->idle_flag,chan->mtu); return; } } if (wan_skb_len(card->u.aft.tdmv_api_tx) < chan->mtu){ /* CRITICAL ERROR: * The tx api packet must have info for all * timeslots */ memset(txdata,chan->idle_flag,chan->mtu); WAN_NETIF_STATS_INC_TX_ERRORS(&chan->common); //++chan->if_stats.tx_errors; return; } buf=wan_skb_data(card->u.aft.tdmv_api_tx); memcpy(txdata,buf,chan->mtu); wan_skb_pull(card->u.aft.tdmv_api_tx,chan->mtu); WAN_NETIF_STATS_INC_TX_DROPPED(&chan->common); //++chan->if_stats.tx_dropped; #endif return; } /*================================================ * wp_tdmv_api_rx_tx * * */ static void wp_tdmv_api_rx_tx (sdla_t *card, private_area_t *chan) { #if defined(__LINUX__) chan=(private_area_t*)wan_netif_priv(chan->common.dev); if (!card->u.aft.tdmv_api_rx){ /* CRITICAL ERROR: * There should be an rx api packet here */ goto wp_tdmv_api_rx_tx_skip_rx; } if (wan_skb_len(card->u.aft.tdmv_api_rx) != card->u.aft.tdmv_mtu){ wan_skb_free(card->u.aft.tdmv_api_rx); card->u.aft.tdmv_api_rx=NULL; goto wp_tdmv_api_rx_tx_skip_rx; } if (wan_skb_headroom(card->u.aft.tdmv_api_rx) >= sizeof(api_rx_hdr_t)){ api_rx_hdr_t *rx_hdr= (api_rx_hdr_t*)skb_push(card->u.aft.tdmv_api_rx, sizeof(api_rx_hdr_t)); memset(rx_hdr,0,sizeof(api_rx_hdr_t)); }else{ wan_skb_free(card->u.aft.tdmv_api_rx); card->u.aft.tdmv_api_rx=NULL; goto wp_tdmv_api_rx_tx_skip_rx; } card->u.aft.tdmv_api_rx->protocol = htons(PVC_PROT); card->u.aft.tdmv_api_rx->mac.raw = card->u.aft.tdmv_api_rx->data; card->u.aft.tdmv_api_rx->dev = chan->common.dev; card->u.aft.tdmv_api_rx->pkt_type = WAN_PACKET_DATA; if (wan_api_rx(chan,card->u.aft.tdmv_api_rx) != 0){ wan_skb_free(card->u.aft.tdmv_api_rx); } card->u.aft.tdmv_api_rx=NULL; wp_tdmv_api_rx_tx_skip_rx: if (card->u.aft.tdmv_api_tx){ if (wan_skb_len(card->u.aft.tdmv_api_tx) != 0){ /*CRITICAL ERROR: * Length must be zero, because we pulled * all timeslots out*/ } wan_skb_free(card->u.aft.tdmv_api_tx); card->u.aft.tdmv_api_tx=NULL; if (WAN_NETIF_QUEUE_STOPPED(chan->common.dev)){ WAN_NETIF_WAKE_QUEUE(chan->common.dev); wan_wakeup_api(chan); } } #endif return; } #endif #if defined(__LINUX__) /*============================================= * aft_set_ss7_force_rx * * Force the firmware to pass up a single * ss7 packet. Otherwise, the ss7 engine * will wait for the next different packet. */ static void aft_set_ss7_force_rx(sdla_t *card, private_area_t *chan) { u32 reg, dma_ram_desc; if (wan_test_and_set_bit(0,&chan->ss7_force_rx)){ DEBUG_TEST("%s: FORCE BUSY RX\n",card->devname); return; } dma_ram_desc=chan->logic_ch_num*4+AFT_PORT_REG(card,AFT_DMA_CHAIN_RAM_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_ram_desc,®); if (wan_test_bit(AFT_DMACHAIN_SS7_FORCE_RX,®)){ wan_clear_bit(AFT_DMACHAIN_SS7_FORCE_RX,®); }else{ wan_set_bit(AFT_DMACHAIN_SS7_FORCE_RX,®); } card->hw_iface.bus_write_4(card->hw,dma_ram_desc,reg); DEBUG_TEST("%s: FORCE RX\n",card->devname); } #endif /*============================================= * aft_clear_ss7_force_rx * * Reset the ss7 force rx logic. * This must be done before trying to enable * force rx again. * Note: That first_time_slot must be cleared LAST. * Thus the reverse clear order. */ static void aft_clear_ss7_force_rx(sdla_t *card, private_area_t *chan) { wan_clear_bit(0,&chan->ss7_force_rx); } #if defined(AFT_API_SUPPORT) || defined(AFT_TDM_API_SUPPORT) static int aft_event_ctrl(void *chan_ptr, wan_event_ctrl_t *p_event) { sdla_t *card = NULL; private_area_t *chan = (private_area_t *)chan_ptr; wan_event_ctrl_t *event_ctrl; int err = -EINVAL; card = chan->card; event_ctrl = wan_malloc(sizeof(wan_event_ctrl_t)); if (event_ctrl == NULL){ DEBUG_EVENT("%s: Failed to allocate event control!\n", card->devname); return -EFAULT; } memset(event_ctrl, 0, sizeof(wan_event_ctrl_t)); memcpy(event_ctrl, p_event, sizeof(wan_event_ctrl_t)); if (event_ctrl->type == WAN_EVENT_EC_DTMF && card->wandev.ec_dev){ #if defined(CONFIG_WANPIPE_HWEC) DEBUG_TEST("%s: Event control request EC_DTMF...\n", chan->if_name); err = wanpipe_ec_event_ctrl(card->wandev.ec_dev, card, event_ctrl); #endif }else if (chan->card->wandev.fe_iface.event_ctrl){ DEBUG_TEST("%s: FE Event control request...\n", chan->if_name); err = chan->card->wandev.fe_iface.event_ctrl( &chan->card->fe, event_ctrl); }else{ DEBUG_TEST("%s: Unsupported event control request (%lX)\n", chan->if_name, event_ctrl->type); } if (err){ if (event_ctrl) wan_free(event_ctrl); } return err; } #endif #ifdef AFT_TDM_API_SUPPORT static int aft_read_rbs_bits(void *chan_ptr, u32 ch, u8 *rbs_bits) { private_area_t *chan = (private_area_t *)chan_ptr; wan_smp_flag_t flags; if (!chan_ptr){ return -EINVAL; } chan->card->hw_iface.hw_lock(chan->card->hw,&flags); *rbs_bits = chan->card->wandev.fe_iface.read_rbsbits( &chan->card->fe, chan->logic_ch_num+1, WAN_TE_RBS_UPDATE); chan->card->hw_iface.hw_unlock(chan->card->hw,&flags); return 0; } static int aft_write_rbs_bits(void *chan_ptr, u32 ch, u8 rbs_bits) { private_area_t *chan = (private_area_t *)chan_ptr; wan_smp_flag_t flags; int err; if (!chan_ptr){ return -EINVAL; } chan->card->hw_iface.hw_lock(chan->card->hw,&flags); err = chan->card->wandev.fe_iface.set_rbsbits(&chan->card->fe, chan->logic_ch_num+1, rbs_bits); chan->card->hw_iface.hw_unlock(chan->card->hw,&flags); return err; } static int aft_write_hdlc_frame(void *chan_ptr, netskb_t *skb) { private_area_t *chan = (private_area_t *)chan_ptr; sdla_t *card=chan->card; wan_smp_flag_t smp_flags; int err=-EINVAL; private_area_t *top_chan; if (!chan_ptr || !chan->common.dev || !card){ WAN_ASSERT(1); return -EINVAL; } if (wan_skb_len(skb) > chan->mtu) { return -EINVAL; } if (card->u.aft.tdmv_dchan){ top_chan=wan_netif_priv(chan->common.dev); }else{ top_chan=chan; } #if defined(CONFIG_PRODUCT_WANPIPE_AFT_BRI) if(IS_BRI_CARD(card)){ if(chan->dchan_time_slot >= 0){ #if 0 err=aft_bri_dchan_transmit(card, chan, NULL, 0); if(err){ /* still busy transmitting */ return -EBUSY; } #endif /* NOTE: BRI dchan tx has to be done inside IRQ lock. It allows to synchronize access to SPI on the card. */ card->hw_iface.hw_lock(card->hw,&smp_flags); err=aft_bri_dchan_transmit(card, chan, wan_skb_data(skb), wan_skb_len(skb)); card->hw_iface.hw_unlock(card->hw,&smp_flags); if (err == 0) { wan_capture_trace_packet(chan->card, &top_chan->trace_info, skb,TRC_OUTGOING_FRM); wan_skb_free(skb); err = 0; } else { err = -EBUSY; } } else { /* On b-channel data is transmitted using AFT DMA. */ DEBUG_EVENT("%s: Error: BRI TX on non-D-channel!!\n", card->devname); wan_skb_free(skb); err = 0; } return err; } #endif wan_spin_lock_irq(&card->wandev.lock, &smp_flags); if (wan_skb_queue_len(&chan->wp_tx_pending_list) > chan->max_tx_bufs){ aft_dma_tx(card,chan); wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); return -EBUSY; } wan_skb_unlink(skb); wan_skb_queue_tail(&chan->wp_tx_pending_list,skb); aft_dma_tx(card,chan); err=0; wan_spin_unlock_irq(&card->wandev.lock, &smp_flags); return err; } #endif static int aft_tdm_ring_rsync(sdla_t *card) { int i; private_area_t *chan; for (i=0; iu.aft.num_of_time_slots;i++){ if (!wan_test_bit(i,&card->u.aft.tdm_logic_ch_map)){ continue; } chan=(private_area_t*)card->u.aft.dev_to_ch_map[i]; if (!chan){ DEBUG_EVENT("%s: Error: No Dev for Rx logical ch=%d\n", card->devname,i); continue; } if (chan->channelized_cfg && !chan->hdlc_eng && chan->cfg.tdmv_master_if){ u32 lo_reg; u32 dma_descr=(chan->logic_ch_num<<4) + AFT_PORT_REG(card,AFT_RX_DMA_LO_DESCR_BASE_REG); card->hw_iface.bus_read_4(card->hw,dma_descr,&lo_reg); lo_reg=(lo_reg&AFT_TDMV_BUF_MASK)/AFT_TDMV_CIRC_BUF; if (card->wandev.ec_enable){ /* HW EC standard */ if (lo_reg > 0) { card->u.aft.tdm_rx_dma_toggle = lo_reg-1; } else { card->u.aft.tdm_rx_dma_toggle = 3; } } else { /* Software ec moves spike to 8bytes */ card->u.aft.tdm_rx_dma_toggle=lo_reg+1; if (card->u.aft.tdm_rx_dma_toggle > 3) { card->u.aft.tdm_rx_dma_toggle=0; } } if (lo_reg < 3) { card->u.aft.tdm_tx_dma_toggle = lo_reg+1; } else { card->u.aft.tdm_tx_dma_toggle = 0; } card->rsync_timeout=0; DEBUG_EVENT("%s: Card TDM Rsync Rx=%i Tx=%i\n", card->devname, card->u.aft.tdm_rx_dma_toggle, card->u.aft.tdm_tx_dma_toggle); } } return 0; } static void aft_critical_shutdown (sdla_t *card) { DEBUG_EVENT("%s: Error: Card Critically Shutdown!\n", card->devname); if (card->wandev.fe_iface.pre_release){ card->wandev.fe_iface.pre_release(&card->fe); } if (card->wandev.fe_iface.unconfig){ card->wandev.fe_iface.unconfig(&card->fe); } disable_data_error_intr(card,DEVICE_DOWN); wan_set_bit(CARD_DOWN,&card->wandev.critical); port_set_state(card,WAN_DISCONNECTED); aft_hwdev[card->wandev.card_type].aft_led_ctrl(card, WAN_AFT_RED, 0,WAN_AFT_ON); aft_hwdev[card->wandev.card_type].aft_led_ctrl(card, WAN_AFT_GREEN, 0, WAN_AFT_OFF); } static int aft_hwec_config (sdla_t *card, private_area_t *chan, wanif_conf_t *conf, int ctrl) { int err = 0; int fe_chan = 0; unsigned int tdmv_hwec_option=0; /* If not hardware echo nothing to configure */ if (!card->wandev.ec_enable) { return 0; } if (conf) { tdmv_hwec_option=conf->hwec.enable; } if (chan->common.usedby == TDM_VOICE_API || chan->common.usedby == TDM_VOICE){ /* Nov 6, 2007 Calling EC function with FE channel number. */ if (IS_TE1_CARD(card)) { if (IS_T1_CARD(card)){ fe_chan = chan->first_time_slot+1; }else{ fe_chan = chan->first_time_slot; } } else if (IS_FXOFXS_CARD(card)) { fe_chan = chan->first_time_slot+1; } else { fe_chan = chan->first_time_slot+1; } #if defined(CONFIG_WANPIPE_HWEC) if (ctrl == 0) { if (IS_BRI_CARD(card)) { DEBUG_HWEC("%s(): original fe_chan: %d\n", __FUNCTION__, fe_chan); /* translate channel to be 1 or 2, nothing else!! */ fe_chan = (fe_chan % 2); if (fe_chan == 0) { fe_chan=2; } DEBUG_HWEC("%s(): new fe_chan: %d\n", __FUNCTION__, fe_chan); } card->wandev.ec_enable(card, 0, fe_chan); } else if (tdmv_hwec_option) { if (IS_BRI_CARD(card)){ DEBUG_HWEC("%s(): original fe_chan: %d\n", __FUNCTION__, fe_chan); /* translate channel to be 1 or 2, nothing else!! */ fe_chan = (fe_chan % 2); if (fe_chan == 0) { fe_chan=2; } DEBUG_HWEC("%s(): new fe_chan: %d\n", __FUNCTION__, fe_chan); } DEBUG_HWEC("[HWEC] %s: Enable Echo Canceller on fe_chan %d\n", chan->if_name, fe_chan); err = card->wandev.ec_enable(card, 1, fe_chan); if (err) { DEBUG_EVENT("%s: Failed to enable HWEC on fe chan %d\n", chan->if_name,fe_chan); return err; } } #endif } return err; } #if defined(AFT_RTP_SUPPORT) enum { WAN_TDM_RTP_NO_CHANGE, WAN_TDM_RTP_CALL_START, WAN_TDM_RTP_CALL_STOP }; static void aft_rtp_unconfig(sdla_t *card) { wan_rtp_chan_t *rtp_chan; int i; netskb_t *skb; card->wandev.rtp_len=0; card->rtp_conf.rtp_ip=0; card->rtp_conf.rtp_sample=0; if (card->wandev.rtp_dev) { dev_put(card->wandev.rtp_dev); card->wandev.rtp_dev=NULL; } for (i=0;i<32;i++) { rtp_chan=&card->wandev.rtp_chan[i]; if (rtp_chan->rx_skb) { wan_skb_free(rtp_chan->rx_skb); rtp_chan->rx_skb=NULL; } if (rtp_chan->tx_skb) { wan_skb_free(rtp_chan->tx_skb); rtp_chan->rx_skb=NULL; } } while ((skb=wan_skb_dequeue(&card->u.aft.rtp_tap_list))) { wan_skb_free(skb); } } #endif #if defined(AFT_RTP_SUPPORT) static int aft_rtp_config(sdla_t *card) { netdevice_t *dev; card->wandev.rtp_tap=NULL; if (!card->rtp_conf.rtp_ip || !card->rtp_conf.rtp_sample) { return 1; } if (card->rtp_conf.rtp_sample < 10 || card->rtp_conf.rtp_sample > 150) { DEBUG_EVENT("%s: Error: Invalid RTP Sample %d [Min=10 Max=150ms]\n", card->devname,card->rtp_conf.rtp_sample); goto aft_rtp_init_exit; } DEBUG_EVENT("%s: RTP TAP [ %d.%d.%d.%d:%d %dms %s %02X:%02X:%02X:%02X:%02X:%02X ]\n", card->devname, NIPQUAD(card->rtp_conf.rtp_ip), card->rtp_conf.rtp_port, card->rtp_conf.rtp_sample, card->rtp_conf.rtp_devname, card->rtp_conf.rtp_mac[0], card->rtp_conf.rtp_mac[1], card->rtp_conf.rtp_mac[2], card->rtp_conf.rtp_mac[3], card->rtp_conf.rtp_mac[4], card->rtp_conf.rtp_mac[5]); card->wandev.rtp_len = (card->rtp_conf.rtp_sample * 8) + sizeof(wan_rtp_pkt_t); if ((card->wandev.rtp_dev=wan_dev_get_by_name(card->rtp_conf.rtp_devname)) == NULL){ DEBUG_EVENT("%s: Failed to open rtp tx device %s\n", card->devname, card->rtp_conf.rtp_devname); goto aft_rtp_init_exit; } dev=(netdevice_t*)card->wandev.rtp_dev; memcpy(card->rtp_conf.rtp_local_mac,dev->dev_addr,dev->addr_len); card->rtp_conf.rtp_local_ip=wan_get_ip_address(card->wandev.rtp_dev,WAN_LOCAL_IP); if (card->rtp_conf.rtp_local_ip == 0) { goto aft_rtp_init_exit; } card->wandev.rtp_tap=&aft_rtp_tap; memset(card->wandev.rtp_chan,0,sizeof(card->wandev.rtp_chan)); return 0; aft_rtp_init_exit: aft_rtp_unconfig(card); DEBUG_EVENT("%s: Failed to configure rtp tap!\n",card->devname); return -1; } static __inline void aft_rtp_tap_chan(sdla_t *card, u8 *data, u32 len, netskb_t **skb_q, u32 *timestamp, u8 call_status, u32 chan) { wan_rtp_pkt_t *pkt; u8 *buf; netskb_t *skb; u32 ts; if ((skb=*skb_q) == NULL) { *skb_q=wan_skb_alloc(card->wandev.rtp_len+128); if (!*skb_q) { return; } skb=*skb_q; pkt = (wan_rtp_pkt_t*)wan_skb_put(skb,sizeof(wan_rtp_pkt_t)); memset(pkt,0,sizeof(wan_rtp_pkt_t)); pkt->rtp_hdr.version=2; if (IS_T1_CARD(card)) { pkt->rtp_hdr.pt=0; } else { pkt->rtp_hdr.pt=1; } DEBUG_TEST("%s: RTP(%d) SKB Allocated Len=%i \n", card->devname,chan,card->wandev.rtp_len); } pkt = (wan_rtp_pkt_t*)wan_skb_data(skb); if (call_status == WAN_TDM_RTP_CALL_START) { pkt->rtp_hdr.seq=0; pkt->rtp_hdr.ts=0; *timestamp=0; } buf=wan_skb_put(skb,len); memcpy(buf,data,len); ts=htonl(pkt->rtp_hdr.ts); ts+=len; pkt->rtp_hdr.ts = htonl(ts); if (wan_skb_len(skb) >= card->wandev.rtp_len || call_status==WAN_TDM_RTP_CALL_STOP) { netskb_t *nskb; u16 seq; pkt->rtp_hdr.ts = *timestamp; wan_ip_udp_setup(card, &card->rtp_conf, chan, wan_skb_data(skb), wan_skb_len(skb)-sizeof(wan_rtp_pkt_t)); nskb=wan_skb_clone(skb); if (nskb) { nskb->next = nskb->prev = NULL; nskb->dev = card->wandev.rtp_dev; nskb->protocol = htons(ETH_P_802_2); wan_skb_reset_mac_header(nskb); wan_skb_reset_network_header(nskb); wan_skb_queue_tail(&card->u.aft.rtp_tap_list,nskb); wan_set_bit(AFT_RTP_TAP_Q,&card->u.aft.port_task_cmd); WAN_TASKQ_SCHEDULE((&card->u.aft.port_task)); DEBUG_TEST("%s: RTP(%d) SKB Tx on dev %s \n", card->devname,chan,nskb->dev->name); } wan_skb_trim(skb,sizeof(wan_rtp_pkt_t)); pkt = (wan_rtp_pkt_t*)wan_skb_data(skb); seq=htons(pkt->rtp_hdr.seq); seq++; pkt->rtp_hdr.seq=htons(seq); *timestamp = htonl(ts); DEBUG_TEST("Chan=%i Seq=%i TS=%i\n",chan,seq,ts); pkt->rtp_hdr.ts = htonl(ts); } } static void aft_rtp_tap(void *card_ptr, u8 chan, u8* rx, u8* tx, u32 len) { sdla_t *card = (sdla_t *)card_ptr; u8 call_status=WAN_TDM_RTP_NO_CHANGE; wan_rtp_chan_t *rtp_chan; u32 span; if (!card || !rx || !tx ) { if (WAN_NET_RATELIMIT()) { DEBUG_EVENT("%s: Internal Error: rtp tap invalid pointers chan %i\n", __FUNCTION__,chan); } return; } if (!card->rtp_conf.rtp_ip || !card->rtp_conf.rtp_sample || !card->wandev.rtp_len || !card->wandev.rtp_dev) { if (WAN_NET_RATELIMIT()) { DEBUG_EVENT("%s: RTP Tap Not configured %i\n", card->devname,chan); } return; } if (chan >= 32) { if (WAN_NET_RATELIMIT()) { DEBUG_EVENT("%s: Internal Error: rtp tap chan out of range %i\n", card->devname,chan); } return; } span = card->tdmv_conf.span_no-1; rtp_chan = &card->wandev.rtp_chan[chan]; if (wan_test_bit(chan,&card->wandev.rtp_tap_call_map)) { if (!wan_test_and_set_bit(chan,&card->wandev.rtp_tap_call_status)) { /* Start of the call */ call_status=WAN_TDM_RTP_CALL_START; DEBUG_TEST("%s: CALL Start on ch %i\n", card->devname,chan); } } else { if (!wan_test_bit(chan,&card->wandev.rtp_tap_call_status)) { /* Call not up */ return; } wan_clear_bit(chan,&card->wandev.rtp_tap_call_status); call_status=WAN_TDM_RTP_CALL_STOP; DEBUG_TEST("%s: CALL Stop on ch %i\n", card->devname,chan); } aft_rtp_tap_chan(card, rx, len, &rtp_chan->rx_skb, &rtp_chan->rx_ts, call_status, (span<<4|(chan+1))); aft_rtp_tap_chan(card, tx, len, &rtp_chan->tx_skb, &rtp_chan->tx_ts, call_status, (span<<4|(chan+1))+2000); } #endif static int aft_find_master_if_and_dchan(sdla_t *card, int *master_if, u32 active_ch) { int dchan_found=0; int i; if (card->tdmv_conf.dchan) { if (IS_E1_CARD(card) && !(WAN_FE_FRAME(&card->fe) == WAN_FR_UNFRAMED)) { card->tdmv_conf.dchan = card->tdmv_conf.dchan << 1; wan_clear_bit(0,&card->tdmv_conf.dchan); } } for (i=card->u.aft.num_of_time_slots-1;i>=0;i--){ if (wan_test_bit(i,&active_ch)){ if (wan_test_bit(i,&card->tdmv_conf.dchan)){ dchan_found=1; card->u.aft.tdmv_dchan=i; continue; } /* Find the TOP timeslot. This timeslot will be * considered MASTER since it is the last timeslot * to rx data from the T1 line */ if (*master_if < 0){ *master_if=i; } } } if (card->tdmv_conf.dchan && !dchan_found){ /* We configured for dchan however, this interface * was not configued with the DCHAN timeslot. * It IS now possible that another interface has * this time slot */ for (i=card->u.aft.num_of_time_slots-1;i>=0;i--){ if (wan_test_bit(i,&card->tdmv_conf.dchan)){ dchan_found=1; card->u.aft.tdmv_dchan=i; wan_set_bit(i,&card->u.aft.tdmv_dchan_cfg_on_master); continue; } } if (!dchan_found) { DEBUG_EVENT("%s: Error: TDM DCHAN is out of range 0x%08X\n", card->devname,card->tdmv_conf.dchan); return -EINVAL; } /* We have found a DCHAN outside the Voice active channels */ } return 0; } static int digital_loop_test(sdla_t* card,wan_udp_pkt_t* wan_udp_pkt) { netskb_t* skb; netdevice_t* dev; char* buf; private_area_t *chan; dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head)); if (dev == NULL) { return 1; } chan = wan_netif_priv(dev); if (chan == NULL) { return 1; } if (chan->common.state != WAN_CONNECTED) { DEBUG_EVENT("%s: Loop test failed: dev not connected!\n", card->devname); return 2; } skb = wan_skb_alloc(wan_udp_pkt->wan_udp_data_len+100); if (skb == NULL) { return 3; } switch (chan->common.usedby) { case API: wan_skb_push(skb, sizeof(api_rx_hdr_t)); break; case STACK: case WANPIPE: break; case TDM_VOICE: case TDM_VOICE_API: case TDM_VOICE_DCHAN: if (card->u.aft.tdmv_dchan) { break; } else { DEBUG_EVENT("%s: Loop test failed: no dchan in TDMV mode!\n", card->devname); } /* Fall into the default case */ default: DEBUG_EVENT("%s: Loop test failed: invalid operation mode!\n", card->devname); wan_skb_free(skb); return 4; } buf = wan_skb_put(skb, wan_udp_pkt->wan_udp_data_len); memcpy(buf, wan_udp_pkt->wan_udp_data, wan_udp_pkt->wan_udp_data_len); #if defined(__LINUX__) skb->next = skb->prev = NULL; skb->dev = dev; skb->protocol = htons(ETH_P_IP); wan_skb_reset_mac_header(skb); dev_queue_xmit(skb); #elif defined(__FreeBSD__) || defined(__OpenBSD__) DEBUG_EVENT("%s: WARNING: Digital loop test mode is not supported!\n", card->devname); #endif return 0; } void wanpipe_wake_stack(private_area_t* chan) { WAN_NETIF_WAKE_QUEUE(chan->common.dev); if (chan->common.usedby == API){ wan_wakeup_api(chan); } else if (chan->common.usedby == STACK){ wanpipe_lip_kick(chan,0); } else if (chan->common.usedby == TDM_VOICE_DCHAN){ #ifdef AFT_TDM_API_SUPPORT if (is_tdm_api(chan,&chan->wp_tdm_api_dev)){ wanpipe_tdm_api_kick(&chan->wp_tdm_api_dev); } #endif } else if (chan->common.usedby == ANNEXG) { #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG if (chan->annexg_dev){ if (IS_FUNC_CALL(lapb_protocol,lapb_mark_bh)){ lapb_protocol.lapb_mark_bh(chan->annexg_dev); } } #endif } } enum { MASTER_CLOCK_CHECK, MASTER_CLOCK_SET }; static int32_t aft_bri_clock_control(sdla_t *card, u8 line_state) { u_int32_t reg; /* Due to a hardware bug, only first 0x100 register * controls the clock routing */ card->hw_iface.bus_read_4(card->hw,AFT_LINE_CFG_REG,®); if (line_state == 1){ /* The 'Reference' line is connected, enable sync from line interface */ if (wan_test_bit(A500_LINE_SYNC_MASTER_BIT, ®)) { return 0; } wan_set_bit(A500_LINE_SYNC_MASTER_BIT, ®); } if (line_state == 0){ /* The 'Reference' line is DISconnected, disable sync from line interface */ if (!wan_test_bit(A500_LINE_SYNC_MASTER_BIT, ®)) { return 0; } wan_clear_bit(A500_LINE_SYNC_MASTER_BIT, ®); } card->hw_iface.bus_write_4(card->hw,AFT_LINE_CFG_REG,reg); return 0; } static int aft_handle_clock_master (sdla_t *card_ptr) { void **card_list; u32 max_number_of_ports, i; sdla_t *card; int master_clock_src_found=0; /* This feature only works for BRI cards for now */ if (!IS_BRI_CARD(card_ptr)) { return 0; } if (card_ptr->wandev.fe_iface.clock_ctrl == NULL){ return 0; } max_number_of_ports = MAX_BRI_LINES; /* 24 */ DEBUG_TEST("%s:aft_handle_clock_master !\n", card_ptr->devname); card_list=__sdla_get_ptr_isr_array(card_ptr->hw); for (i=0; iwandev.critical)) { continue; } DEBUG_TEST("%s: Device Type TE=%i NT=%i!\n",card->devname, aft_is_bri_te_card(card),aft_is_bri_nt_card(card)); if (IS_BRI_CARD(card)) { if (aft_is_bri_te_card(card) && wan_test_bit(CARD_MASTER_CLOCK,&card->wandev.critical)) { if (card->wandev.state != WAN_CONNECTED) { if (card->wandev.fe_iface.clock_ctrl){ DEBUG_EVENT("%s: Clearing Master Clock!\n", card->devname); card->wandev.fe_iface.clock_ctrl(&card->fe, 0); aft_bri_clock_control(card,0); } else { DEBUG_EVENT("%s: Internal Error: ctrl_clock feature not available!\n", card->devname); aft_bri_clock_control(card,0); } wan_clear_bit(CARD_MASTER_CLOCK,&card->wandev.critical); } else { DEBUG_TEST("%s: Master Clock Found!\n", card->devname); /* Master Clock port is still OK */ master_clock_src_found=1; } } } } if (master_clock_src_found) { return 0; } /* At this point the recovery clock must be set on any connected port */ for (i=0; iwandev.critical)) { continue; } if (IS_BRI_CARD(card)) { /* Check if this module is forced configured in oscillator mode */ if (IS_BRI_CLK(card) == WAN_MASTER_CLK) { continue; } /* Only enable clock recovery on cards with new CPLD */ if (!aft_is_bri_512khz_card(card)) { continue; } if (aft_is_bri_te_card(card) && !wan_test_bit(CARD_MASTER_CLOCK,&card->wandev.critical)) { if (card->wandev.state == WAN_CONNECTED) { if (card->wandev.fe_iface.clock_ctrl){ DEBUG_EVENT("%s: Setting Master Clock!\n", card->devname); card->wandev.fe_iface.clock_ctrl(&card->fe, 1); aft_bri_clock_control(card,1); wan_set_bit(CARD_MASTER_CLOCK,&card->wandev.critical); master_clock_src_found=1; } break; } } } } return 0; } static int aft_tdmapi_mtu_check(sdla_t *card_ptr, unsigned int *mtu) { void **card_list; u32 max_number_of_ports, i; sdla_t *card; int used_cnt; #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) int zt_chunksize; #endif card_ptr->hw_iface.getcfg(card_ptr->hw, SDLA_HWCPU_USEDCNT, &used_cnt); if (used_cnt == 1) { card=card_ptr; #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) if (card->sdla_tdmv_dummy) { zt_chunksize = sdla_tdmv_dummy_get_zt_chunksize(); *mtu = zt_chunksize; DEBUG_EVENT("%s: TDMV Dummy Enabled setting MTU to %d bytes!\n", card->devname,zt_chunksize); return 0; } #endif /* If SDLA TDMV dummy is not used, then allow the first card mtu to be configured by the user */ return -1; } if (IS_BRI_CARD(card_ptr)) { max_number_of_ports = MAX_BRI_LINES; /* 24 */ } else { max_number_of_ports = 8; } card_list=__sdla_get_ptr_isr_array(card_ptr->hw); for (i=0; iwandev.critical)) { continue; } if (card_ptr == card) { continue; } #if defined(CONFIG_PRODUCT_WANPIPE_TDM_VOICE) if (card->sdla_tdmv_dummy) { zt_chunksize = sdla_tdmv_dummy_get_zt_chunksize(); *mtu = zt_chunksize; DEBUG_EVENT("%s: TDMV Dummy Enabled setting MTU to %d bytes!\n", card->devname,zt_chunksize); return 0; } #endif if (wan_test_bit(AFT_TDM_GLOBAL_ISR,&card->u.aft.chip_cfg_status)) { /* Make sure that all MTUs are the same */ *mtu = card->u.aft.tdmv_mtu; return 0; } } return -1; } #if defined(__LINUX__) static int if_change_mtu(netdevice_t *dev, int new_mtu) { private_area_t* chan= (private_area_t*)wan_netif_priv(dev); if (!chan || wan_test_bit(0,&chan->interface_down)) { return -ENODEV; } if (!chan->hdlc_eng) { return -EINVAL; } if (new_mtu < 16) { return -EINVAL; } if (chan->common.usedby == API){ new_mtu+=sizeof(api_tx_hdr_t); }else if (chan->common.usedby == STACK){ new_mtu+=32; } if (new_mtu > chan->dma_mru) { return -EINVAL; } dev->mtu = new_mtu; return 0; } #endif #ifdef CONFIG_PRODUCT_WANPIPE_ANNEXG static int bind_annexg(netdevice_t *dev, netdevice_t *annexg_dev) { wan_smp_flag_t smp_flags=0; private_area_t* chan = wan_netif_priv(dev); sdla_t *card = chan->card; if (!chan) return -EINVAL; if (chan->common.usedby != ANNEXG) return -EPROTONOSUPPORT; if (chan->annexg_dev) return -EBUSY; wan_spin_lock_irq(&card->wandev.lock,&smp_flags); chan->annexg_dev = annexg_dev; wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); return 0; } static netdevice_t * un_bind_annexg(wan_device_t *wandev, netdevice_t *annexg_dev) { struct wan_dev_le *devle; netdevice_t *dev; wan_smp_flag_t smp_flags=0; sdla_t *card = wandev->priv; WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){ private_area_t* chan; dev = WAN_DEVLE2DEV(devle); if (dev == NULL || (chan = wan_netif_priv(dev)) == NULL) continue; if (!chan->annexg_dev || chan->common.usedby != ANNEXG) continue; if (chan->annexg_dev == annexg_dev){ wan_spin_lock_irq(&card->wandev.lock,&smp_flags); chan->annexg_dev = NULL; wan_spin_unlock_irq(&card->wandev.lock,&smp_flags); return dev; } } return NULL; } static void get_active_inactive(wan_device_t *wandev, netdevice_t *dev, void *wp_stats_ptr) { private_area_t* chan = wan_netif_priv(dev); wp_stack_stats_t *wp_stats = (wp_stack_stats_t *)wp_stats_ptr; if (chan->common.usedby == ANNEXG && chan->annexg_dev){ if (IS_FUNC_CALL(lapb_protocol,lapb_get_active_inactive)){ lapb_protocol.lapb_get_active_inactive(chan->annexg_dev,wp_stats); } } if (chan->common.state == WAN_CONNECTED){ wp_stats->fr_active++; }else{ wp_stats->fr_inactive++; } } static int get_map(wan_device_t *wandev, netdevice_t *dev, struct seq_file* m, int* stop_cnt) { private_area_t* chan = wan_netif_priv(dev); if (!(dev->flags&IFF_UP)){ return m->count; } if (chan->common.usedby == ANNEXG && chan->annexg_dev){ if (IS_FUNC_CALL(lapb_protocol,lapb_get_map)){ return lapb_protocol.lapb_get_map(chan->annexg_dev, m); } } PROC_ADD_LINE(m, "%15s:%s:%c:%s:%c\n", chan->label, wandev->name,(wandev->state == WAN_CONNECTED) ? '*' : ' ', dev->name,(chan->common.state == WAN_CONNECTED) ? '*' : ' '); return m->count; } #endif /****** End ****************************************************************/