/*- * Copyright (c) 2001-2004 Sangoma Technologies (SAN) * All rights reserved. www.sangoma.com * * This code is written by Nenad Corbic and * Alex Feldman for SAN. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * 3. Neither the name of Sangoma Technologies nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY SANGOMA TECHNOLOGIES AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include /****** Defines & Macros ****************************************************/ /* Private critical flags */ enum { POLL_CRIT = PRIV_CRIT, TX_BUSY, RX_BUSY, TASK_POLL, CARD_DOWN }; enum { LINK_DOWN, DEVICE_DOWN }; #define MAX_IP_ERRORS 10 #define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" ) #define MAX_TX_BUF 10 #define MAX_RX_BUF 10 #undef DEB_XILINX #if 1 # define TRUE_FIFO_SIZE 1 #else # undef TRUE_FIFO_SIZE # define HARD_FIFO_CODE 0x01 #endif static int aft_rx_copyback=1000; /******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 */ typedef struct { wanpipe_common_t common; struct ifqueue wp_tx_free_list; struct ifqueue wp_tx_pending_list; struct ifqueue wp_tx_complete_list; struct ifqueue wp_rx_free_list; struct ifqueue wp_rx_complete_list; struct mbuf *tx_dma_mbuf; u_int8_t tx_dma_cnt; struct mbuf *rx_dma_mbuf; unsigned long time_slot_map; unsigned char num_of_time_slots; long logic_ch_num; unsigned char dma_status; unsigned char ignore_modem; struct ifqueue udp_queue; unsigned long router_start_time; unsigned long tick_counter; /* For 5s timeout counter */ unsigned long router_up_time; unsigned char mc; /* Mulitcast support on/off */ unsigned char udp_pkt_src; /* udp packet processing */ unsigned short timer_int_enabled; unsigned char interface_down; u_int8_t gateway; u_int8_t true_if_encoding; char if_name[IFNAMSIZ+1]; u_int8_t idle_flag; u_int16_t max_idle_size; u_int8_t idle_start; u_int8_t pkt_error; u_int8_t rx_fifo_err_cnt; int first_time_slot; struct mbuf *tx_idle_mbuf; unsigned long tx_dma_addr; unsigned int tx_dma_len; unsigned char rx_dma; unsigned char pci_retry; unsigned char fifo_size_code; unsigned char fifo_base_addr; unsigned char fifo_size; int dma_mtu; void *prot_ch; wan_trace_t trace_info; }xilinx_softc_t; #define WAN_IFP_TO_SOFTC(ifp) (xilinx_softc_t*)((ifp)->if_softc) /* 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; */ extern void disable_irq(unsigned int); extern void enable_irq(unsigned int); /**SECTOIN************************************************** * * Function Prototypes * ***********************************************************/ /* WAN link driver entry points. These are called by the WAN router module. */ static int wan_xilinx_release(sdla_t*, struct ifnet*); /* Network device interface */ static int wan_xilinx_up (struct ifnet*); static int wan_xilinx_down(struct ifnet*); static int wan_xilinx_ioctl(struct ifnet*, int cmd, struct ifreq*); static int wan_xilinx_send (struct mbuf*, struct ifnet*); static void handle_front_end_state(void*); static void enable_timer(void*); /* Miscellaneous Functions */ static void port_set_state (sdla_t*, int); /* Interrupt handlers */ static void wp_xilinx_isr (sdla_t*); /* Miscellaneous functions */ static int process_udp_mgmt_pkt(sdla_t*, struct ifnet*, xilinx_softc_t*, int); /* Bottom half handlers */ static void xilinx_process_packet(xilinx_softc_t*); static int xilinx_chip_configure(sdla_t*); static int xilinx_chip_unconfigure(sdla_t*); static int xilinx_dev_configure(sdla_t*, xilinx_softc_t*); static void xilinx_dev_unconfigure(sdla_t*, xilinx_softc_t*); static int xilinx_dma_rx(sdla_t*, xilinx_softc_t*); static void xilinx_dev_enable(sdla_t*, xilinx_softc_t*); static void xilinx_dev_close(sdla_t*, xilinx_softc_t*); static int xilinx_dma_tx (sdla_t*, xilinx_softc_t*); static void xilinx_dma_tx_complete (sdla_t*, xilinx_softc_t*); static void xilinx_dma_rx_complete (sdla_t*, xilinx_softc_t*); static void xilinx_dma_max_logic_ch(sdla_t*); static int xilinx_init_rx_dev_fifo(sdla_t*, xilinx_softc_t*, unsigned char); static void xilinx_init_tx_dma_descr(sdla_t*, xilinx_softc_t*); static int xilinx_init_tx_dev_fifo(sdla_t*, xilinx_softc_t*, unsigned char); static void xilinx_tx_post_complete (sdla_t*, xilinx_softc_t*, struct mbuf*); static void xilinx_rx_post_complete (sdla_t*, xilinx_softc_t*, struct mbuf*, struct mbuf**, unsigned char*); static char request_xilinx_logical_channel_num (sdla_t*, xilinx_softc_t*, long*); static void free_xilinx_logical_channel_num (sdla_t*, int); static unsigned char read_cpld(sdla_t*, unsigned short); static unsigned char write_cpld(sdla_t*, unsigned short,unsigned char); static void front_end_interrupt(sdla_t*, unsigned long); static void enable_data_error_intr(sdla_t*); static void disable_data_error_intr(sdla_t*, unsigned char); static void xilinx_tx_fifo_under_recover (sdla_t*, xilinx_softc_t*); static int xilinx_write_ctrl_hdlc(sdla_t*, u_int32_t, u_int8_t, u_int32_t); static int set_chan_state(sdla_t*, struct ifnet*, int); static int fifo_error_interrupt(sdla_t*, unsigned long); static int request_fifo_baddr_and_size(sdla_t*, xilinx_softc_t*); static int map_fifo_baddr_and_size(sdla_t*, unsigned char, unsigned char*); static int free_fifo_baddr_and_size (sdla_t*, xilinx_softc_t*); static void aft_red_led_ctrl(sdla_t*, int); static void aft_led_timer(void*); static int aft_alloc_rx_dma_buff(sdla_t*, xilinx_softc_t*, int); static int aft_init_requeue_free_m(xilinx_softc_t*, struct mbuf*); static int aft_core_ready(sdla_t*); /* TE1 Control registers */ static WRITE_FRONT_END_REG_T write_front_end_reg; static READ_FRONT_END_REG_T read_front_end_reg; static void wan_ifmedia_sts(struct ifnet*, struct ifmediareq*); static int wan_ifmedia_upd(struct ifnet*); static void xilinx_delay(int sec) { #if 0 unsigned long timeout=ticks; while ((ticks-timeout)<(sec*hz)){ schedule(); } #endif } /**SECTION********************************************************* * * Public Functions * ******************************************************************/ /*============================================================================ * wan_xilinx_init - * */ void* wan_xilinx_init (sdla_t* card) { xilinx_softc_t *sc; struct ifnet *ifp; /* Verify configuration ID */ bit_clear((u_int8_t*)&card->critical, CARD_DOWN); card->u.xilinx.num_of_ch = 0; card->u.xilinx.mru_trans = 1500; card->u.xilinx.dma_per_ch = 10; /* TE1 Make special hardware initialization for T1/E1 board */ if (IS_TE1(&card->fe_te.te_cfg)){ card->write_front_end_reg = write_front_end_reg; card->read_front_end_reg = read_front_end_reg; card->te_enable_timer = enable_timer; card->te_link_state = handle_front_end_state; }else{ card->front_end_status = FE_CONNECTED; } /* 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->del_if = &wan_xilinx_release; card->iface_up = &wan_xilinx_up; card->iface_down = &wan_xilinx_down; card->iface_send = &wan_xilinx_send; card->iface_ioctl= &wan_xilinx_ioctl; write_cpld(card,LED_CONTROL_REG,0x0E); sdla_getcfg(card->hw, SDLA_BASEADDR, &card->u.xilinx.bar); xilinx_delay(1); timeout_set(&card->u.xilinx.led_timer, aft_led_timer, (void*)card); /* allocate and initialize private data */ sc = malloc(sizeof(xilinx_softc_t), M_DEVBUF, M_NOWAIT); if(sc == NULL){ return NULL; } memset(sc, 0, sizeof(xilinx_softc_t)); ifp = (struct ifnet*)&sc->common.ifp; if (wanpipe_generic_register(card, ifp, card->devname)){ free(sc, M_DEVBUF); return NULL; } strncpy(sc->if_name, ifp->if_xname, IFNAMSIZ); ifp->if_softc = sc; sc->common.card = card; sc->first_time_slot=-1; sc->time_slot_map = 0; IFQ_SET_MAXLEN(&sc->wp_tx_free_list, MAX_TX_BUF); sc->wp_tx_free_list.ifq_len = 0; IFQ_SET_MAXLEN(&sc->wp_tx_pending_list, MAX_TX_BUF); sc->wp_tx_pending_list.ifq_len = 0; IFQ_SET_MAXLEN(&sc->wp_tx_complete_list, MAX_TX_BUF); sc->wp_tx_complete_list.ifq_len = 0; IFQ_SET_MAXLEN(&sc->wp_rx_free_list, MAX_RX_BUF); sc->wp_rx_free_list.ifq_len = 0; IFQ_SET_MAXLEN(&sc->wp_rx_complete_list, MAX_RX_BUF); sc->wp_rx_complete_list.ifq_len = 0; xilinx_delay(1); ifmedia_init(&sc->common.ifm, 0, wan_ifmedia_upd, wan_ifmedia_sts); if (IS_TE1(&card->fe_te.te_cfg)){ ifmedia_add(&sc->common.ifm, IFM_TDM|IFM_TDM_T1, 0, NULL); ifmedia_add(&sc->common.ifm, IFM_TDM|IFM_TDM_T1_AMI, 0, NULL); ifmedia_add(&sc->common.ifm, IFM_TDM|IFM_TDM_E1, 0, NULL); ifmedia_add(&sc->common.ifm, IFM_TDM|IFM_TDM_E1_AMI, 0, NULL); ifmedia_set(&sc->common.ifm, IFM_TDM|IFM_TDM_T1); }else{ /* Currently we not support ifmedia types for other ** front end types. */ } return sc; } /*============================================================================ * wan_xilinx_release * * */ static int wan_xilinx_release (sdla_t* card, struct ifnet* ifp) { xilinx_softc_t* sc = ifp->if_softc; IF_PURGE(&sc->wp_rx_free_list); IF_PURGE(&sc->wp_rx_complete_list); IF_PURGE(&sc->wp_tx_free_list); IF_PURGE(&sc->wp_tx_pending_list); if (sc->tx_dma_addr && sc->tx_dma_len){ sc->tx_dma_addr=0; sc->tx_dma_len=0; } if (sc->tx_dma_mbuf){ log(LOG_INFO, "freeing tx dma mbuf\n"); m_freem(sc->tx_dma_mbuf); sc->tx_dma_mbuf=NULL; } if (sc->tx_idle_mbuf){ log(LOG_INFO, "freeing idle tx dma mbuf\n"); m_freem(sc->tx_idle_mbuf); sc->tx_idle_mbuf=NULL; } if (sc->rx_dma_mbuf){ m_freem(sc->rx_dma_mbuf); sc->rx_dma_mbuf=NULL; } wanpipe_generic_unregister(ifp); ifp->if_softc = NULL; free(sc, M_DEVBUF); return 0; } static void wan_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmreq) { wanpipe_common_t *common = (wanpipe_common_t*)ifp->if_softc; struct ifmedia *ifm; WAN_ASSERT1(common == NULL); ifm = &common->ifm; ifmreq->ifm_active = ifm->ifm_cur->ifm_media; return; } static int wan_ifmedia_upd(struct ifnet *ifp) { wanpipe_common_t *common = (wanpipe_common_t*)ifp->if_softc; sdla_t *card; WAN_ASSERT(common == NULL); WAN_ASSERT(common->card == NULL); card = (sdla_t*)common->card; if (IS_TE1(&card->fe_te.te_cfg)){ return sdla_te_setcfg(card, &common->ifm); } return -EINVAL; } /**SECTION*********************************************************** * * KERNEL Device Entry Interfaces * ********************************************************************/ /*============================================================================ * wan_xilinx_up * */ static int wan_xilinx_up (struct ifnet* ifp) { xilinx_softc_t *sc = ifp->if_softc; sdla_t *card = NULL; struct timeval tv; int err = 0; WAN_ASSERT(sc == NULL); WAN_ASSERT(sc->common.card == NULL); card = (sdla_t*)sc->common.card; if (card->state != WAN_DISCONNECTED){ return 0; } sc->time_slot_map = card->fe_te.te_cfg.active_ch; sc->dma_mtu = xilinx_valid_mtu(ifp->if_mtu+100); if (!sc->dma_mtu){ log(LOG_INFO, "%s:%s: Error invalid MTU %d\n", card->devname, sc->if_name, ifp->if_mtu); return -EINVAL; } #if defined(DEBUG_INIT) log(LOG_INFO, "%s: Allocating %d dma mbuf len=%d\n", card->devname, card->u.xilinx.dma_per_ch, sc->dma_mtu); #endif err=aft_alloc_rx_dma_buff(card, sc, card->u.xilinx.dma_per_ch); if (err){ return -EINVAL; } err=xilinx_chip_configure(card); if (err){ return -EINVAL; } card->isr = &wp_xilinx_isr; err=xilinx_dev_configure(card, sc); if (err){ xilinx_chip_unconfigure(card); return -EINVAL; } xilinx_delay(1); /* Initialize the router start time. * Used by wanpipemon debugger to indicate * how long has the interface been up */ microtime(&tv); sc->router_start_time = tv.tv_sec; xilinx_init_tx_dma_descr(card,sc); xilinx_dev_enable(card,sc); sc->ignore_modem=0x0F; bit_clear((u_int8_t*)&card->critical, CARD_DOWN); port_set_state(card, WAN_CONNECTING); return err; } /*============================================================================ * wan_xilinx_down * */ static int wan_xilinx_down (struct ifnet* ifp) { xilinx_softc_t *sc = ifp->if_softc; sdla_t *card = (sdla_t*)sc->common.card; struct mbuf *m; int s; if (card->state == WAN_DISCONNECTED){ return 0; } xilinx_dev_close(card,sc); /* Disable DMA ENGINE before we perform * core reset. Otherwise, we will receive * rx fifo errors on subsequent resetart. */ disable_data_error_intr(card,DEVICE_DOWN); bit_set((u_int8_t*)&card->critical, CARD_DOWN); timeout_del(&card->u.xilinx.led_timer); /* TE1 - Unconfiging, only on shutdown */ if (IS_TE1(&card->fe_te.te_cfg)) { sdla_te_unconfig(card); } s = splnet(); card->isr=NULL; if (sc->tx_dma_addr && sc->tx_dma_len){ sc->tx_dma_addr=0; sc->tx_dma_len=0; } if (sc->tx_dma_mbuf){ m_freem(sc->tx_dma_mbuf); sc->tx_dma_mbuf=NULL; } if (sc->tx_idle_mbuf){ m_freem(sc->tx_idle_mbuf); sc->tx_idle_mbuf=NULL; } /* If there is something left in rx_dma_buf, then ** move it to rx_free_list. */ if (sc->rx_dma_mbuf){ m=sc->rx_dma_mbuf; aft_init_requeue_free_m(sc, m); sc->rx_dma_mbuf=NULL; } /* If there is something in rx_complete_list, then ** move evething to rx_free_list. */ for(;;){ IF_DEQUEUE(&sc->wp_rx_complete_list, m); if (m == NULL) break; IF_ENQUEUE(&sc->wp_rx_free_list, m); } splx(s); DELAY(10); xilinx_dev_unconfigure(card, sc); xilinx_chip_unconfigure(card); port_set_state(card, WAN_DISCONNECTED); sc->ignore_modem=0x00; return 0; } /*============================================================================ * wan_xilinx_send * * */ static int wan_xilinx_send (struct mbuf* m, struct ifnet* ifp) { xilinx_softc_t *sc = ifp->if_softc; sdla_t *card = (sdla_t*)sc->common.card; /* Mark interface as busy. The kernel will not * attempt to send any more packets until we clear * this condition */ if (m == NULL){ /* This should never happen. Just a sanity check. */ return -EINVAL; } if (card->state != WAN_CONNECTED){ /* The card is still not ready to transmit... drop this packet! */ m_freem(m); return -EINVAL; }else { if (IF_QFULL(&sc->wp_tx_pending_list)){ int err; #if defined(DEBUG_TX) log(LOG_INFO, "%s: Tx pending queue FULL\n", ifp->if_xname); #endif /* TX pending queue is full. Try to send packet ** from tx_pending queue (first) */ err = xilinx_dma_tx(card,sc); if (!err && !IF_QFULL(&sc->wp_tx_pending_list)){ /* On success, we have place for the new ** tx packet, try to send it now! */ goto wan_xilinx_dma_tx_try; } /* Tx pedning queue is full. I can't accept new ** tx packet, drop this packet and set interface ** queue to OACTIVE */ m_freem(m); ifp->if_flags |= IFF_OACTIVE; return -EBUSY; }else{ wan_xilinx_dma_tx_try: IF_ENQUEUE(&sc->wp_tx_pending_list, m); xilinx_dma_tx(card,sc); } } return 0; } /*======================================================================== * * wan_xilinx_ioctl * * */ static int wan_xilinx_ioctl(struct ifnet *ifp, int cmd, struct ifreq *ifr) { xilinx_softc_t *sc= (xilinx_softc_t*)ifp->if_softc; struct mbuf *m; sdla_t *card; wan_udp_pkt_t *wan_udp_pkt; int err=0; if (!sc){ return -ENODEV; } card=(sdla_t*)sc->common.card; switch(cmd) { case SIOC_WANPIPE_PIPEMON: if (IF_QFULL(&sc->udp_queue)){ return -EBUSY; } /* For performance reasons test the critical * here before spin lock */ if (bit_test((u_int8_t*)&card->in_isr, 0)){ return -EBUSY; } m = wan_mbuf_alloc(); if (m == NULL){ return -ENOMEM; } wan_udp_pkt = mtod(m, wan_udp_pkt_t*); if (copyin(ifr->ifr_data, &wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){ m_freem(m); return -EFAULT; } IF_ENQUEUE(&sc->udp_queue, m); process_udp_mgmt_pkt(card,ifp,sc,1); if (copyout(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data, sizeof(wan_udp_hdr_t))){ m_freem(m); return -EFAULT; } IF_DEQUEUE(&sc->udp_queue, m); m_freem(m); return 0; default: if (card->ioctl){ err = card->ioctl(ifp, cmd, ifr); } break; } return err; } /*============================================================================= * 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, struct ifnet* ifp, xilinx_softc_t* sc, int local_dev ) { struct mbuf *m; unsigned short buffer_length; wan_udp_pkt_t *wan_udp_pkt; wan_trace_t *trace_info=NULL; struct timeval tv; IF_POLL(&sc->udp_queue, m); if (m == NULL){ return -EINVAL; } wan_udp_pkt = mtod(m, wan_udp_pkt_t *); trace_info=&sc->trace_info; { struct mbuf *m0; wan_udp_pkt->wan_udp_opp_flag = 0; switch(wan_udp_pkt->wan_udp_command) { case READ_CONFIGURATION: case READ_CODE_VERSION: wan_udp_pkt->wan_udp_return_code = 0; 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 (!bit_test((u_int8_t*)&trace_info->tracing_enabled, 0)){ trace_info->trace_timeout = ticks; IF_PURGE(&trace_info->ifq); if (wan_udp_pkt->wan_udp_data[0] == 0){ bit_clear((u_int8_t*)&trace_info->tracing_enabled, 1); log(LOG_INFO, "%s: ADSL L3 trace enabled!\n", card->devname); }else if (wan_udp_pkt->wan_udp_data[0] == 1){ bit_clear((u_int8_t*)&trace_info->tracing_enabled,2 ); bit_set((u_int8_t*)&trace_info->tracing_enabled,1); log(LOG_INFO, "%s: ADSL L2 trace enabled!\n", card->devname); }else{ bit_clear((u_int8_t*)&trace_info->tracing_enabled, 1); bit_set((u_int8_t*)&trace_info->tracing_enabled,2); log(LOG_INFO, "%s: ADSL L1 trace enabled!\n", card->devname); } bit_set ((u_int8_t*)&trace_info->tracing_enabled, 0); }else{ log(LOG_INFO, "%s: Error: AFT 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(bit_test((u_int8_t*)&trace_info->tracing_enabled, 0)) { bit_clear((u_int8_t*)&trace_info->tracing_enabled, 0); bit_clear((u_int8_t*)&trace_info->tracing_enabled, 1); bit_clear((u_int8_t*)&trace_info->tracing_enabled, 2); IF_PURGE(&trace_info->ifq); log(LOG_INFO, "%s: Disabling ADSL 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(bit_test((u_int8_t*)&trace_info->tracing_enabled, 0)){ trace_info->trace_timeout = ticks; }else{ log(LOG_INFO, "%s: Error AFT 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_aft_num_frames = 0; wan_udp_pkt->wan_udp_aft_ismoredata = 0; while (!IF_IS_EMPTY(&trace_info->ifq)){ IF_POLL(&trace_info->ifq, m0); if (m0 == NULL){ log(LOG_INFO, "%s: No more trace packets in trace queue!\n", card->devname); break; } if ((WAN_MAX_DATA_SIZE - buffer_length) < m0->m_pkthdr.len){ /* indicate there are more frames on board & exit */ wan_udp_pkt->wan_udp_aft_ismoredata = 0x01; break; } m_copydata(m0, 0, m0->m_pkthdr.len, &wan_udp_pkt->wan_udp_data[buffer_length]); buffer_length += m0->m_pkthdr.len; IF_DEQUEUE(&trace_info->ifq, m0); if (m0){ m_freem(m0); } wan_udp_pkt->wan_udp_aft_num_frames++; } /* 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: microtime(&tv); sc->router_up_time = tv.tv_sec; sc->router_up_time -= sc->router_start_time; *(unsigned long *)&wan_udp_pkt->wan_udp_data = sc->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: case WAN_FE_GET_STAT: case WAN_FE_SET_LB_MODE: case WAN_FE_FLUSH_PMON: case WAN_FE_GET_CFG: if (IS_TE1(&card->fe_te.te_cfg)){ sdla_te_udp(card, &wan_udp_pkt->wan_udp_cmd, &wan_udp_pkt->wan_udp_data[0]); }else{ if (wan_udp_pkt->wan_udp_command == WAN_GET_MEDIA_TYPE){ wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char); wan_udp_pkt->wan_udp_return_code = WAN_CMD_OK; }else{ wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD; } } break; case WAN_GET_PROTOCOL: wan_udp_pkt->wan_udp_aft_num_frames = WANCONFIG_AFT; wan_udp_pkt->wan_udp_return_code = WAN_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 = WAN_CMD_OK; wan_udp_pkt->wan_udp_data_len = 1; break; default: wan_udp_pkt->wan_udp_data_len = 0; wan_udp_pkt->wan_udp_return_code = 0xCD; log(LOG_INFO, "%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 */ wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY; return 1; } #endif /**SECTION********************************************************** * * FIRMWARE Specific Interface Functions * *******************************************************************/ /*============================================================================ * xilinx_chip_configure * * */ static int xilinx_chip_configure(sdla_t *card) { u_int32_t reg,tmp; int err=0; u_int16_t adapter_type,adptr_security; #if defined(DEBUG_INIT) log(LOG_DEBUG, "Xilinx Chip Configuration. -- \n"); #endif xilinx_delay(1); sdla_bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); /* Configure for T1 or E1 front end */ if (IS_T1(&card->fe_te.te_cfg)){ card->u.xilinx.num_of_time_slots=NUM_OF_T1_CHANNELS; bit_clear((u_int8_t*)®, INTERFACE_TYPE_T1_E1_BIT); bit_set((u_int8_t*)®, FRONT_END_FRAME_FLAG_ENABLE_BIT); }else if (IS_E1(&card->fe_te.te_cfg)){ card->u.xilinx.num_of_time_slots=NUM_OF_E1_CHANNELS; bit_set((u_int8_t*)®, INTERFACE_TYPE_T1_E1_BIT); bit_set((u_int8_t*)®, FRONT_END_FRAME_FLAG_ENABLE_BIT); }else{ log(LOG_INFO, "%s: Error: Xilinx doesn't support non T1/E1 interface!\n", card->devname); return -EINVAL; } sdla_bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); DELAY(10000); /* Reset PMC */ sdla_bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); bit_clear((u_int8_t*)®, FRONT_END_RESET_BIT); sdla_bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); DELAY(1000); bit_set((u_int8_t*)®, FRONT_END_RESET_BIT); sdla_bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); DELAY(100); #if defined(DEBUG_INIT) log(LOG_DEBUG, "--- Chip Reset. -- \n"); #endif /* Reset Chip Core */ sdla_bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); bit_set((u_int8_t*)®, CHIP_RESET_BIT); sdla_bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); DELAY(100); /* Disable the chip/hdlc reset condition */ bit_clear((u_int8_t*)®, CHIP_RESET_BIT); /* Disable ALL chip interrupts */ bit_clear((u_int8_t*)®, GLOBAL_INTR_ENABLE_BIT); bit_clear((u_int8_t*)®, ERROR_INTR_ENABLE_BIT); bit_clear((u_int8_t*)®, FRONT_END_INTR_ENABLE_BIT); sdla_bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); xilinx_delay(1); sdla_getcfg(card->hw, SDLA_ADAPTERTYPE, &adapter_type); DELAY(100); #if defined(DEBUG_INIT) log(LOG_INFO, "%s: Hardware Adapter Type 0x%X\n", card->devname,adapter_type); #endif adptr_security = read_cpld(card,SECURITY_CPLD_REG); adptr_security = adptr_security >> SECURITY_CPLD_SHIFT; adptr_security = adptr_security & SECURITY_CPLD_MASK; #if defined(DEBUG_INIT) switch(adptr_security){ case SECURITY_1LINE_UNCH: log(LOG_INFO, "%s: Security 1 Line UnCh\n", card->devname); break; case SECURITY_1LINE_CH: log(LOG_INFO, "%s: Security 1 Line Ch\n", card->devname); break; case SECURITY_2LINE_UNCH: log(LOG_INFO, "%s: Security 2 Line UnCh\n", card->devname); break; case SECURITY_2LINE_CH: log(LOG_INFO, "%s: Security 2 Line Ch\n", card->devname); break; default: log(LOG_INFO, "%s: Error Invalid Security ID=0x%X\n", card->devname,adptr_security); /*return -EINVAL;*/ } #endif /* Turn off Onboard RED LED */ sdla_bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); bit_set((u_int8_t*)®, XILINX_RED_LED); sdla_bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); DELAY(10); err=aft_core_ready(card); if (err != 0){ log(LOG_INFO, "%s: WARNING: HDLC Core Not Ready: B4 TE CFG!\n", card->devname); } log(LOG_INFO, "%s: Configuring A101 PMC T1/E1/J1 Front End\n", card->devname); if (sdla_te_config(card)){ log(LOG_INFO, "%s: Failed %s configuratoin!\n", card->devname, IS_T1(&card->fe_te.te_cfg)?"T1":"E1"); return -EINVAL; } xilinx_delay(1); err=aft_core_ready(card); if (err != 0){ log(LOG_INFO, "%s: Error: HDLC Core Not Ready!\n", card->devname); sdla_bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); /* Disable the chip/hdlc reset condition */ bit_set((u_int8_t*)®, CHIP_RESET_BIT); sdla_bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); return err; } else{ #if defined(DEBUG_INIT) log(LOG_INFO, "%s: HDLC Core Ready 0x%08X\n", card->devname,reg); #endif } xilinx_delay(1); /* Setup global DMA parameters */ reg=0; reg|=(XILINX_DMA_SIZE << DMA_SIZE_BIT_SHIFT); reg|=(XILINX_DMA_FIFO_UP << DMA_FIFO_HI_MARK_BIT_SHIFT); reg|=(XILINX_DMA_FIFO_LO << DMA_FIFO_LO_MARK_BIT_SHIFT); /* Enable global DMA engine and set to default * number of active channels. Note: this value will * change in dev configuration */ reg|=(XILINX_DEFLT_ACTIVE_CH << DMA_ACTIVE_CHANNEL_BIT_SHIFT); bit_set((u_int8_t*)®, DMA_ENGINE_ENABLE_BIT); #if defined(DEBUG_INIT) log(LOG_INFO, "--- Setup DMA control Reg. -- \n"); #endif sdla_bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); #if defined(DEBUG_INIT) log(LOG_INFO, "--- Tx/Rx global enable. -- \n"); #endif xilinx_delay(1); reg=0; sdla_bus_write_4(card->hw,XILINX_TIMESLOT_HDLC_CHAN_REG,reg); /* Clear interrupt pending registers befor first interrupt enable */ sdla_bus_read_4(card->hw, XILINX_DMA_RX_INTR_PENDING_REG, &tmp); sdla_bus_read_4(card->hw, XILINX_DMA_TX_INTR_PENDING_REG, &tmp); sdla_bus_read_4(card->hw,XILINX_HDLC_RX_INTR_PENDING_REG, &tmp); sdla_bus_read_4(card->hw,XILINX_HDLC_TX_INTR_PENDING_REG, &tmp); sdla_bus_read_4(card->hw,XILINX_CHIP_CFG_REG, (u_int32_t*)®); if (bit_test((u_int8_t*)®, DMA_INTR_FLAG)){ log(LOG_INFO, "%s: Error: Active DMA Interrupt Pending. !\n", card->devname); reg = 0; /* Disable the chip/hdlc reset condition */ bit_set((u_int8_t*)®, CHIP_RESET_BIT); sdla_bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); return err; } if (bit_test((u_int8_t*)®, ERROR_INTR_FLAG)){ log(LOG_INFO, "%s: Error: Active Error Interrupt Pending. !\n", card->devname); reg = 0; /* Disable the chip/hdlc reset condition */ bit_set((u_int8_t*)®, CHIP_RESET_BIT); sdla_bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); return err; } /* Alawys disable global data and error * interrupts */ bit_clear((u_int8_t*)®, GLOBAL_INTR_ENABLE_BIT); bit_clear((u_int8_t*)®, ERROR_INTR_ENABLE_BIT); /* Always enable the front end interrupt */ bit_set((u_int8_t*)®, FRONT_END_INTR_ENABLE_BIT); #if defined(DEBUG_INIT) log(LOG_DEBUG, "--- Set Global Interrupts (0x%X)-- \n",reg); #endif xilinx_delay(1); sdla_bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); return err; } /*============================================================================ * xilinx_chip_unconfigure * * */ static int xilinx_chip_unconfigure(sdla_t *card) { u_int32_t reg = 0; sdla_bus_write_4(card->hw,XILINX_TIMESLOT_HDLC_CHAN_REG,reg); sdla_bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); /* Enable the chip/hdlc reset condition */ reg=0; bit_set((u_int8_t*)®, CHIP_RESET_BIT); sdla_bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); return 0; } /*============================================================================ * xilinx_dev_configure * * */ static int xilinx_dev_configure(sdla_t *card, xilinx_softc_t *sc) { u_int32_t reg; long free_logic_ch,i; sc->logic_ch_num=-1; if (!IS_TE1(&card->fe_te.te_cfg)){ return -EINVAL; } if (IS_E1(&card->fe_te.te_cfg)){ log(LOG_DEBUG, "%s: Time Slot Orig 0x%lX Shifted 0x%lX\n", sc->if_name, sc->time_slot_map, sc->time_slot_map<<1); sc->time_slot_map=sc->time_slot_map<<1; bit_clear((u_int8_t*)&sc->time_slot_map, 0); } /* Channel definition section. If not channels defined * return error */ if (sc->time_slot_map == 0){ log(LOG_INFO, "%s: Invalid Channel Selection 0x%lX\n", card->devname,sc->time_slot_map); return -EINVAL; } #if defined(DEBUG_INIT) log(LOG_INFO, "%s:%s: Active channels = 0x%lX\n", card->devname,sc->if_name,sc->time_slot_map); #endif xilinx_delay(1); /* Check that the time slot is not being used. If it is * stop the interface setup. Notice, though we proceed * to check for all timeslots before we start binding * the channels in. This way, we don't have to go back * and clean the time_slot_map */ for (i=0;iu.xilinx.num_of_time_slots;i++){ if (bit_test((u_int8_t*)&sc->time_slot_map, i)){ if (sc->first_time_slot == -1){ #if defined(DEBUG_INIT) log(LOG_INFO, "%s: Setting first time slot to %ld\n", card->devname,i); #endif sc->first_time_slot=i; } #if defined(DEBUG_INIT) log(LOG_DEBUG, "%s: Configuring %s for timeslot %ld\n", card->devname, sc->if_name, IS_E1(&card->fe_te.te_cfg)?i:i+1); #endif if (bit_test((u_int8_t*)&card->u.xilinx.time_slot_map, i)){ log(LOG_INFO, "%s: Channel/Time Slot resource conflict!\n", card->devname); log(LOG_INFO, "%s: %s: Channel/Time Slot %ld, aready in use!\n", card->devname,sc->if_name,(i+1)); return -EEXIST; } /* Calculate the number of timeslots for this * interface */ ++sc->num_of_time_slots; } } xilinx_delay(1); sc->logic_ch_num=request_xilinx_logical_channel_num(card, sc, &free_logic_ch); if (sc->logic_ch_num == -1){ return -EBUSY; } xilinx_delay(1); for (i=0;iu.xilinx.num_of_time_slots;i++){ if (bit_test((u_int8_t*)&sc->time_slot_map, i)){ bit_set((u_int8_t*)&card->u.xilinx.time_slot_map, i); sdla_bus_read_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, ®); reg&=~TIMESLOT_BIT_MASK; /*FIXME do not hardcode !*/ reg&= HDLC_LCH_TIMESLOT_MASK; /* mask not valid bits */ /* Select a Timeslot for configuration */ sdla_bus_write_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, (reg|(i<logic_ch_num&CONTROL_RAM_DATA_MASK; #ifdef TRUE_FIFO_SIZE reg|=(sc->fifo_size_code&HDLC_FIFO_SIZE_MASK)<fifo_base_addr&HDLC_FIFO_BASE_ADDR_MASK)<< HDLC_FIFO_BASE_ADDR_SHIFT; #if defined(DEBUG_INIT) log(LOG_INFO, "Setting Timeslot %ld to logic ch %ld Reg=0x%X\n", i, sc->logic_ch_num,reg); #endif xilinx_write_ctrl_hdlc(card, i, XILINX_CONTROL_RAM_ACCESS_BUF, reg); } } if (free_logic_ch != -1){ char free_ch_used=0; for (i=0;iu.xilinx.num_of_time_slots;i++){ if (!bit_test((u_int8_t*)&card->u.xilinx.time_slot_map, i)){ sdla_bus_read_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, ®); reg&=~TIMESLOT_BIT_MASK; reg&= HDLC_LCH_TIMESLOT_MASK; /* mask not valid bits */ /* Select a Timeslot for configuration */ sdla_bus_write_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, (reg|(i<if_name,free_logic_ch); #endif xilinx_delay(1); /* Setup the free logic channel as IDLE */ sdla_bus_read_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, ®); reg&=~HDLC_LOGIC_CH_BIT_MASK; reg&=HDLC_LCH_TIMESLOT_MASK; /* mask not valid bits */ sdla_bus_write_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, (reg|(free_logic_ch&HDLC_LOGIC_CH_BIT_MASK))); reg=0; bit_clear((u_int8_t*)®, HDLC_RX_PROT_DISABLE_BIT); bit_clear((u_int8_t*)®, HDLC_TX_PROT_DISABLE_BIT); bit_set((u_int8_t*)®, HDLC_RX_ADDR_RECOGN_DIS_BIT); xilinx_write_ctrl_hdlc(card, sc->first_time_slot, XILINX_HDLC_CONTROL_REG, reg); } } /* Select an HDLC logic channel for configuration */ sdla_bus_read_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, ®); reg&=~HDLC_LOGIC_CH_BIT_MASK; reg&= HDLC_LCH_TIMESLOT_MASK; /* mask not valid bits */ sdla_bus_write_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, (reg|(sc->logic_ch_num&HDLC_LOGIC_CH_BIT_MASK))); reg=0; /* HDLC engine is enabled on the above logical channels */ bit_clear((u_int8_t*)®, HDLC_RX_PROT_DISABLE_BIT); bit_clear((u_int8_t*)®, HDLC_TX_PROT_DISABLE_BIT); bit_set((u_int8_t*)®, HDLC_TX_CHAN_ENABLE_BIT); bit_set((u_int8_t*)®, HDLC_RX_ADDR_RECOGN_DIS_BIT); xilinx_write_ctrl_hdlc(card, sc->first_time_slot, XILINX_HDLC_CONTROL_REG, reg); return 0; } static void xilinx_dev_unconfigure(sdla_t *card, xilinx_softc_t *sc) { u_int32_t reg; int i, s; #if defined(DEBUG_INIT) log(LOG_DEBUG, "\n-- Unconfigure Xilinx. --\n"); #endif /* Select an HDLC logic channel for configuration */ if (sc->logic_ch_num != -1){ sdla_bus_read_4(card->hw,XILINX_TIMESLOT_HDLC_CHAN_REG, ®); reg&=~HDLC_LOGIC_CH_BIT_MASK; reg&= HDLC_LCH_TIMESLOT_MASK; /* mask not valid bits */ sdla_bus_write_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, (reg|(sc->logic_ch_num&HDLC_LOGIC_CH_BIT_MASK))); reg=0x00020000; xilinx_write_ctrl_hdlc(card, sc->first_time_slot, XILINX_HDLC_CONTROL_REG, reg); for (i=0;iu.xilinx.num_of_time_slots;i++){ if (bit_test((u_int8_t*)&sc->time_slot_map, i)){ sdla_bus_read_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, ®); reg&=~TIMESLOT_BIT_MASK; reg&= HDLC_LCH_TIMESLOT_MASK; /* mask not valid bits */ /* Select a Timeslot for configuration */ sdla_bus_write_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, (reg|(i<logic_ch_num); for (i=0;iu.xilinx.num_of_time_slots;i++){ if (bit_test((u_int8_t*)&sc->time_slot_map, i)){ --sc->num_of_time_slots; } } free_fifo_baddr_and_size(card,sc); splx(s); sc->logic_ch_num=-1; for (i=0;iu.xilinx.num_of_time_slots;i++){ if (bit_test((u_int8_t*)&sc->time_slot_map, i)){ bit_clear((u_int8_t*)&card->u.xilinx.time_slot_map, i); } } } } #define FIFO_RESET_TIMEOUT_CNT 1000 #define FIFO_RESET_TIMEOUT_US 10 static int xilinx_init_rx_dev_fifo(sdla_t *card, xilinx_softc_t *sc, unsigned char wait) { u_int32_t reg; u_int32_t dma_descr; u_int8_t timeout=1; u_int16_t i; /* Clean RX DMA fifo */ dma_descr=(unsigned long)(sc->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_HI; reg=0; bit_set((u_int8_t*)®, INIT_DMA_FIFO_CMD_BIT); #if defined(DEBUG_INIT) log(LOG_DEBUG, "%s: Clearing RX Fifo DmaDescr=(0x%X) Reg=(0x%X) (%s)\n", sc->if_name, dma_descr,reg, __FUNCTION__); #endif sdla_bus_write_4(card->hw,dma_descr,reg); if (wait == WP_WAIT){ for(i=0;ihw,dma_descr,®); if (bit_test((u_int8_t*)®, INIT_DMA_FIFO_CMD_BIT)){ DELAY(FIFO_RESET_TIMEOUT_US); continue; } timeout=0; break; } #if defined(DEBUG_INIT) if (timeout){ log(LOG_INFO, "%s:%s: Error: Rx fifo reset timedout %u us\n", card->devname,sc->if_name,i*FIFO_RESET_TIMEOUT_US); }else{ log(LOG_INFO, "%s:%s: Rx Fifo reset successful %u us\n", card->devname,sc->if_name,i*FIFO_RESET_TIMEOUT_US); } #endif }else{ timeout=0; } return timeout; } static int xilinx_init_tx_dev_fifo(sdla_t *card, xilinx_softc_t *sc, unsigned char wait) { u_int32_t reg; u_int32_t dma_descr; u_int8_t timeout=1; u_int16_t i; /* Clean TX DMA fifo */ dma_descr=(unsigned long)(sc->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; reg=0; bit_set((u_int8_t*)®, INIT_DMA_FIFO_CMD_BIT); #if defined(DEBUG_INIT) log(LOG_DEBUG, "%s: Clearing TX Fifo DmaDescr=(0x%X) Reg=(0x%X) (%s)\n", sc->if_name, dma_descr,reg, __FUNCTION__); #endif sdla_bus_write_4(card->hw,dma_descr,reg); if (wait == WP_WAIT){ for(i=0;ihw,dma_descr,®); if (bit_test((u_int8_t*)®, INIT_DMA_FIFO_CMD_BIT)){ DELAY(FIFO_RESET_TIMEOUT_US); continue; } timeout=0; break; } #if defined(DEBUG_INIT) if (timeout){ log(LOG_INFO, "%s:%s: Error: Tx fifo reset timedout %u us\n", card->devname,sc->if_name,i*FIFO_RESET_TIMEOUT_US); }else{ log(LOG_INFO, "%s:%s: Tx Fifo reset successful %u us\n", card->devname,sc->if_name,i*FIFO_RESET_TIMEOUT_US); } #endif }else{ timeout=0; } return timeout; } static void xilinx_dev_enable(sdla_t *card, xilinx_softc_t *sc) { u_int32_t reg; #if defined(DEBUG_INIT) log(LOG_INFO, "%s: Enabling Global Inter Mask !\n",sc->if_name); #endif /* Enable Logic Channel Interrupts for DMA and fifo */ sdla_bus_read_4(card->hw, XILINX_GLOBAL_INTER_MASK, ®); bit_set((u_int8_t*)®, sc->logic_ch_num); sdla_bus_write_4(card->hw, XILINX_GLOBAL_INTER_MASK, reg); bit_set((u_int8_t*)&card->u.xilinx.active_ch_map, sc->logic_ch_num); } static void xilinx_dev_close(sdla_t *card, xilinx_softc_t *sc) { u_int32_t reg; unsigned long dma_descr; int s; #if defined(DEBUG_INIT) log(LOG_DEBUG, "-- Close Xilinx device. --\n"); #endif /* Disable Logic Channel Interrupts for DMA and fifo */ sdla_bus_read_4(card->hw, XILINX_GLOBAL_INTER_MASK, ®); bit_clear((u_int8_t*)®, sc->logic_ch_num); bit_clear((u_int8_t*)&card->u.xilinx.active_ch_map, sc->logic_ch_num); /* We are masking the sc interrupt. * Lock to make sure that the interrupt is * not running */ s = splnet(); sdla_bus_write_4(card->hw, XILINX_GLOBAL_INTER_MASK, reg); splx(s); reg=0; /* Select an HDLC logic channel for configuration */ sdla_bus_read_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, ®); reg&=~HDLC_LOGIC_CH_BIT_MASK; reg&= HDLC_LCH_TIMESLOT_MASK; /* mask not valid bits */ sdla_bus_write_4(card->hw, XILINX_TIMESLOT_HDLC_CHAN_REG, (reg|(sc->logic_ch_num&HDLC_LOGIC_CH_BIT_MASK))); reg=0; xilinx_write_ctrl_hdlc(card, sc->first_time_slot, XILINX_HDLC_CONTROL_REG, reg); /* Clear descriptors */ reg=0; dma_descr=(sc->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_HI; sdla_bus_write_4(card->hw,dma_descr,reg); dma_descr=(sc->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; sdla_bus_write_4(card->hw,dma_descr,reg); /* FIXME: Cleanp up Tx and Rx buffers */ } static int xilinx_dma_rx(sdla_t *card, xilinx_softc_t *sc) { u_int32_t reg; unsigned long dma_descr; unsigned long bus_addr; wp_rx_element_t *rx_el; /* sanity check: make sure that DMA is in ready state */ #if 0 dma_descr=(sc->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_HI; sdla_bus_read_4(card->hw,dma_descr, ®); if (bit_test((u_int8_t*)®,RxDMA_HI_DMA_GO_READY_BIT)){ log(LOG_INFO, "%s: Error: RxDMA GO Ready bit set on dma Rx\n", card->devname); return -EFAULT; } #endif if (sc->rx_dma_mbuf){ log(LOG_INFO, "%s: Critial Error: Rx Dma Buf busy!\n", sc->if_name); return -EINVAL; } IF_DEQUEUE(&sc->wp_rx_free_list, sc->rx_dma_mbuf); if (!sc->rx_dma_mbuf){ log(LOG_INFO, "%s: Critical Error no rx dma buf Free=%d Comp=%d!\n", sc->if_name, sc->wp_rx_free_list.ifq_len, sc->wp_rx_complete_list.ifq_len); return -ENOMEM; } rx_el = mtod(sc->rx_dma_mbuf, wp_rx_element_t*); sc->rx_dma_mbuf->m_len = sizeof(wp_rx_element_t); sc->rx_dma_mbuf->m_pkthdr.len = sc->rx_dma_mbuf->m_len; memset(rx_el,0,sizeof(wp_rx_element_t)); bus_addr = kvtop(mtod(sc->rx_dma_mbuf, caddr_t) + sc->rx_dma_mbuf->m_len); if (!bus_addr){ log(LOG_INFO, "%s: %s Critical error pci_map_single() failed!\n", sc->if_name,__FUNCTION__); return -EINVAL; } rx_el->dma_addr=bus_addr; /* Write the pointer of the data packet to the * DMA address register */ reg=bus_addr; /* Set the 32bit alignment of the data length. * Since we are setting up for rx, set this value * to Zero */ reg&=~(RxDMA_LO_ALIGNMENT_BIT_MASK); dma_descr=(sc->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_LO; #if defined(DEBUG_RX) log(LOG_INFO,"%s: RxDMA_LO = 0x%X, BusAddr=0x%lX DmaDescr=0x%lX (%s)\n", card->devname,reg,bus_addr,dma_descr, __FUNCTION__); #endif sdla_bus_write_4(card->hw,dma_descr,reg); dma_descr=(unsigned long)(sc->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_HI; reg =0; reg|=(sc->dma_mtu>>2)&RxDMA_HI_DMA_DATA_LENGTH_MASK; #ifdef TRUE_FIFO_SIZE reg|=(sc->fifo_size_code&DMA_FIFO_SIZE_MASK)<fifo_base_addr&DMA_FIFO_BASE_ADDR_MASK)<< DMA_FIFO_BASE_ADDR_SHIFT; bit_set((u_int8_t*)®, RxDMA_HI_DMA_GO_READY_BIT); #if defined(DEBUG_RX) log(LOG_INFO, "%s: RXDMA_HI = 0x%X, BusAddr=0x%lX DmaDescr=0x%lX (%s)\n", sc->if_name, reg,bus_addr,dma_descr, __FUNCTION__); #endif sdla_bus_write_4(card->hw,dma_descr,reg); bit_set((u_int8_t*)&sc->rx_dma, 0); return 0; } static int xilinx_dma_tx (sdla_t *card, xilinx_softc_t *sc) { u_int32_t reg=0; struct mbuf *m; unsigned long dma_descr; unsigned char len_align=0; int len=0; #if defined(DEBUG_TX) log(LOG_INFO, "------ Setup Tx DMA descriptor. --\n"); #endif if (bit_test((u_int8_t*)&sc->dma_status, TX_BUSY)){ log(LOG_INFO, "%s: TX_BUSY set (%s:%d)!\n", sc->if_name, __FUNCTION__,__LINE__); return -EBUSY; } bit_set((u_int8_t*)&sc->dma_status, TX_BUSY); /* Free the previously skb dma mapping. * In this case the tx interrupt didn't finish * and we must re-transmit.*/ if (sc->tx_dma_addr && sc->tx_dma_len){ log(LOG_INFO, "%s: Unmaping tx_dma_addr in %s\n", sc->if_name,__FUNCTION__); sc->tx_dma_addr=0; sc->tx_dma_len=0; } /* Free the previously sent tx packet. To * minimize tx isr, the previously transmitted * packet is deallocated here */ if (sc->tx_dma_mbuf){ log(LOG_INFO, "%s: Deallocating tx_dma_mbuf in %s\n", sc->if_name,__FUNCTION__); m_freem(sc->tx_dma_mbuf); sc->tx_dma_mbuf=NULL; } /* check queue pointers befor start transmittion */ /* sanity check: make sure that DMA is in ready state */ dma_descr=(sc->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; #if defined(DEBUG_TX) log(LOG_INFO, "%s: sc logic ch=%ld dma_descr=0x%lx set (%s:%d)!\n", sc->if_name, sc->logic_ch_num,dma_descr, __FUNCTION__,__LINE__); #endif sdla_bus_read_4(card->hw,dma_descr, ®); if (bit_test((u_int8_t*)®, TxDMA_HI_DMA_GO_READY_BIT)){ log(LOG_INFO, "%s: Error: TxDMA GO Ready bit set on dma Tx 0x%X\n", card->devname,reg); bit_clear((u_int8_t*)&sc->dma_status, TX_BUSY); return -EFAULT; } IF_DEQUEUE(&sc->wp_tx_pending_list, m); if (!m){ bit_clear((u_int8_t*)&sc->dma_status, TX_BUSY); return -ENOBUFS; }else{ len = m->m_len; if (len > MAX_XILINX_TX_DMA_SIZE){ /* FIXME: We need to split this frame into * multiple parts. For now thought * just drop it :) */ log(LOG_INFO, "%s: Tx len %d > %d (MAX TX DMA LEN) (%s:%d)!\n", sc->if_name, len, MAX_XILINX_TX_DMA_SIZE, __FUNCTION__,__LINE__); m_freem(m); bit_clear((u_int8_t*)&sc->dma_status, TX_BUSY); return -EINVAL; } sc->tx_dma_addr = kvtop(mtod(m, caddr_t)); sc->tx_dma_len = len; } if (sc->tx_dma_addr & 0x03){ log(LOG_INFO, "%s: Error: Tx Ptr not aligned to 32bit boudary!\n", card->devname); if (m){ m_freem(m); } bit_clear((u_int8_t*)&sc->dma_status, TX_BUSY); return -EINVAL; } sc->tx_dma_mbuf=m; /* WARNING: Do ont use the "skb" pointer from * here on. The skb pointer might not exist if * we are in transparent mode */ dma_descr=(sc->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_LO; /* Write the pointer of the data packet to the * DMA address register */ reg=sc->tx_dma_addr; /* Set the 32bit alignment of the data length. * Used to pad the tx packet to the 32 bit * boundary */ reg&=~(TxDMA_LO_ALIGNMENT_BIT_MASK); reg|=(len&0x03); if (len&0x03){ len_align=1; } #if defined(DEBUG_TX) log(LOG_INFO, "%s: TXDMA_LO=0x%X PhyAddr=0x%lX DmaDescr=0x%lX (%s)\n", sc->if_name, reg,sc->tx_dma_addr,dma_descr, __FUNCTION__); #endif sdla_bus_write_4(card->hw,dma_descr,reg); dma_descr=(sc->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; reg=0; reg|=(((len>>2)+len_align)&TxDMA_HI_DMA_DATA_LENGTH_MASK); #ifdef TRUE_FIFO_SIZE reg|=(sc->fifo_size_code&DMA_FIFO_SIZE_MASK)<fifo_base_addr&DMA_FIFO_BASE_ADDR_MASK)<< DMA_FIFO_BASE_ADDR_SHIFT; /* Only enable the Frame Start/Stop on * non-transparent hdlc configuration */ bit_set((u_int8_t*)®, TxDMA_HI_DMA_FRAME_START_BIT); bit_set((u_int8_t*)®, TxDMA_HI_DMA_FRAME_END_BIT); bit_set((u_int8_t*)®, TxDMA_HI_DMA_GO_READY_BIT); #if defined(DEBUG_TX) log(LOG_INFO, "%s: TXDMA_HI=0x%X DmaDescr=0x%lX (%s)\n", sc->if_name, reg,dma_descr, __FUNCTION__); #endif sdla_bus_write_4(card->hw,dma_descr,reg); return 0; } static void xilinx_dma_tx_complete (sdla_t *card, xilinx_softc_t *sc) { u_int32_t reg=0; unsigned long dma_descr; #if defined(DEBUG_TX) log(LOG_INFO, "%s: TX DMA complete\n", card->devname); #endif /* DEBUGTX */ /* sdla_bus_read_4(card->hw,0x78, &tmp1); */ dma_descr=(sc->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; sdla_bus_read_4(card->hw,dma_descr, ®); if (!sc->tx_dma_mbuf){ log(LOG_INFO, "%s: Critical Error: Tx DMA intr: no tx mbuf !\n", card->devname); bit_clear((u_int8_t*)&sc->dma_status, TX_BUSY); return; }else{ sc->tx_dma_addr=0; sc->tx_dma_len=0; /* Do not free the packet here, * copy the packet dma info into csum * field and let the bh handler analyze * the transmitted packet. */ if (reg & TxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT){ log(LOG_INFO, "%s:%s: PCI Error: 'Retry' exceeds maximum (64k): Reg=0x%X!\n", card->devname,sc->if_name,reg); if (++sc->pci_retry < 3){ bit_set((u_int8_t*)®, TxDMA_HI_DMA_GO_READY_BIT); log(LOG_INFO, "%s: Retry: TXDMA_HI=0x%X DmaDescr=0x%lX (%s)\n", sc->if_name, reg,dma_descr, __FUNCTION__); sdla_bus_write_4(card->hw,dma_descr,reg); return; } } sc->pci_retry=0; sc->tx_dma_mbuf->m_pkthdr.csum = reg; IF_ENQUEUE(&sc->wp_tx_complete_list, sc->tx_dma_mbuf); sc->tx_dma_mbuf=NULL; bit_clear((u_int8_t*)&sc->dma_status, TX_BUSY); xilinx_process_packet(sc); } } static void xilinx_tx_post_complete (sdla_t *card, xilinx_softc_t *sc, struct mbuf *m) { struct ifnet *ifp; unsigned long reg = m->m_pkthdr.csum; WAN_ASSERT1(sc == NULL); ifp = (struct ifnet*)&sc->common.ifp; if ((bit_test((u_int8_t*)®, TxDMA_HI_DMA_GO_READY_BIT)) || (reg & TxDMA_HI_DMA_DATA_LENGTH_MASK) || (reg & TxDMA_HI_DMA_PCI_ERROR_MASK)){ #if defined(DEBUG_TX) log(LOG_INFO, "%s:%s: Tx DMA Descriptor=0x%lX\n", card->devname,sc->if_name,reg); #endif /* Checking Tx DMA Go bit. Has to be '0' */ if (bit_test((u_int8_t*)®, TxDMA_HI_DMA_GO_READY_BIT)){ log(LOG_INFO, "%s:%s: Error: TxDMA Intr: GO bit set on Tx intr\n", card->devname,sc->if_name); } if (reg & TxDMA_HI_DMA_DATA_LENGTH_MASK){ log(LOG_INFO, "%s:%s: Error: TxDMA Length not equal 0 \n", card->devname,sc->if_name); } /* Checking Tx DMA PCI error status. Has to be '0's */ if (reg&TxDMA_HI_DMA_PCI_ERROR_MASK){ if (reg & TxDMA_HI_DMA_PCI_ERROR_M_ABRT){ log(LOG_INFO, "%s:%s: Tx Error: Abort from Master: pci fatal error!\n", card->devname,sc->if_name); } if (reg & TxDMA_HI_DMA_PCI_ERROR_T_ABRT){ log(LOG_INFO, "%s:%s: Tx Error: Abort from Target: pci fatal error!\n", card->devname,sc->if_name); } if (reg & TxDMA_HI_DMA_PCI_ERROR_DS_TOUT){ log(LOG_INFO, "%s:%s: Tx Warning: PCI Latency Timeout!\n", card->devname,sc->if_name); goto tx_post_ok; } if (reg & TxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT){ log(LOG_INFO, "%s:%s: Tx Error: 'Retry' exceeds maximum (64k): pci fatal error!\n", card->devname,sc->if_name); } } goto tx_post_exit; } tx_post_ok: if (ifp){ ifp->if_opackets++; ifp->if_obytes += m->m_len; } /* Indicate that the first tx frame went * out on the transparent link */ bit_set((u_int8_t*)&sc->idle_start, 0); tx_post_exit: if (!xilinx_dma_tx(card,sc)){ /* If we was able to transmit and the interface is set to OACTIVE ** remove this flag and let kernel try to transmit. */ if (ifp->if_flags & IFF_OACTIVE){ ifp->if_flags &= ~IFF_OACTIVE; } } return; } static void xilinx_dma_rx_complete (sdla_t *card, xilinx_softc_t *sc) { unsigned long dma_descr; struct mbuf *m; wp_rx_element_t *rx_el; bit_clear((u_int8_t*)&sc->rx_dma, 0); if (!sc->rx_dma_mbuf){ log(LOG_INFO, "%s: Critical Error: rx_dma_mbuf\n",sc->if_name); return; } rx_el= mtod(sc->rx_dma_mbuf, wp_rx_element_t *); /* Reading Rx DMA descriptor information */ dma_descr=(sc->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_LO; sdla_bus_read_4(card->hw,dma_descr, &rx_el->align); rx_el->align&=RxDMA_LO_ALIGNMENT_BIT_MASK; dma_descr=(sc->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_HI; sdla_bus_read_4(card->hw,dma_descr, &rx_el->reg); rx_el->pkt_error = sc->pkt_error; sc->pkt_error=0; #if defined(DEBUG_RX) log(LOG_INFO, "%s: RX HI=0x%X LO=0x%X DMA=0x%lX (%s:%d)\n", sc->if_name,rx_el->reg,rx_el->align,rx_el->dma_addr, __FUNCTION__,__LINE__); #endif m=sc->rx_dma_mbuf; sc->rx_dma_mbuf=NULL; xilinx_dma_rx(card,sc); IF_ENQUEUE(&sc->wp_rx_complete_list, m); xilinx_process_packet(sc); /* sdla_bus_read_4(card->hw,0x80, &rx_empty); */ } static void xilinx_rx_post_complete (sdla_t *card, xilinx_softc_t *sc, struct mbuf *m, struct mbuf **new_m, unsigned char *pkt_error) { struct ifnet *ifp; unsigned int len,data_error = 0; wp_rx_element_t *rx_el = mtod(m, wp_rx_element_t *); WAN_ASSERT1(sc == NULL); ifp = (struct ifnet*)&sc->common.ifp; /*m->m_pkthdr.rcvif;*/ #if defined(DEBUG_RX) log(LOG_INFO, "%s: RX HI=0x%X LO=0x%X DMA=0x%lX (%s:%d)\n", sc->if_name, rx_el->reg, rx_el->align, rx_el->dma_addr, __FUNCTION__,__LINE__); #endif rx_el->align&=RxDMA_LO_ALIGNMENT_BIT_MASK; *pkt_error=0; *new_m=NULL; /* Checking Rx DMA Go bit. Has to be '0' */ if (bit_test((u_int8_t*)&rx_el->reg, RxDMA_HI_DMA_GO_READY_BIT)){ log(LOG_INFO, "%s: Error: RxDMA Intr: GO bit set on Rx intr\n", card->devname); ifp->if_ierrors++; goto rx_comp_error; } /* Checking Rx DMA PCI error status. Has to be '0's */ if (rx_el->reg&RxDMA_HI_DMA_PCI_ERROR_MASK){ if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_M_ABRT){ #if defined(DEBUG_ERR) log(LOG_INFO, "%s: Rx Error: Abort from Master: pci fatal error!\n", card->devname); #endif } if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_T_ABRT){ #if defined(DEBUG_ERR) log(LOG_INFO, "%s: Rx Error: Abort from Target: pci fatal error!\n", card->devname); #endif } if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_DS_TOUT){ #if defined(DEBUG_ERR) log(LOG_INFO, "%s: Rx Error: No 'DeviceSelect' from target: pci fatal error!\n", card->devname); #endif } if (rx_el->reg & RxDMA_HI_DMA_PCI_ERROR_RETRY_TOUT){ #if defined(DEBUG_ERR) log(LOG_INFO, "%s: Rx Error: 'Retry' exceeds maximum (64k): pci fatal error!\n", card->devname); #endif } #if defined(DEBUG_ERR) log(LOG_INFO, "%s: RXDMA PCI ERROR = 0x%x\n", card->devname,rx_el->reg); #endif if (ifp) ifp->if_ierrors++; goto rx_comp_error; } /* Checking Rx DMA Frame start bit. (information for api) */ if (!bit_test((u_int8_t*)&rx_el->reg, RxDMA_HI_DMA_FRAME_START_BIT)){ #if defined(DEBUG_ERR) log(LOG_INFO, "%s: RxDMA Intr: Start flag missing: MTU Mismatch! Reg=0x%X\n", card->devname,rx_el->reg); #endif if (ifp) ifp->if_ierrors++; goto rx_comp_error; } /* Checking Rx DMA Frame end bit. (information for api) */ if (!bit_test((u_int8_t*)&rx_el->reg, RxDMA_HI_DMA_FRAME_END_BIT)){ #if defined(DEBUG_ERR) log(LOG_INFO, "%s: RxDMA Intr: End flag missing: MTU Mismatch! Reg=0x%X\n", card->devname,rx_el->reg); #endif if (ifp) ifp->if_ierrors++; goto rx_comp_error; } else { /* Check CRC error flag only if this is the end of Frame */ if (bit_test((u_int8_t*)&rx_el->reg, RxDMA_HI_DMA_CRC_ERROR_BIT)){ #if defined(DEBUG_ERR) log(LOG_INFO, "%s: RxDMA Intr: CRC Error! Reg=0x%X\n", card->devname,rx_el->reg); #endif if (ifp) ifp->if_ierrors++; bit_set((u_int8_t*)&rx_el->pkt_error, WP_CRC_ERROR_BIT); data_error = 1; } /* Check if this frame is an abort, if it is * drop it and continue receiving */ if (bit_test((u_int8_t*)&rx_el->reg, RxDMA_HI_DMA_FRAME_ABORT_BIT)){ #if defined(DEBUG_ERR) log(LOG_INFO, "%s: RxDMA Intr: Abort! Reg=0x%X\n", card->devname,rx_el->reg); #endif if (ifp) ifp->if_ierrors++; bit_set((u_int8_t*)&rx_el->pkt_error, WP_ABORT_ERROR_BIT); data_error = 1; } if (data_error){ goto rx_comp_error; } } len=rx_el->reg&RxDMA_HI_DMA_DATA_LENGTH_MASK; /* In HDLC mode, calculate rx length based * on alignment value, received from DMA */ len=(((sc->dma_mtu>>2)-len)<<2) - (~(rx_el->align)&RxDMA_LO_ALIGNMENT_BIT_MASK); *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 (bit_test((u_int8_t*)&rx_el->pkt_error, WP_FIFO_ERROR_BIT)){ if (++sc->rx_fifo_err_cnt >= WP_MAX_FIFO_FRAMES){ sc->rx_fifo_err_cnt=0; } bit_set((u_int8_t*)pkt_error, WP_FIFO_ERROR_BIT); }else{ if (sc->rx_fifo_err_cnt){ if (++sc->rx_fifo_err_cnt >= WP_MAX_FIFO_FRAMES){ sc->rx_fifo_err_cnt=0; } bit_set((u_int8_t*)pkt_error, WP_FIFO_ERROR_BIT); } } if (len > aft_rx_copyback){ /* The rx size is big enough, thus * send this buffer up the stack * and allocate another one */ #if 0 memset(&skb->cb[0],0,sizeof(wp_rx_element_t)); #endif memset(mtod(m, caddr_t),0,sizeof(wp_rx_element_t)); m_adj(m, sizeof(wp_rx_element_t)); m->m_len += len; m->m_pkthdr.len = m->m_len; *new_m=m; aft_alloc_rx_dma_buff(card,sc,1); }else{ struct mbuf *m0; /* The rx packet is very * small thus, allocate a new * buffer and pass it up */ m0 = wan_mbuf_alloc(); if (m0 == NULL){ log(LOG_INFO, "%s: Failed to allocate mbuf!\n", sc->if_name); if (ifp) ifp->if_ierrors++; goto rx_comp_error; } m0->m_len = m0->m_pkthdr.len = len; memcpy(mtod(m0, caddr_t), mtod(m, caddr_t) + m->m_len, len); *new_m = m0; aft_init_requeue_free_m(sc, m); } return; rx_comp_error: aft_init_requeue_free_m(sc, m); return; } static char request_xilinx_logical_channel_num (sdla_t *card, xilinx_softc_t *sc, long *free_ch) { char logic_ch=-1, free_logic_ch=-1; int i,err; *free_ch=-1; #if defined(DEBUG_INIT) log(LOG_INFO, "-- Request_Xilinx_logic_channel_num:--\n"); log(LOG_INFO, "%s: Global Num Timeslots=%d Global Logic ch Map 0x%lX (%s:%d)\n", sc->if_name, card->u.xilinx.num_of_time_slots, card->u.xilinx.logic_ch_map, __FUNCTION__,__LINE__); #endif err=request_fifo_baddr_and_size(card,sc); if (err){ return -1; } for (i=0;iu.xilinx.num_of_time_slots;i++){ if (!bit_test((u_int8_t*)&card->u.xilinx.logic_ch_map, i)){ bit_set((u_int8_t*)&card->u.xilinx.logic_ch_map, i); logic_ch=i; break; } } if (logic_ch == -1){ return logic_ch; } for (i=0;iu.xilinx.num_of_time_slots;i++){ if (!bit_test((u_int8_t*)&card->u.xilinx.logic_ch_map, i)){ free_logic_ch=HDLC_FREE_LOGIC_CH; break; } } if (card->u.xilinx.dev_to_ch_map[(unsigned char)logic_ch]){ log(LOG_INFO, "%s: Error, request logical ch=%d map busy\n", card->devname,logic_ch); return -1; } *free_ch=free_logic_ch; card->u.xilinx.dev_to_ch_map[(unsigned char)logic_ch]=(void*)sc; if (logic_ch > card->u.xilinx.top_logic_ch){ card->u.xilinx.top_logic_ch=logic_ch; xilinx_dma_max_logic_ch(card); } return logic_ch; } static void free_xilinx_logical_channel_num (sdla_t *card, int logic_ch) { bit_clear ((u_int8_t*)&card->u.xilinx.logic_ch_map, logic_ch); card->u.xilinx.dev_to_ch_map[logic_ch]=NULL; if (logic_ch >= card->u.xilinx.top_logic_ch){ int i; card->u.xilinx.top_logic_ch=XILINX_DEFLT_ACTIVE_CH; for (i=0;iu.xilinx.num_of_time_slots;i++){ if (card->u.xilinx.dev_to_ch_map[logic_ch]){ card->u.xilinx.top_logic_ch=i; } } xilinx_dma_max_logic_ch(card); } } static void xilinx_dma_max_logic_ch(sdla_t *card) { u_int32_t reg; #if defined(DEBUG_INIT) log(LOG_INFO, "-- Xilinx_dma_max_logic_ch :--\n"); #endif sdla_bus_read_4(card->hw,XILINX_DMA_CONTROL_REG, ®); /* Set up the current highest active logic channel */ reg&=DMA_ACTIVE_CHANNEL_BIT_MASK; reg|=(card->u.xilinx.top_logic_ch << DMA_ACTIVE_CHANNEL_BIT_SHIFT); sdla_bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); } static int aft_init_requeue_free_m(xilinx_softc_t *sc, struct mbuf *m) { int err; m->m_data = (m->m_flags & M_EXT) ? m->m_ext.ext_buf : m->m_pktdat; m->m_pkthdr.len = m->m_len = 0; memset(mtod(m, caddr_t),0,sizeof(wp_rx_element_t)); IF_ENQUEUE(&sc->wp_rx_free_list, m); return err; } static int aft_alloc_rx_dma_buff(sdla_t *card, xilinx_softc_t *sc, int num) { int i; struct mbuf *m; for (i=0;iif_name,__FUNCTION__); return -ENOMEM; } IF_ENQUEUE(&sc->wp_rx_free_list, m); } return 0; } /*============================================================================ * Enable timer interrupt */ static void enable_timer (void* card_id) { sdla_t *card = (sdla_t*)card_id; int s; s = splnet(); sdla_te_polling(card); splx(s); return; } static void xilinx_process_packet(xilinx_softc_t *sc) { struct ifnet *ifp; struct mbuf *new_m, *m; unsigned char pkt_error; WAN_ASSERT1(sc == NULL); for(;;){ IF_DEQUEUE(&sc->wp_rx_complete_list, m); if (m == NULL) break; new_m=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 */ xilinx_rx_post_complete (sc->common.card, sc, m, &new_m, &pkt_error); if (new_m){ ifp = (struct ifnet*)&sc->common.ifp; #if defined(DEBUG_RX) log(LOG_INFO, "%s: Receiving packet %d bytes!\n", ifp->if_xname, new_m->m_len); #endif wanpipe_generic_input(ifp, new_m); } } for(;;){ IF_DEQUEUE(&sc->wp_tx_complete_list, m); if (m == NULL) break; xilinx_tx_post_complete (sc->common.card,sc,m); m_freem(m); } return; } static int fifo_error_interrupt(sdla_t *card, unsigned long reg) { u_int32_t rx_status, tx_status; u_int32_t err=0; u_int32_t i; xilinx_softc_t *sc; #if defined(DEBUG_ERR) log(LOG_INFO, "%s: Fifo error interrupt!\n", card->devname); #endif /* Clear HDLC pending registers */ sdla_bus_read_4(card->hw,XILINX_HDLC_TX_INTR_PENDING_REG,&tx_status); sdla_bus_read_4(card->hw,XILINX_HDLC_RX_INTR_PENDING_REG,&rx_status); if (card->state != WAN_CONNECTED){ log(LOG_INFO, "%s: Warning: Ignoring Error Intr: link disc!\n", card->devname); return 0; } tx_status&=card->u.xilinx.active_ch_map; rx_status&=card->u.xilinx.active_ch_map; if (tx_status != 0){ for (i=0;iu.xilinx.num_of_time_slots;i++){ if (bit_test((u_int8_t*)&tx_status, i) && bit_test((u_int8_t*)&card->u.xilinx.logic_ch_map, i)){ struct ifnet *ifp; sc=(xilinx_softc_t*)card->u.xilinx.dev_to_ch_map[i]; if (!sc){ log(LOG_INFO, "Warning: ignoring tx error intr: no dev!\n"); continue; } ifp = (struct ifnet*)&sc->common.ifp; #if 0 if (!(ifp->if_flags & IFF_UP)){ log(LOG_INFO, "%s: Warning: ignoring tx error intr: dev down 0x%X UP=0x%X!\n", ifp->if_xname, sc->common.state, sc->ignore_modem); continue; } #endif if (card->state != WAN_CONNECTED){ log(LOG_INFO, "%s: Warning: ignoring tx error intr: dev disc!\n", ifp->if_xname); continue; } #if defined(DEBUG_ERR) log(LOG_INFO, "%s:%s: Warning TX Fifo Error on LogicCh=%ld Slot=%d!\n", card->devname,sc->if_name,sc->logic_ch_num,i); #endif xilinx_tx_fifo_under_recover(card,sc); err=-EINVAL; } } } if (rx_status != 0){ for (i=0;iu.xilinx.num_of_time_slots;i++){ if (bit_test((u_int8_t*)&rx_status, i) && bit_test((u_int8_t*)&card->u.xilinx.logic_ch_map, i)){ struct ifnet *ifp; sc=(xilinx_softc_t*)card->u.xilinx.dev_to_ch_map[i]; if (!sc){ continue; } ifp = (struct ifnet*)&sc->common.ifp; #if 0 if (!(ifp->if_flags & IFF_UP)){ log(LOG_INFO, "%s: Warning: ignoring rx error intr: dev down 0x%X UP=0x%X!\n", ifp->if_xname, sc->common.state, sc->ignore_modem); continue; } #endif if (card->state != WAN_CONNECTED){ log(LOG_INFO, "%s: Warning: ignoring rx error intr: dev disc!\n", ifp->if_xname); continue; } #if defined(DEBUG_ERR) log(LOG_INFO, "%s:%s: Warning RX Fifo Error on LCh=%ld Slot=%d RxCL=%d RxFL=%d RxDMA=%d\n", card->devname, sc->if_name, sc->logic_ch_num, i, sc->wp_rx_complete_list.ifq_len, sc->wp_rx_free_list.ifq_len, sc->rx_dma); #endif #if 0 { unsigned long dma_descr; unsigned int reg; dma_descr=(sc->logic_ch_num<<4) + XILINX_RxDMA_DESCRIPTOR_HI; sdla_bus_read_4(card->hw, dma_descr, ®); log(LOG_INFO, "%s: Hi Descriptor 0x%X\n",sc->if_name,reg); } #endif bit_set((u_int8_t*)&sc->pkt_error, WP_FIFO_ERROR_BIT); err=-EINVAL; } } } return err; } static void front_end_interrupt(sdla_t *card, unsigned long reg) { sdla_te_intr(card); handle_front_end_state(card); return; } /**SECTION*************************************************************** * * HARDWARE Interrupt Handlers * ***********************************************************************/ /*============================================================================ * wan_xilinx_isr * * Main interrupt service routine. * Determin the interrupt received and handle it. * */ static void wp_xilinx_isr (sdla_t* card) { int i; u_int32_t reg; u_int32_t dma_tx_reg,dma_rx_reg; xilinx_softc_t *sc; if (bit_test((u_int8_t*)&card->critical, CARD_DOWN)){ log(LOG_INFO, "%s: Card down, ignoring interrupt !!!!!!!!\n", card->devname); return; } bit_set((u_int8_t*)&card->in_isr, 0); /* write_cpld(card,LED_CONTROL_REG,0x0F);*/ /* -----------------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,XILINX_CHIP_CFG_REG, ®); if (bit_test((u_int8_t*)®, SECURITY_STATUS_FLAG)){ log(LOG_INFO, "%s: Critical: Chip Security Compromised!\n", card->devname); log(LOG_INFO, "%s: Disabling Driver!\n", card->devname); log(LOG_INFO, "%s: Please call Sangoma Tech Suppor!\n", card->devname); log(LOG_INFO, "%s: (www.sangoma.com)!\n", card->devname); port_set_state(card,WAN_DISCONNECTED); disable_data_error_intr(card,CARD_DOWN); goto isr_end; } /* Note: If interrupts are received without pending ** flags, it usually indicates that the interrupt ** is being shared. (Check 'cat /proc/interrupts') */ if (bit_test((u_int8_t*)®, FRONT_END_INTR_ENABLE_BIT)){ if (bit_test((u_int8_t*)®, FRONT_END_INTR_FLAG)){ front_end_interrupt(card,reg); if (card->u.xilinx.state_change_exit_isr){ card->u.xilinx.state_change_exit_isr=0; /* The state change occured, skip all ** other interrupts */ goto isr_end; } } } /* Test Fifo Error Interrupt, ** If set shutdown all interfaces and ** reconfigure */ if (bit_test((u_int8_t*)®, ERROR_INTR_ENABLE_BIT)){ if (bit_test((u_int8_t*)®, ERROR_INTR_FLAG)){ fifo_error_interrupt(card,reg); } } /* -----------------2/6/2003 9:37AM------------------ ** Checking for Interrupt source: ** 1. Receive DMA Engine ** 2. Transmit DMA Engine ** 3. Error conditions. ** --------------------------------------------------*/ if (bit_test((u_int8_t*)®, GLOBAL_INTR_ENABLE_BIT) && bit_test((u_int8_t*)®, DMA_INTR_FLAG)){ /* Receive DMA Engine */ sdla_bus_read_4(card->hw, XILINX_DMA_RX_INTR_PENDING_REG, &dma_rx_reg); dma_rx_reg&=card->u.xilinx.active_ch_map; if (dma_rx_reg == 0){ goto isr_rx; } for (i=0; iu.xilinx.num_of_time_slots ;i++){ if (bit_test((u_int8_t*)&dma_rx_reg, i) && bit_test((u_int8_t*)&card->u.xilinx.logic_ch_map, i)){ sc=(xilinx_softc_t*)card->u.xilinx.dev_to_ch_map[i]; if (!sc){ log(LOG_INFO, "%s: Error: No Dev for Rx logical ch=%d\n", card->devname,i); continue; } xilinx_dma_rx_complete(card,sc); } } isr_rx: /* Transmit DMA Engine */ sdla_bus_read_4(card->hw, XILINX_DMA_TX_INTR_PENDING_REG, &dma_tx_reg); dma_tx_reg&=card->u.xilinx.active_ch_map; if (dma_tx_reg == 0){ goto isr_tx; } for (i=0; iu.xilinx.num_of_time_slots ;i++){ if (bit_test((u_int8_t*)&dma_tx_reg, i) && bit_test((u_int8_t*)&card->u.xilinx.logic_ch_map, i)){ sc=(xilinx_softc_t*)card->u.xilinx.dev_to_ch_map[i]; if (!sc){ log(LOG_INFO, "%s: Error: No Dev for Tx logical ch=%d\n", card->devname,i); continue; } xilinx_dma_tx_complete(card,sc); } } } isr_tx: /* -----------------2/6/2003 10:36AM----------------- * Finish of the interupt handler * --------------------------------------------------*/ isr_end: /* write_cpld(card,LED_CONTROL_REG,0x0E); */ bit_clear((u_int8_t*)&card->in_isr, 0); return; } /**SECTION************************************************************* * * TASK Functions and Triggers * **********************************************************************/ /*============================================================================ * port_set_state * * Set PORT state. * */ static void port_set_state (sdla_t *card, int state) { wanpipe_common_t *common; if (card->state != state){ switch (state){ case WAN_CONNECTED: log(LOG_INFO, "%s: Link connected!\n", card->devname); aft_red_led_ctrl(card,AFT_LED_OFF); aft_green_led_ctrl(card,AFT_LED_ON); break; case WAN_CONNECTING: log(LOG_INFO, "%s: Link connecting...\n", card->devname); aft_red_led_ctrl(card,AFT_LED_ON); aft_green_led_ctrl(card,AFT_LED_OFF); break; case WAN_DISCONNECTED: log(LOG_INFO, "%s: Link disconnected!\n", card->devname); aft_red_led_ctrl(card,AFT_LED_ON); aft_green_led_ctrl(card,AFT_LED_OFF); break; } card->state = state; LIST_FOREACH(common, &card->dev_head, next){ struct ifnet* ifp = (struct ifnet*)&common->ifp; if (ifp){ set_chan_state(card, ifp, state); } } } } /*============================================================ * handle_front_end_state * * */ static void handle_front_end_state(void *card_id) { sdla_t* card = (sdla_t*)card_id; if (card->front_end_status == FE_CONNECTED){ enable_data_error_intr(card); port_set_state(card,WAN_CONNECTED); card->u.xilinx.state_change_exit_isr=1; }else{ port_set_state(card,WAN_CONNECTING); disable_data_error_intr(card,LINK_DOWN); card->u.xilinx.state_change_exit_isr=1; } } static unsigned char read_cpld(sdla_t *card, unsigned short cpld_off) { u_int16_t org_off; u_int8_t tmp; cpld_off &= ~BIT_DEV_ADDR_CLEAR; cpld_off |= BIT_DEV_ADDR_CPLD; /* Save the current address. */ sdla_bus_read_2(card->hw, XILINX_MCPU_INTERFACE_ADDR, &org_off); sdla_bus_write_2(card->hw, XILINX_MCPU_INTERFACE_ADDR, cpld_off); sdla_bus_read_1(card->hw,XILINX_MCPU_INTERFACE, &tmp); /* Restore original address */ sdla_bus_write_2(card->hw, XILINX_MCPU_INTERFACE_ADDR, org_off); return tmp; } static unsigned char write_cpld(sdla_t *card, unsigned short off,unsigned char data) { u_int16_t org_off; off &= ~BIT_DEV_ADDR_CLEAR; off |= BIT_DEV_ADDR_CPLD; /* Save the current original address */ sdla_bus_read_2(card->hw, XILINX_MCPU_INTERFACE_ADDR, &org_off); sdla_bus_write_2(card->hw, XILINX_MCPU_INTERFACE_ADDR, off); /* This delay is required to avoid bridge optimization * (combining two writes together)*/ DELAY(5); sdla_bus_write_1(card->hw, XILINX_MCPU_INTERFACE, data); /* This delay is required to avoid bridge optimization * (combining two writes together)*/ DELAY(5); /* Restore the original address */ sdla_bus_write_2(card->hw, XILINX_MCPU_INTERFACE_ADDR, org_off); return 0; } static unsigned char write_front_end_reg(void* card1, unsigned short off, unsigned char value) { sdla_t* card = (sdla_t*)card1; off &= ~BIT_DEV_ADDR_CLEAR; sdla_bus_write_2(card->hw,XILINX_MCPU_INTERFACE_ADDR, off); /* AF: Sep 10, 2003 * IMPORTANT * This delays are required to avoid bridge optimization * (combining two writes together) */ DELAY(5); sdla_bus_write_1(card->hw,XILINX_MCPU_INTERFACE, value); DELAY(5); return 0; } /*======================================================================= * Read TE1/56K Front end registers */ static unsigned char read_front_end_reg (void* card1, unsigned short off) { sdla_t* card = (sdla_t*)card1; u_int8_t tmp; off &= ~BIT_DEV_ADDR_CLEAR; sdla_bus_write_2(card->hw, XILINX_MCPU_INTERFACE_ADDR, off); sdla_bus_read_1(card->hw,XILINX_MCPU_INTERFACE, &tmp); DELAY(5); return tmp; } /*========================================= * 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) { wanpipe_common_t *common; struct ifnet *ifp; u_int32_t reg; /* Clean Tx/Rx DMA interrupts */ sdla_bus_read_4(card->hw, XILINX_DMA_RX_INTR_PENDING_REG, ®); sdla_bus_read_4(card->hw, XILINX_DMA_TX_INTR_PENDING_REG, ®); /* For all channels clean Tx/Rx fifos */ LIST_FOREACH(common, &card->dev_head, next){ xilinx_softc_t *sc; ifp = (struct ifnet*)&common->ifp; if (!ifp || !ifp->if_softc) continue; sc = ifp->if_softc; #if 0 if (!(ifp->if_flags & IFF_UP)){ continue; } #endif #if defined(DEBUG_INIT) log(LOG_INFO, "%s: Init interface fifo no wait %s\n", sc->if_name, __FUNCTION__); #endif xilinx_init_rx_dev_fifo(card, sc, WP_NO_WAIT); xilinx_init_tx_dev_fifo(card, sc, WP_NO_WAIT); } /* Enable DMA controler, in order to start the ** fifo cleaning */ sdla_bus_read_4(card->hw,XILINX_DMA_CONTROL_REG,®); bit_set((u_int8_t*)®, DMA_ENGINE_ENABLE_BIT); sdla_bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); /* For all channels clean Tx/Rx fifos */ LIST_FOREACH(common, &card->dev_head, next){ xilinx_softc_t *sc; ifp = (struct ifnet*)&common->ifp; if (!ifp || ifp->if_softc == NULL) continue; sc = ifp->if_softc; #if 0 if (!(ifp->if_flags & IFF_UP)){ continue; } #endif #if defined(DEBUG_INIT) log(LOG_INFO, "%s: Init interface fifo %s\n", sc->if_name, __FUNCTION__); #endif xilinx_init_rx_dev_fifo(card, sc, WP_WAIT); xilinx_init_tx_dev_fifo(card, sc, WP_WAIT); #if defined(DEBUG_INIT) log(LOG_INFO, "%s: Clearing Fifo and idle_flag %s\n", card->devname,sc->if_name); #endif bit_clear((u_int8_t*)&sc->idle_start, 0); } /* 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 */ LIST_FOREACH(common, &card->dev_head, next){ xilinx_softc_t *sc; ifp = (struct ifnet*)&common->ifp; if (!ifp || !ifp->if_softc) continue; sc = ifp->if_softc; #if 0 if (!(ifp->if_flags & IFF_UP)){ continue; } #endif #if defined(DEBUG_INIT) log(LOG_INFO, "%s: Init interface %s\n", sc->if_name, __FUNCTION__); #endif if (sc->rx_dma_mbuf){ wp_rx_element_t *rx_el; struct mbuf *m=sc->rx_dma_mbuf; sc->rx_dma_mbuf=NULL; rx_el = mtod(m, wp_rx_element_t *); aft_init_requeue_free_m(sc, m); } xilinx_dma_rx(card,sc); if (sc->tx_dma_addr && sc->tx_dma_len){ sc->tx_dma_addr=0; sc->tx_dma_len=0; } if (sc->tx_dma_mbuf){ m_freem(sc->tx_dma_mbuf); sc->tx_dma_mbuf=NULL; } bit_clear((u_int8_t*)&sc->dma_status, TX_BUSY); bit_clear((u_int8_t*)&sc->idle_start, 0); #if defined(DEBUG_INIT) log(LOG_INFO, "%s: Clearing Fifo and idle_flag %s\n", card->devname,sc->if_name); #endif } /* Clean Tx/Rx Error interrupts, since fifos are now * empty, and Tx fifo may generate an underrun which * we want to ignore :) */ sdla_bus_read_4(card->hw, XILINX_HDLC_RX_INTR_PENDING_REG, ®); sdla_bus_read_4(card->hw, XILINX_HDLC_TX_INTR_PENDING_REG, ®); /* Enable Global DMA and Error Interrupts */ reg=0; sdla_bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); bit_set((u_int8_t*)®, GLOBAL_INTR_ENABLE_BIT); bit_set((u_int8_t*)®, ERROR_INTR_ENABLE_BIT); sdla_bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); return; } static void disable_data_error_intr(sdla_t *card, unsigned char event) { u_int32_t reg; sdla_bus_read_4(card->hw,XILINX_CHIP_CFG_REG,®); bit_clear((u_int8_t*)®, GLOBAL_INTR_ENABLE_BIT); bit_clear((u_int8_t*)®, ERROR_INTR_ENABLE_BIT); if (event==DEVICE_DOWN){ bit_clear((u_int8_t*)®, FRONT_END_INTR_ENABLE_BIT); } sdla_bus_write_4(card->hw,XILINX_CHIP_CFG_REG,reg); sdla_bus_read_4(card->hw,XILINX_DMA_CONTROL_REG,®); bit_clear((u_int8_t*)®, DMA_ENGINE_ENABLE_BIT); sdla_bus_write_4(card->hw,XILINX_DMA_CONTROL_REG,reg); } static void xilinx_init_tx_dma_descr(sdla_t *card, xilinx_softc_t *sc) { unsigned long dma_descr; unsigned long reg=0; dma_descr=(sc->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; sdla_bus_write_4(card->hw,dma_descr, reg); } static void xilinx_tx_fifo_under_recover (sdla_t *card, xilinx_softc_t *sc) { struct ifnet *ifp = (struct ifnet*)&sc->common.ifp; u_int32_t reg=0; unsigned long dma_descr; #if defined(DEBUG_ERR) log(LOG_INFO, "%s:%s: Tx Fifo Recovery \n", card->devname,sc->if_name); #endif /* Initialize Tx DMA descriptor: Stop DMA */ dma_descr=(sc->logic_ch_num<<4) + XILINX_TxDMA_DESCRIPTOR_HI; sdla_bus_write_4(card->hw,dma_descr, reg); /* Clean the TX FIFO */ xilinx_init_tx_dev_fifo(card, sc, WP_WAIT); if (sc->tx_dma_addr && sc->tx_dma_len){ sc->tx_dma_addr=0; sc->tx_dma_len=0; } /* Requeue the current tx packet, for ** re-transmission */ if (sc->tx_dma_mbuf){ IF_PREPEND(&sc->wp_tx_pending_list, (struct mbuf*)sc->tx_dma_mbuf); sc->tx_dma_mbuf=NULL; } /* Wake up the stack, because tx dma interrupt ** failed */ if (ifp) ifp->if_oerrors++; #if defined(DEBUG_ERR) log(LOG_INFO, "%s:%s: Tx Fifo Recovery: Restarting Transmission \n", card->devname,sc->if_name); #endif /* Re-start transmission */ bit_clear((u_int8_t*)&sc->dma_status, TX_BUSY); if (!xilinx_dma_tx(card,sc)){ /* If we was able to transmit and the interface is set ** to OACTIVE remove this flag and let kernel try to ** transmit. */ if (ifp->if_flags & IFF_OACTIVE){ ifp->if_flags &= ~IFF_OACTIVE; } } return; } static int xilinx_write_ctrl_hdlc(sdla_t *card, u_int32_t timeslot, u_int8_t reg_off, u_int32_t data) { u_int32_t reg; u_int32_t ts_orig=timeslot; unsigned long timeout=ticks; if (timeslot == 0){ timeslot=card->u.xilinx.num_of_time_slots-2; }else if (timeslot == 1){ timeslot=card->u.xilinx.num_of_time_slots-1; }else{ timeslot-=2; } timeslot=timeslot<hw,XILINX_TIMESLOT_HDLC_CHAN_REG,®); reg&=XILINX_CURRENT_TIMESLOT_MASK; if (reg == timeslot){ sdla_bus_write_4(card->hw,reg_off,data); return 0; } if ((ticks-timeout) > 1){ log(LOG_INFO, "%s: Error: Access to timeslot %d timed out!\n", card->devname,ts_orig); return -EIO; } } return -EIO; } static int set_chan_state(sdla_t* card, struct ifnet* ifp, int state) { xilinx_softc_t *sc = ifp->if_softc; if (sc == NULL){ return 0; } if (state == WAN_CONNECTED){ #if defined(DEBUG_INIT) log(LOG_INFO, "%s: Setting idle_start to 0\n", sc->if_name); #endif bit_clear((u_int8_t*)&sc->idle_start, 0); } return 0; } static char fifo_size_vector[] = {1, 2, 4, 8, 16, 32}; static char fifo_code_vector[] = {0, 1, 3, 7,0xF,0x1F}; static int request_fifo_baddr_and_size(sdla_t *card, xilinx_softc_t *sc) { unsigned char req_fifo_size,fifo_size; int i; /* Calculate the optimal fifo size based * on the number of time slots requested */ if (IS_T1(&card->fe_te.te_cfg)){ if (sc->num_of_time_slots == NUM_OF_T1_CHANNELS){ req_fifo_size=32; }else if (sc->num_of_time_slots == 1){ req_fifo_size=1; }else if (sc->num_of_time_slots == 2 || sc->num_of_time_slots == 3){ req_fifo_size=2; }else if (sc->num_of_time_slots >= 4 && sc->num_of_time_slots<= 7){ req_fifo_size=4; }else if (sc->num_of_time_slots >= 8 && sc->num_of_time_slots<= 15){ req_fifo_size=8; }else if (sc->num_of_time_slots >= 16 && sc->num_of_time_slots<= 23){ req_fifo_size=16; }else{ log(LOG_INFO, "%s: Invalid number of timeslots %d\n", card->devname, sc->num_of_time_slots); return -EINVAL; } }else{ if (sc->num_of_time_slots == (NUM_OF_E1_CHANNELS-1)){ req_fifo_size=32; }else if (sc->num_of_time_slots == 1){ req_fifo_size=1; }else if (sc->num_of_time_slots == 2 || sc->num_of_time_slots == 3){ req_fifo_size=2; }else if (sc->num_of_time_slots >= 4 && sc->num_of_time_slots <= 7){ req_fifo_size=4; }else if (sc->num_of_time_slots >= 8 && sc->num_of_time_slots <= 15){ req_fifo_size=8; }else if (sc->num_of_time_slots >= 16 && sc->num_of_time_slots <= 31){ req_fifo_size=16; }else{ log(LOG_INFO, "%s:%s: Invalid number of timeslots %d\n", card->devname, sc->if_name, sc->num_of_time_slots); return -EINVAL; } } #if defined(DEBUG_INIT) log(LOG_INFO, "%s:%s: Optimal Fifo Size =%d Timeslots=%d \n", card->devname, sc->if_name, req_fifo_size, sc->num_of_time_slots); #endif fifo_size=map_fifo_baddr_and_size(card, req_fifo_size, &sc->fifo_base_addr); if (fifo_size == 0 || sc->fifo_base_addr == 31){ log(LOG_INFO, "%s:%s: Error: Failed to obtain fifo size %d or addr %d\n", card->devname, sc->if_name, fifo_size, sc->fifo_base_addr); return -EINVAL; } #if defined(DEBUG_INIT) log(LOG_INFO, "%s:%s: Optimal Fifo Size =%d TS=%d New Fifo Size=%d\n", card->devname, sc->if_name, req_fifo_size, sc->num_of_time_slots, fifo_size); #endif for (i=0;ififo_size_code=fifo_code_vector[i]; break; } } if (fifo_size != req_fifo_size){ log(LOG_INFO, "%s:%s: WARN: Failed to obtain the req fifo %d got %d\n", card->devname, sc->if_name, req_fifo_size, fifo_size); } #if defined(DEBUG_INIT) log(LOG_INFO, "%s: %s:Fifo Size=%d TS=%d Fifo Code=%d Addr=%d\n", card->devname,sc->if_name,fifo_size, sc->num_of_time_slots,sc->fifo_size_code, sc->fifo_base_addr); #endif sc->fifo_size = fifo_size; return 0; } static int map_fifo_baddr_and_size(sdla_t *card, unsigned char fifo_size, unsigned char *addr) { u_int32_t reg=0; int i; for (i=0;idevname,reg,card->u.xilinx.fifo_addr_map); #endif for (i=0;i<32;i+=fifo_size){ if (card->u.xilinx.fifo_addr_map & (reg<u.xilinx.fifo_addr_map |= reg<devname,card->u.xilinx.fifo_addr_map,i); #endif return fifo_size; } if (fifo_size == 1){ return 0; } fifo_size = fifo_size >> 1; return map_fifo_baddr_and_size(card,fifo_size,addr); } static int free_fifo_baddr_and_size (sdla_t *card, xilinx_softc_t *sc) { u_int32_t reg=0; int i; for (i=0;ififo_size;i++){ bit_set((u_int8_t*)®, i); } #if defined(DEBUG_INIT) log(LOG_INFO, "%s: Unmapping 0x%X from 0x%lX\n", card->devname, reg<fifo_base_addr, card->u.xilinx.fifo_addr_map); #endif card->u.xilinx.fifo_addr_map &= ~(reg<fifo_base_addr); #if defined(DEBUG_INIT) log(LOG_INFO, "%s: New Map is 0x%lX\n", card->devname, card->u.xilinx.fifo_addr_map); #endif sc->fifo_size=0; sc->fifo_base_addr=0; return 0; } static void aft_red_led_ctrl(sdla_t *card, int mode) { unsigned int led; sdla_bus_read_4(card->hw,XILINX_CHIP_CFG_REG, &led); if (mode == AFT_LED_ON){ bit_clear((u_int8_t*)&led, XILINX_RED_LED); }else if (mode == AFT_LED_OFF){ bit_set((u_int8_t*)&led, XILINX_RED_LED); }else{ if (bit_test((u_int8_t*)&led, XILINX_RED_LED)){ bit_clear((u_int8_t*)&led, XILINX_RED_LED); }else{ bit_set((u_int8_t*)&led, XILINX_RED_LED); } } sdla_bus_write_4(card->hw,XILINX_CHIP_CFG_REG, led); } static void aft_led_timer(void *data) { sdla_t *card=(sdla_t*)data; unsigned int te_alarm; if (bit_test((u_int8_t*)&card->critical, CARD_DOWN)){ return; } if (IS_TE1(&card->fe_te.te_cfg)) { int s = splnet(); te_alarm = sdla_te_alarm(card, 0); te_alarm&=~(BIT_OOSMF_ALARM|BIT_OOCMF_ALARM); if (!te_alarm){ if (card->state == WAN_CONNECTED){ aft_red_led_ctrl(card, AFT_LED_OFF); aft_green_led_ctrl(card, AFT_LED_ON); }else{ aft_red_led_ctrl(card, AFT_LED_OFF); aft_green_led_ctrl(card, AFT_LED_TOGGLE); } }else if (te_alarm & (BIT_RED_ALARM|BIT_LOS_ALARM)){ /* Red or LOS Alarm solid RED */ aft_red_led_ctrl(card, AFT_LED_ON); aft_green_led_ctrl(card, AFT_LED_OFF); }else if (te_alarm & BIT_OOF_ALARM){ /* OOF Alarm flashing RED */ aft_red_led_ctrl(card, AFT_LED_TOGGLE); aft_green_led_ctrl(card, AFT_LED_OFF); }else if (te_alarm & BIT_AIS_ALARM){ /* AIS - Blue Alarm flasing RED and GREEN */ aft_red_led_ctrl(card, AFT_LED_TOGGLE); aft_green_led_ctrl(card, AFT_LED_TOGGLE); }else if (te_alarm & BIT_YEL_ALARM){ /* Yellow Alarm */ aft_red_led_ctrl(card, AFT_LED_ON); aft_green_led_ctrl(card, AFT_LED_ON); }else{ /* Default case shouldn't happen */ log(LOG_INFO, "%s: Unknown Alarm 0x%X\n", card->devname,te_alarm); aft_red_led_ctrl(card, AFT_LED_ON); aft_green_led_ctrl(card, AFT_LED_ON); } splx(s); timeout_add(&card->u.xilinx.led_timer,hz); } } int aft_core_ready(sdla_t *card) { u_int32_t reg; volatile unsigned char cnt=0; for (;;){ sdla_bus_read_4(card->hw,XILINX_CHIP_CFG_REG, ®); if (!bit_test((u_int8_t*)®, HDLC_CORE_READY_FLAG_BIT)){ /* The HDLC Core is not ready! we have ** an error. */ if (++cnt > 5){ return -EINVAL; }else{ DELAY(500); /* WARNING: we cannot do this while in * critical area */ } }else{ return 0; } } return -EINVAL; } /****** End ****************************************************************/