📄 sdla_fr.c
字号:
struct device *dev = card->wandev.dev; struct device *dev2; int i; unsigned long host_cpu_flags; unsigned disable_tx_intr = 1; fr_channel_t *chan; fr_dlci_interface_t *dlci_interface; /* This flag prevents nesting of interrupts. See sdla_isr() routine * in sdlamain.c. */ card->in_isr = 1; ++card->statistics.isr_entry; if (test_and_set_bit(0, (void *) &card->wandev.critical)) { printk(KERN_INFO "fr508_isr: %s, wandev.critical set to 0x%02X, int type = 0x%02X\n", card->devname, card->wandev.critical, flags->iflag); ++card->statistics.isr_already_critical; card->in_isr = 0; return; } /* For all interrupts set the critical flag to CRITICAL_RX_INTR. * If the if_send routine is called with this flag set it will set * the enable transmit flag to 1. (for a delayed interrupt) */ card->wandev.critical = CRITICAL_IN_ISR; card->dlci_int_mode_unbusy = 0; card->buff_int_mode_unbusy = 0; switch (flags->iflag) { case 0x01: /* receive interrupt */ ++card->statistics.isr_rx; fr508_rx_intr(card); break; case 0x02: /* transmit interrupt */ ++card->statistics.isr_tx; bctl = (void *) (flags->tse_offs - FR_MB_VECTOR + card->hw.dpmbase); bctl->flag = 0xA0; if (card->intr_mode == DLCI_LIST_INTR_MODE) { /* Find the structure and make it unbusy */ dev = find_channel(card, flags->dlci); dev->tbusy = 0; /* This is used to perform devtint at the * end of the isr */ card->dlci_int_mode_unbusy = 1; /* check to see if any other interfaces are * busy. If so then do not disable the tx * interrupts */ for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { if (dev2->tbusy == 1) { disable_tx_intr = 0; break; } } if (disable_tx_intr) flags->imask &= ~0x02; } else if (card->intr_mode == BUFFER_INTR_MODE) { for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { if (!dev2 || !dev2->start) { ++card->statistics.tx_intr_dev_not_started; continue; } if (dev2->tbusy) { card->buff_int_mode_unbusy = 1; ((fr_channel_t *) dev2->priv)->dev_pending_devtint = 1; dev2->tbusy = 0; } else ((fr_channel_t *) dev2->priv)->dev_pending_devtint = 0; } flags->imask &= ~0x02; } break; case 0x08: Intr_test_counter++; ++card->statistics.isr_intr_test; break; default: ++card->statistics.isr_spurious; spur_intr(card); printk(KERN_INFO "%s: Interrupt Type 0x%02X!\n", card->devname, flags->iflag); printk(KERN_INFO "%s: ID Bytes = ", card->devname); for (i = 0; i < 8; i++) printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); printk(KERN_INFO "\n"); break; } card->wandev.critical = CRITICAL_INTR_HANDLED; if (card->wandev.enable_tx_int) { if (card->intr_mode == DLCI_LIST_INTR_MODE) { for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) { chan = dev2->priv; if (chan->tx_int_status == WAITING_TO_BE_ENABLED) { dlci_interface = chan->dlci_int_interface; dlci_interface->gen_interrupt |= 0x40; dlci_interface->packet_length = chan->pkt_length; chan->tx_int_status = DISABLED; } } } card->wandev.enable_tx_int = 0; flags->imask |= 0x02; ++card->statistics.isr_enable_tx_int; } save_flags(host_cpu_flags); cli(); card->in_isr = 0; card->wandev.critical = 0xD1; flags->iflag = 0; card->wandev.critical = 0; restore_flags(host_cpu_flags); /* Device is now ready to send. The instant this is executed the If_Send routine is called. That is why this is put at the bottom of the ISR to prevent a endless loop condition caused by repeated Interrupts and enable_tx_int flag. */ if (card->dlci_int_mode_unbusy) mark_bh(NET_BH); if (card->buff_int_mode_unbusy) { for (;;) { if (((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint == 1) { ((fr_channel_t *) ((card->devs_struct)->dev_ptr)->priv)->dev_pending_devtint = 0; mark_bh(NET_BH); } if ((card->devs_struct)->next == card->dev_to_devtint_next) break; card->devs_struct = (card->devs_struct)->next; } card->devs_struct = (card->dev_to_devtint_next)->next; card->dev_to_devtint_next = card->devs_struct; }}/*============================================================================ * Receive interrupt handler. */static void fr502_rx_intr(sdla_t * card){ fr_mbox_t *mbox = card->rxmb; struct sk_buff *skb; struct device *dev; fr_channel_t *chan; unsigned dlci, len; void *buf; unsigned char *sendpacket; unsigned char buf2[3]; int udp_type; sdla_mapmem(&card->hw, FR502_RX_VECTOR); dlci = mbox->cmd.dlci; len = mbox->cmd.length; /* Find network interface for this packet */ dev = find_channel(card, dlci); if (dev == NULL) { /* Invalid channel, discard packet */ printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n", card->devname, dlci); sdla_mapmem(&card->hw, FR_MB_VECTOR); } chan = dev->priv; if (!dev->start) { ++chan->ifstats.rx_dropped; sdla_mapmem(&card->hw, FR_MB_VECTOR); } /* Allocate socket buffer */ skb = dev_alloc_skb(len); if (skb == NULL) { printk(KERN_INFO "%s: no socket buffers available!\n", card->devname); ++chan->ifstats.rx_dropped; sdla_mapmem(&card->hw, FR_MB_VECTOR); } /* Copy data to the socket buffer */ buf = skb_put(skb, len); memcpy(buf, mbox->data, len); sdla_mapmem(&card->hw, FR_MB_VECTOR); /* Check if it's a UDP management packet */ sendpacket = skb->data; memcpy(&buf2, &card->wandev.udp_port, 2); udp_type = udp_pkt_type(skb, card); if ((udp_type == UDP_FPIPE_TYPE) || (udp_type == UDP_DRVSTATS_TYPE)) { if (udp_type == UDP_DRVSTATS_TYPE) { ++chan->rx_intr_DRVSTATS_request; process_udp_driver_call(UDP_PKT_FRM_NETWORK, card, skb, dev, dlci, chan); } else { ++chan->rx_intr_FPIPE_request; process_udp_mgmt_pkt(UDP_PKT_FRM_NETWORK, card, skb, dev, dlci, chan); } } else { /* Decapsulate packet and pass it up the protocol stack */ skb->dev = dev; buf = skb_pull(skb, 1); /* remove hardware header */ if (!wanrouter_type_trans(skb, dev)) { /* can't decapsulate packet */ dev_kfree_skb(skb); ++chan->ifstats.rx_errors; ++card->wandev.stats.rx_errors; } else { netif_rx(skb); ++chan->ifstats.rx_packets; ++card->wandev.stats.rx_packets; chan->ifstats.rx_bytes += skb->len; card->wandev.stats.rx_bytes += skb->len; } } sdla_mapmem(&card->hw, FR_MB_VECTOR);}/*============================================================================ * Receive interrupt handler. */static void fr508_rx_intr(sdla_t * card){ fr_buf_ctl_t *frbuf = card->rxmb; struct sk_buff *skb; struct device *dev; fr_channel_t *chan; unsigned dlci, len, offs; void *buf; unsigned rx_count = 0; fr508_flags_t *flags = card->flags; char *ptr = &flags->iflag; int i, err, udp_type; if (frbuf->flag != 0x01) { printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n", card->devname, (unsigned) frbuf, frbuf->flag); printk(KERN_INFO "%s: ID Bytes = ", card->devname); for (i = 0; i < 8; i++) printk(KERN_INFO "0x%02X ", *(ptr + 0x28 + i)); printk(KERN_INFO "\n"); ++card->statistics.rx_intr_corrupt_rx_bfr; return; } do { len = frbuf->length; dlci = frbuf->dlci; offs = frbuf->offset; /* Find network interface for this packet */ dev = find_channel(card, dlci); chan = dev->priv; if (dev == NULL) { /* Invalid channel, discard packet */ printk(KERN_INFO "%s: receiving on orphaned DLCI %d!\n" ,card->devname, dlci); ++card->statistics.rx_intr_on_orphaned_DLCI; } else { skb = dev_alloc_skb(len); if (!dev->start || (skb == NULL)) { ++chan->ifstats.rx_dropped; if (dev->start) { printk(KERN_INFO "%s: no socket buffers available!\n", card->devname); ++chan->rx_intr_no_socket; } else ++chan->rx_intr_dev_not_started; } else { /* Copy data to the socket buffer */ if ((offs + len) > card->u.f.rx_top + 1) { unsigned tmp = card->u.f.rx_top - offs + 1; buf = skb_put(skb, tmp); sdla_peek(&card->hw, offs, buf, tmp); offs = card->u.f.rx_base; len -= tmp; } buf = skb_put(skb, len); sdla_peek(&card->hw, offs, buf, len); udp_type = udp_pkt_type(skb, card); if (udp_type == UDP_DRVSTATS_TYPE) { ++chan->rx_intr_DRVSTATS_request; process_udp_driver_call( UDP_PKT_FRM_NETWORK, card, skb, dev, dlci, chan); } else if (udp_type == UDP_FPIPE_TYPE) { ++chan->rx_intr_FPIPE_request; err = process_udp_mgmt_pkt( UDP_PKT_FRM_NETWORK, card, skb, dev, dlci, chan); } else if (handle_IPXWAN(skb->data, card->devname, card->wandev.enable_IPX, card->wandev.network_number)) { if (card->wandev.enable_IPX) fr508_send(card, dlci, 0, skb->len, skb->data); } else { /* Decapsulate packet and pass it up the protocol stack */ skb->dev = dev; /* remove hardware header */ buf = skb_pull(skb, 1); if (!wanrouter_type_trans(skb, dev)) { /* can't decapsulate packet */ dev_kfree_skb(skb); ++chan-> rx_intr_bfr_not_passed_to_stack; ++chan-> ifstats.rx_errors; ++card-> wandev.stats.rx_errors; } else { netif_rx(skb); ++chan->rx_intr_bfr_passed_to_stack; ++chan->ifstats.rx_packets; ++card->wandev.stats.rx_packets; chan->ifstats.rx_bytes += skb->len; card->wandev.stats.rx_bytes += skb->len; } } } } /* Release buffer element and calculate a pointer to the next one */ frbuf->flag = 0; card->rxmb = ++frbuf; if ((void *) frbuf > card->u.f.rxmb_last) card->rxmb = card->u.f.rxmb_base; /* The loop put in is temporary, that is why the break is * placed here. (?????) */ break; frbuf = card->rxmb; } while (frbuf->flag && ((++rx_count) < 4));}/*============================================================================ * Transmit interrupt handler. * o print a warning * o * If number of spurious interrupts exceeded some limit, then ??? */static void tx_intr(sdla_t * card){ struct device *dev = card->wandev.dev; if (card->intr_mode == BUFFER_INTR_MODE) { for (; dev; dev = dev->slave) { if (!dev || !dev->start) { ++card->statistics.tx_intr_dev_not_started; continue; } dev->tbusy = 0; mark_bh(NET_BH); } } else { dev->tbusy = 0; mark_bh(NET_BH); }}/*============================================================================ * Spurious interrupt handler. * o print a warning * o * If number of spurious interrupts exceeded some limit, then ??? */static void spur_intr(sdla_t * card){ printk(KERN_INFO "%s: spurious interrupt!\n", card->devname);}/* Return 0 for non-IPXWAN packet 1 for IPXWAN packet or IPX is not enabled! */static int handle_IPXWAN(unsigned char *sendpacket, char *devname, unsigned char enable_IPX, unsigned long network_number){ int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -