📄 sdla_chdlc.c
字号:
unsigned cmd = mb->command; switch (err) { case CMD_TIMEOUT: printk(KERN_INFO "%s: command 0x%02X timed out!\n", card->devname, cmd); break; case S514_BOTH_PORTS_SAME_CLK_MODE: if(cmd == SET_CHDLC_CONFIGURATION) { printk(KERN_INFO "%s: Configure both ports for the same clock source\n", card->devname); break; } default: printk(KERN_INFO "%s: command 0x%02X returned 0x%02X!\n", card->devname, cmd, err); } return 0;}#if defined(LINUX_2_1) || defined(LINUX_2_4)/********** Bottom Half Handlers ********************************************//* NOTE: There is no API, BH support for Kernels lower than 2.2.X. * DO NOT INSERT ANY CODE HERE, NOTICE THE * PREPROCESSOR STATEMENT ABOVE, UNLESS YOU KNOW WHAT YOU ARE * DOING */static void chdlc_bh (netdevice_t * dev){ chdlc_private_area_t* chan = dev->priv; sdla_t *card = chan->card; struct sk_buff *skb; if (atomic_read(&chan->bh_buff_used) == 0){ clear_bit(0, &chan->tq_working); return; } while (atomic_read(&chan->bh_buff_used)){ skb = ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb; if (skb != NULL){ if (chan->common.sk == NULL || chan->common.func == NULL){ ++card->wandev.stats.rx_dropped; wan_dev_kfree_skb(skb, FREE_READ); chdlc_bh_cleanup(dev); continue; } if (chan->common.func(skb,dev,chan->common.sk) != 0){ /* Sock full cannot send, queue us for another * try */ atomic_set(&chan->common.receive_block,1); return; }else{ chdlc_bh_cleanup(dev); } }else{ chdlc_bh_cleanup(dev); } } clear_bit(0, &chan->tq_working); return;}static int chdlc_bh_cleanup (netdevice_t *dev){ chdlc_private_area_t* chan = dev->priv; ((bh_data_t *)&chan->bh_head[chan->bh_read])->skb = NULL; if (chan->bh_read == MAX_BH_BUFF){ chan->bh_read=0; }else{ ++chan->bh_read; } atomic_dec(&chan->bh_buff_used); return 0;}static int bh_enqueue (netdevice_t *dev, struct sk_buff *skb){ /* Check for full */ chdlc_private_area_t* chan = dev->priv; sdla_t *card = chan->card; if (atomic_read(&chan->bh_buff_used) == (MAX_BH_BUFF+1)){ ++card->wandev.stats.rx_dropped; wan_dev_kfree_skb(skb, FREE_READ); return 1; } ((bh_data_t *)&chan->bh_head[chan->bh_write])->skb = skb; if (chan->bh_write == MAX_BH_BUFF){ chan->bh_write=0; }else{ ++chan->bh_write; } atomic_inc(&chan->bh_buff_used); return 0;}/* END OF API BH Support */#endif/****** Interrupt Handlers **************************************************//*============================================================================ * Cisco HDLC interrupt service routine. */static void wpc_isr (sdla_t* card){ netdevice_t* dev; SHARED_MEMORY_INFO_STRUCT* flags = NULL; int i; sdla_t *my_card; /* Check for which port the interrupt has been generated * Since Secondary Port is piggybacking on the Primary * the check must be done here. */ flags = card->u.c.flags; if (!flags->interrupt_info_struct.interrupt_type){ /* Check for a second port (piggybacking) */ if ((my_card = card->next)){ flags = my_card->u.c.flags; if (flags->interrupt_info_struct.interrupt_type){ card = my_card; card->isr(card); return; } } } flags = card->u.c.flags; card->in_isr = 1; dev = card->wandev.dev; /* If we get an interrupt with no network device, stop the interrupts * and issue an error */ if (!card->tty_opt && !dev && flags->interrupt_info_struct.interrupt_type != COMMAND_COMPLETE_APP_INT_PEND){ goto isr_done; } /* if critical due to peripheral operations * ie. update() or getstats() then reset the interrupt and * wait for the board to retrigger. */ if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) { printk(KERN_INFO "ISR CRIT TO PERI\n"); goto isr_done; } /* On a 508 Card, if critical due to if_send * Major Error !!! */ if(card->hw.type != SDLA_S514) { if(test_bit(SEND_CRIT, (void*)&card->wandev.critical)) { printk(KERN_INFO "%s: Critical while in ISR: %lx\n", card->devname, card->wandev.critical); card->in_isr = 0; flags->interrupt_info_struct.interrupt_type = 0; return; } } switch(flags->interrupt_info_struct.interrupt_type) { case RX_APP_INT_PEND: /* 0x01: receive interrupt */ rx_intr(card); break; case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ flags->interrupt_info_struct.interrupt_permission &= ~APP_INT_ON_TX_FRAME;#if defined(LINUX_2_1) || defined(LINUX_2_4) if (card->tty_opt){ wanpipe_tty_trigger_poll(card); break; } if (dev && is_queue_stopped(dev)){ if (card->u.c.usedby == API){ start_net_queue(dev); wakeup_sk_bh(dev); }else{ wake_net_dev(dev); } }#else wake_net_dev(dev);#endif break; case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ ++ Intr_test_counter; break; case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ process_chdlc_exception(card); break; case GLOBAL_EXCEP_COND_APP_INT_PEND: process_global_exception(card); break; case TIMER_APP_INT_PEND: timer_intr(card); break; default: printk(KERN_INFO "%s: spurious interrupt 0x%02X!\n", card->devname, flags->interrupt_info_struct.interrupt_type); printk(KERN_INFO "Code name: "); for(i = 0; i < 4; i ++) printk(KERN_INFO "%c", flags->global_info_struct.codename[i]); printk(KERN_INFO "\nCode version: "); for(i = 0; i < 4; i ++) printk(KERN_INFO "%c", flags->global_info_struct.codeversion[i]); printk(KERN_INFO "\n"); break; }isr_done: card->in_isr = 0; flags->interrupt_info_struct.interrupt_type = 0; return;}/*============================================================================ * Receive interrupt handler. */static void rx_intr (sdla_t* card){ netdevice_t *dev; chdlc_private_area_t *chdlc_priv_area; SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags; CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb; struct sk_buff *skb; unsigned len; unsigned addr = rxbuf->ptr_data_bfr; void *buf; int i,udp_type; if (rxbuf->opp_flag != 0x01) { printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", card->devname, (unsigned)rxbuf, rxbuf->opp_flag); printk(KERN_INFO "Code name: "); for(i = 0; i < 4; i ++) printk(KERN_INFO "%c", flags->global_info_struct.codename[i]); printk(KERN_INFO "\nCode version: "); for(i = 0; i < 4; i ++) printk(KERN_INFO "%c", flags->global_info_struct.codeversion[i]); printk(KERN_INFO "\n"); /* Bug Fix: Mar 6 2000 * If we get a corrupted mailbox, it measn that driver * is out of sync with the firmware. There is no recovery. * If we don't turn off all interrupts for this card * the machine will crash. */ printk(KERN_INFO "%s: Critical router failure ...!!!\n", card->devname); printk(KERN_INFO "Please contact Sangoma Technologies !\n"); chdlc_set_intr_mode(card,0); return; } len = rxbuf->frame_length;#if defined(LINUX_2_4) || defined(LINUX_2_1) if (card->tty_opt){ if (rxbuf->error_flag){ goto rx_exit; } if (len <= CRC_LENGTH){ goto rx_exit; } if (!card->u.c.async_mode){ len -= CRC_LENGTH; } wanpipe_tty_receive(card,addr,len); goto rx_exit; }#endif dev = card->wandev.dev; if (!dev){ goto rx_exit; } if (!is_dev_running(dev)) goto rx_exit; chdlc_priv_area = dev->priv; /* Allocate socket buffer */ skb = dev_alloc_skb(len); if (skb == NULL) { printk(KERN_INFO "%s: no socket buffers available!\n", card->devname); ++card->wandev.stats.rx_dropped; goto rx_exit; } /* Copy data to the socket buffer */ if((addr + len) > card->u.c.rx_top + 1) { unsigned tmp = card->u.c.rx_top - addr + 1; buf = skb_put(skb, tmp); sdla_peek(&card->hw, addr, buf, tmp); addr = card->u.c.rx_base; len -= tmp; } buf = skb_put(skb, len); sdla_peek(&card->hw, addr, buf, len); skb->protocol = htons(ETH_P_IP); card->wandev.stats.rx_packets ++;#if defined(LINUX_2_1) || defined(LINUX_2_4) card->wandev.stats.rx_bytes += skb->len;#endif udp_type = udp_pkt_type( skb, card ); if(udp_type == UDP_CPIPE_TYPE) { if(store_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, dev, chdlc_priv_area)) { flags->interrupt_info_struct. interrupt_permission |= APP_INT_ON_TIMER; }#if defined(LINUX_2_1) || defined(LINUX_2_4) } else if(card->u.c.usedby == API) { api_rx_hdr_t* api_rx_hdr; skb_push(skb, sizeof(api_rx_hdr_t)); api_rx_hdr = (api_rx_hdr_t*)&skb->data[0x00]; api_rx_hdr->error_flag = rxbuf->error_flag; api_rx_hdr->time_stamp = rxbuf->time_stamp; skb->protocol = htons(PVC_PROT); skb->mac.raw = skb->data; skb->dev = dev; skb->pkt_type = WAN_PACKET_DATA; bh_enqueue(dev, skb); if (!test_and_set_bit(0,&chdlc_priv_area->tq_working)){ wanpipe_queue_tq(&chdlc_priv_area->common.wanpipe_task); wanpipe_mark_bh(); }#endif }else{ /* FIXME: we should check to see if the received packet is a multicast packet so that we can increment the multicast statistic ++ chdlc_priv_area->if_stats.multicast; */ /* Pass it up the protocol stack */ skb->dev = dev; skb->mac.raw = skb->data; netif_rx(skb); }rx_exit: /* Release buffer element and calculate a pointer to the next one */ rxbuf->opp_flag = 0x00; card->u.c.rxmb = ++ rxbuf; if((void*)rxbuf > card->u.c.rxbuf_last){ card->u.c.rxmb = card->u.c.rxbuf_base; }}/*============================================================================ * Timer interrupt handler. * The timer interrupt is used for two purposes: * 1) Processing udp calls from 'cpipemon'. * 2) Reading board-level statistics for updating the proc file system. */void timer_intr(sdla_t *card){ netdevice_t* dev; chdlc_private_area_t* chdlc_priv_area = NULL; SHARED_MEMORY_INFO_STRUCT* flags = NULL; if ((dev = card->wandev.dev)==NULL){ flags = card->u.c.flags; flags->interrupt_info_struct.interrupt_permission &= ~APP_INT_ON_TIMER; return; } chdlc_priv_area = dev->priv; if (chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_CONFIG) { if (!config_chdlc(card)){ chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_CONFIG; } } /* process a udp call if pending */ if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UDP) { process_udp_mgmt_pkt(card, dev, chdlc_priv_area); chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UDP; } /* read the communications statistics if required */ if(chdlc_priv_area->timer_int_enabled & TMR_INT_ENABLED_UPDATE) { update_comms_stats(card, chdlc_priv_area); if(!(-- chdlc_priv_area->update_comms_stats)) { chdlc_priv_area->timer_int_enabled &= ~TMR_INT_ENABLED_UPDATE; } } /* only disable the timer interrupt if there are no udp or statistic */ /* updates pending */ if(!chdlc_priv_area->timer_int_enab
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -