📄 sdla_chdlc.c
字号:
/* on the first timer interrupt, read the comms error statistics */ if(chdlc_priv_area->update_comms_stats == 2) { if(chdlc_read_comm_err_stats(card)) return 1; err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->data; card->wandev.stats.rx_over_errors = err_stats->Rx_overrun_err_count; card->wandev.stats.rx_crc_errors = err_stats->CRC_err_count; card->wandev.stats.rx_frame_errors = err_stats->Rx_abort_count; card->wandev.stats.rx_fifo_errors = err_stats->Rx_dis_pri_bfrs_full_count; card->wandev.stats.rx_missed_errors = card->wandev.stats.rx_fifo_errors; card->wandev.stats.tx_aborted_errors = err_stats->sec_Tx_abort_count; } /* on the second timer interrupt, read the operational statistics */ else { if(chdlc_read_op_stats(card)) return 1; op_stats = (CHDLC_OPERATIONAL_STATS_STRUCT *)mb->data; card->wandev.stats.rx_length_errors = (op_stats->Rx_Data_discard_short_count + op_stats->Rx_Data_discard_long_count); } return 0;}/*============================================================================ * Send packet. * Return: 0 - o.k. * 1 - no transmit buffers available */static int chdlc_send (sdla_t* card, void* data, unsigned len){ CHDLC_DATA_TX_STATUS_EL_STRUCT *txbuf = card->u.c.txbuf; if (txbuf->opp_flag) return 1; sdla_poke(&card->hw, txbuf->ptr_data_bfr, data, len); txbuf->frame_length = len; txbuf->opp_flag = 1; /* start transmission */ /* Update transmit buffer control fields */ card->u.c.txbuf = ++txbuf; if ((void*)txbuf > card->u.c.txbuf_last) card->u.c.txbuf = card->u.c.txbuf_base; return 0;}/****** Firmware Error Handler **********************************************//*============================================================================ * Firmware error handler. * This routine is called whenever firmware command returns non-zero * return code. * * Return zero if previous command has to be cancelled. */static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb){ unsigned cmd = mb->command; switch (err) { case CMD_TIMEOUT: printk(KERN_ERR "%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;}/****** Interrupt Handlers **************************************************//*============================================================================ * Cisco HDLC interrupt service routine. */STATIC void wpc_isr (sdla_t* card){ struct net_device* dev; chdlc_private_area_t* chdlc_priv_area; SHARED_MEMORY_INFO_STRUCT* flags = NULL; int i, interrupt_serviced = 0; 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; } } } dev = card->wandev.dev; card->in_isr = 1; /* if critical due to peripheral operations * ie. update() or getstats() then reset the interrupt and * wait for the board to retrigger. */ if(test_bit(1, (void*)&card->wandev.critical)) { if(card->u.c.flags != NULL) { flags = card->u.c.flags; if(flags->interrupt_info_struct. interrupt_type) { flags->interrupt_info_struct. interrupt_type = 0; } } card->in_isr = 0; return; } /* On a 508 Card, if critical due to if_send * Major Error !!! */ if(card->hw.type != SDLA_S514) { if(test_and_set_bit(0, (void*)&card->wandev.critical)) { printk(KERN_INFO "%s: Critical while in ISR: %x\n", card->devname, card->wandev.critical); card->in_isr = 0; return; } } /* FIXME: Take this check out later in the future */ if(card->u.c.flags != NULL) { flags = card->u.c.flags; switch(flags->interrupt_info_struct.interrupt_type) { case RX_APP_INT_PEND: /* 0x01: receive interrupt */ interrupt_serviced = 1; rx_intr(card); break; case TX_APP_INT_PEND: /* 0x02: transmit interrupt */ interrupt_serviced = 1; flags->interrupt_info_struct.interrupt_permission &= ~APP_INT_ON_TX_FRAME; chdlc_priv_area = dev->priv; netif_wake_queue(dev); break; case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */ interrupt_serviced = 1; ++ Intr_test_counter; break; case CHDLC_EXCEP_COND_APP_INT_PEND: /* 0x20 */ interrupt_serviced = 1; process_chdlc_exception(card); break; case GLOBAL_EXCEP_COND_APP_INT_PEND: interrupt_serviced = 1; process_global_exception(card); break; case TIMER_APP_INT_PEND: interrupt_serviced = 1; timer_intr(card); break; default: break; } } if(!interrupt_serviced) { 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"); } card->in_isr = 0; flags->interrupt_info_struct.interrupt_type = 0; if(card->hw.type != SDLA_S514){ clear_bit(0, (void*)&card->wandev.critical); } }/*============================================================================ * Receive interrupt handler. */static void rx_intr (sdla_t* card){ struct net_device *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; 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"); return; } dev = card->wandev.dev; chdlc_priv_area = dev->priv; if(dev && netif_running(dev)) { len = rxbuf->frame_length; /* Allocate socket buffer */ skb = dev_alloc_skb(len); if (skb != NULL) { /* Copy data to the socket buffer */ unsigned addr = rxbuf->ptr_data_bfr; 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); /* Decapsulate packet */ skb->protocol = htons(ETH_P_IP); card->wandev.stats.rx_packets ++;#ifdef LINUX_2_1 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; } } 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(0x16); skb->pkt_type = PACKET_HOST; }/* 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); } } else { printk(KERN_INFO "%s: no socket buffers available!\n", card->devname); ++card->wandev.stats.rx_dropped; } } /* 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){ struct net_device* dev; chdlc_private_area_t* chdlc_priv_area = NULL; SHARED_MEMORY_INFO_STRUCT* flags = NULL; dev = card->wandev.dev; chdlc_priv_area = dev->priv; /* 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_enabled) { flags = card->u.c.flags; flags->interrupt_info_struct.interrupt_permission &= ~APP_INT_ON_TIMER; }}/*------------------------------------------------------------------------------ Miscellaneous Functions - set_chdlc_config() used to set configuration options on the board------------------------------------------------------------------------------*/static int set_chdlc_config(sdla_t* card){ struct net_device * dev = card->wandev.dev; chdlc_private_area_t *chdlc_priv_area = dev->priv; CHDLC_CONFIGURATION_STRUCT cfg; memset(&cfg, 0, sizeof(CHDLC_CONFIGURATION_STRUCT)); if(card->wandev.clocking) cfg.baud_rate = card->wandev.bps; cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ? INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35; cfg.modem_config_options = 0; cfg.modem_status_timer = 100; cfg.CHDLC_protocol_options = card->u.c.protocol_options; cfg.percent_data_buffer_for_Tx = 50; cfg.CHDLC_statistics_options = (CHDLC_TX_DATA_BYTE_COUNT_STAT | CHDLC_RX_DATA_BYTE_COUNT_STAT); cfg.max_CHDLC_data_field_length = card->wandev.mtu; cfg.transmit_keepalive_timer = card->u.c.kpalv_tx; cfg.receive_keepalive_timer = card->u.c.kpalv_rx; cfg.keepalive_error_tolerance = card->u.c.kpalv_err; cfg.SLARP_request_timer = card->u.c.slarp_timer; if (cfg.SLARP_request_timer) { cfg.IP_address = 0; cfg.IP_netmask = 0; } else {#ifdef LINUX_2_1 struct in_device *in_dev = dev->ip_ptr; if(in_dev != NULL) { struct in_ifaddr *ifa = in_dev->ifa_list; if (ifa != NULL ) { cfg.IP_address = ntohl(ifa->ifa_local); cfg.IP_netmask = ntohl(ifa->ifa_mask); chdlc_priv_area->IP_address = ntohl(ifa->ifa_local); chdlc_priv_area->IP_netmask = ntohl(ifa->ifa_mask); } }#else cfg.IP_address = ntohl(dev->pa_addr); cfg.IP_netmask = ntohl(dev->pa_mask); chdlc_priv_area->IP_address = ntohl(dev->pa_addr); chdlc_priv_area->IP_netmask = ntohl(dev->pa_mask);#endif /* FIXME: We must re-think this message in next release if((cfg.IP_address & 0x000000FF) > 2) { printk(KERN_WARNING "\n"); printk(KERN_WARNING " WARNING:%s configured with an\n", card->devname); printk(KERN_WARNING " invalid local IP address.\n"); printk(KERN_WARNING " Slarp pragmatics will fail.\n"); printk(KERN_WARNING " IP address should be of the\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -