📄 farsync.c
字号:
spin_unlock_irqrestore(&card->card_lock, flags); schedule_timeout(1); spin_lock_irqsave(&card->card_lock, flags); if (++safety > 2000) { printk_err("Mailbox safety timeout\n"); break; } mbval = FST_RDW(card, portMailbox[port->index][0]); } if (safety > 0) { dbg(DBG_CMD, "Mailbox clear after %d jiffies\n", safety); } if (mbval == NAK) { dbg(DBG_CMD, "issue_cmd: previous command was NAK'd\n"); } FST_WRW(card, portMailbox[port->index][0], cmd); if (cmd == ABORTTX || cmd == STARTPORT) { port->txpos = 0; port->txipos = 0; port->start = 0; } spin_unlock_irqrestore(&card->card_lock, flags);}/* Port output signals control */static inline voidfst_op_raise(struct fst_port_info *port, unsigned int outputs){ outputs |= FST_RDL(port->card, v24OpSts[port->index]); FST_WRL(port->card, v24OpSts[port->index], outputs); if (port->run) fst_issue_cmd(port, SETV24O);}static inline voidfst_op_lower(struct fst_port_info *port, unsigned int outputs){ outputs = ~outputs & FST_RDL(port->card, v24OpSts[port->index]); FST_WRL(port->card, v24OpSts[port->index], outputs); if (port->run) fst_issue_cmd(port, SETV24O);}/* * Setup port Rx buffers */static voidfst_rx_config(struct fst_port_info *port){ int i; int pi; unsigned int offset; unsigned long flags; struct fst_card_info *card; pi = port->index; card = port->card; spin_lock_irqsave(&card->card_lock, flags); for (i = 0; i < NUM_RX_BUFFER; i++) { offset = BUF_OFFSET(rxBuffer[pi][i][0]); FST_WRW(card, rxDescrRing[pi][i].ladr, (u16) offset); FST_WRB(card, rxDescrRing[pi][i].hadr, (u8) (offset >> 16)); FST_WRW(card, rxDescrRing[pi][i].bcnt, cnv_bcnt(LEN_RX_BUFFER)); FST_WRW(card, rxDescrRing[pi][i].mcnt, LEN_RX_BUFFER); FST_WRB(card, rxDescrRing[pi][i].bits, DMA_OWN); } port->rxpos = 0; spin_unlock_irqrestore(&card->card_lock, flags);}/* * Setup port Tx buffers */static voidfst_tx_config(struct fst_port_info *port){ int i; int pi; unsigned int offset; unsigned long flags; struct fst_card_info *card; pi = port->index; card = port->card; spin_lock_irqsave(&card->card_lock, flags); for (i = 0; i < NUM_TX_BUFFER; i++) { offset = BUF_OFFSET(txBuffer[pi][i][0]); FST_WRW(card, txDescrRing[pi][i].ladr, (u16) offset); FST_WRB(card, txDescrRing[pi][i].hadr, (u8) (offset >> 16)); FST_WRW(card, txDescrRing[pi][i].bcnt, 0); FST_WRB(card, txDescrRing[pi][i].bits, 0); } port->txpos = 0; port->txipos = 0; port->start = 0; spin_unlock_irqrestore(&card->card_lock, flags);}/* TE1 Alarm change interrupt event */static voidfst_intr_te1_alarm(struct fst_card_info *card, struct fst_port_info *port){ u8 los; u8 rra; u8 ais; los = FST_RDB(card, suStatus.lossOfSignal); rra = FST_RDB(card, suStatus.receiveRemoteAlarm); ais = FST_RDB(card, suStatus.alarmIndicationSignal); if (los) { /* * Lost the link */ if (netif_carrier_ok(port_to_dev(port))) { dbg(DBG_INTR, "Net carrier off\n"); netif_carrier_off(port_to_dev(port)); } } else { /* * Link available */ if (!netif_carrier_ok(port_to_dev(port))) { dbg(DBG_INTR, "Net carrier on\n"); netif_carrier_on(port_to_dev(port)); } } if (los) dbg(DBG_INTR, "Assert LOS Alarm\n"); else dbg(DBG_INTR, "De-assert LOS Alarm\n"); if (rra) dbg(DBG_INTR, "Assert RRA Alarm\n"); else dbg(DBG_INTR, "De-assert RRA Alarm\n"); if (ais) dbg(DBG_INTR, "Assert AIS Alarm\n"); else dbg(DBG_INTR, "De-assert AIS Alarm\n");}/* Control signal change interrupt event */static voidfst_intr_ctlchg(struct fst_card_info *card, struct fst_port_info *port){ int signals; signals = FST_RDL(card, v24DebouncedSts[port->index]); if (signals & (((port->hwif == X21) || (port->hwif == X21D)) ? IPSTS_INDICATE : IPSTS_DCD)) { if (!netif_carrier_ok(port_to_dev(port))) { dbg(DBG_INTR, "DCD active\n"); netif_carrier_on(port_to_dev(port)); } } else { if (netif_carrier_ok(port_to_dev(port))) { dbg(DBG_INTR, "DCD lost\n"); netif_carrier_off(port_to_dev(port)); } }}/* Log Rx Errors */static voidfst_log_rx_error(struct fst_card_info *card, struct fst_port_info *port, unsigned char dmabits, int rxp, unsigned short len){ struct net_device *dev = port_to_dev(port); struct net_device_stats *stats = hdlc_stats(dev); /* * Increment the appropriate error counter */ stats->rx_errors++; if (dmabits & RX_OFLO) { stats->rx_fifo_errors++; dbg(DBG_ASS, "Rx fifo error on card %d port %d buffer %d\n", card->card_no, port->index, rxp); } if (dmabits & RX_CRC) { stats->rx_crc_errors++; dbg(DBG_ASS, "Rx crc error on card %d port %d\n", card->card_no, port->index); } if (dmabits & RX_FRAM) { stats->rx_frame_errors++; dbg(DBG_ASS, "Rx frame error on card %d port %d\n", card->card_no, port->index); } if (dmabits == (RX_STP | RX_ENP)) { stats->rx_length_errors++; dbg(DBG_ASS, "Rx length error (%d) on card %d port %d\n", len, card->card_no, port->index); }}/* Rx Error Recovery */static voidfst_recover_rx_error(struct fst_card_info *card, struct fst_port_info *port, unsigned char dmabits, int rxp, unsigned short len){ int i; int pi; pi = port->index; /* * Discard buffer descriptors until we see the start of the * next frame. Note that for long frames this could be in * a subsequent interrupt. */ i = 0; while ((dmabits & (DMA_OWN | RX_STP)) == 0) { FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN); rxp = (rxp+1) % NUM_RX_BUFFER; if (++i > NUM_RX_BUFFER) { dbg(DBG_ASS, "intr_rx: Discarding more bufs" " than we have\n"); break; } dmabits = FST_RDB(card, rxDescrRing[pi][rxp].bits); dbg(DBG_ASS, "DMA Bits of next buffer was %x\n", dmabits); } dbg(DBG_ASS, "There were %d subsequent buffers in error\n", i); /* Discard the terminal buffer */ if (!(dmabits & DMA_OWN)) { FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN); rxp = (rxp+1) % NUM_RX_BUFFER; } port->rxpos = rxp; return;}/* Rx complete interrupt */static voidfst_intr_rx(struct fst_card_info *card, struct fst_port_info *port){ unsigned char dmabits; int pi; int rxp; int rx_status; unsigned short len; struct sk_buff *skb; struct net_device *dev = port_to_dev(port); struct net_device_stats *stats = hdlc_stats(dev); /* Check we have a buffer to process */ pi = port->index; rxp = port->rxpos; dmabits = FST_RDB(card, rxDescrRing[pi][rxp].bits); if (dmabits & DMA_OWN) { dbg(DBG_RX | DBG_INTR, "intr_rx: No buffer port %d pos %d\n", pi, rxp); return; } if (card->dmarx_in_progress) { return; } /* Get buffer length */ len = FST_RDW(card, rxDescrRing[pi][rxp].mcnt); /* Discard the CRC */ len -= 2; if (len == 0) { /* * This seems to happen on the TE1 interface sometimes * so throw the frame away and log the event. */ printk_err("Frame received with 0 length. Card %d Port %d\n", card->card_no, port->index); /* Return descriptor to card */ FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN); rxp = (rxp+1) % NUM_RX_BUFFER; port->rxpos = rxp; return; } /* Check buffer length and for other errors. We insist on one packet * in one buffer. This simplifies things greatly and since we've * allocated 8K it shouldn't be a real world limitation */ dbg(DBG_RX, "intr_rx: %d,%d: flags %x len %d\n", pi, rxp, dmabits, len); if (dmabits != (RX_STP | RX_ENP) || len > LEN_RX_BUFFER - 2) { fst_log_rx_error(card, port, dmabits, rxp, len); fst_recover_rx_error(card, port, dmabits, rxp, len); return; } /* Allocate SKB */ if ((skb = dev_alloc_skb(len)) == NULL) { dbg(DBG_RX, "intr_rx: can't allocate buffer\n"); stats->rx_dropped++; /* Return descriptor to card */ FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN); rxp = (rxp+1) % NUM_RX_BUFFER; port->rxpos = rxp; return; } /* * We know the length we need to receive, len. * It's not worth using the DMA for reads of less than * FST_MIN_DMA_LEN */ if ((len < FST_MIN_DMA_LEN) || (card->family == FST_FAMILY_TXP)) { memcpy_fromio(skb_put(skb, len), card->mem + BUF_OFFSET(rxBuffer[pi][rxp][0]), len); /* Reset buffer descriptor */ FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN); /* Update stats */ stats->rx_packets++; stats->rx_bytes += len; /* Push upstream */ dbg(DBG_RX, "Pushing frame up the stack\n"); skb->mac.raw = skb->data; skb->dev = dev; if (port->mode == FST_RAW) { /* * Mark it for our own raw sockets interface */ skb->protocol = htons(ETH_P_CUST); skb->pkt_type = PACKET_HOST; } else { skb->protocol = hdlc_type_trans(skb, skb->dev); } rx_status = netif_rx(skb); fst_process_rx_status(rx_status, port_to_dev(port)->name); if (rx_status == NET_RX_DROP) { stats->rx_dropped++; } dev->last_rx = jiffies; } else { card->dma_skb_rx = skb; card->dma_port_rx = port; card->dma_len_rx = len; card->dma_rxpos = rxp; fst_rx_dma(card, (char *) card->rx_dma_handle_card, (char *) BUF_OFFSET(rxBuffer[pi][rxp][0]), len); } if (rxp != port->rxpos) { dbg(DBG_ASS, "About to increment rxpos by more than 1\n"); dbg(DBG_ASS, "rxp = %d rxpos = %d\n", rxp, port->rxpos); } rxp = (rxp+1) % NUM_RX_BUFFER; port->rxpos = rxp;}/* * The bottom halfs to the ISR * */static voiddo_bottom_half_tx(struct fst_card_info *card){ struct fst_port_info *port; int pi; int txq_length; struct sk_buff *skb; unsigned long flags; struct net_device *dev; struct net_device_stats *stats; /* * Find a free buffer for the transmit * Step through each port on this card */ dbg(DBG_TX, "do_bottom_half_tx\n"); for (pi = 0, port = card->ports; pi < card->nports; pi++, port++) { if (!port->run) continue; dev = port_to_dev(port); stats = hdlc_stats(dev); while (! (FST_RDB(card, txDescrRing[pi][port->txpos].bits) & DMA_OWN) && !(card->dmatx_in_progress)) { /* * There doesn't seem to be a txdone event per-se * We seem to have to deduce it, by checking the DMA_OWN * bit on the next buffer we think we can use */ spin_lock_irqsave(&card->card_lock, flags); if ((txq_length = port->txqe - port->txqs) < 0) { /* * This is the case where one has wrapped and the * maths gives us a negative number */ txq_length = txq_length + FST_TXQ_DEPTH; } spin_unlock_irqrestore(&card->card_lock, flags); if (txq_length > 0) { /* * There is something to send */ spin_lock_irqsave(&card->card_lock, flags); skb = port->txq[port->txqs]; port->txqs++; if (port->txqs == FST_TXQ_DEPTH) { port->txqs = 0; } spin_unlock_irqrestore(&card->card_lock, flags); /* * copy the data and set the required indicators on the * card. */ FST_WRW(card, txDescrRing[pi][port->txpos].bcnt, cnv_bcnt(skb->len)); if ((skb->len < FST_MIN_DMA_LEN) || (card->family == FST_FAMILY_TXP)) { /* Enqueue the packet with normal io */ memcpy_toio(card->mem + BUF_OFFSET(txBuffer[pi] [port-> txpos][0]), skb->data, skb->len); FST_WRB(card, txDescrRing[pi][port->txpos]. bits, DMA_OWN | TX_STP | TX_ENP); stats->tx_packets++; stats->tx_bytes += skb->len; dev->trans_start = jiffies; } else { /* Or do it through dma */ memcpy(card->tx_dma_handle_host, skb->data, skb->len); card->dma_port_tx = port; card->dma_len_tx = skb->len; card->dma_txpos = port->txpos; fst_tx_dma(card, (char *) card-> tx_dma_handle_card, (char *) BUF_OFFSET(txBuffer[pi] [port->txpos][0]), skb->len); } if (++port->txpos >= NUM_TX_BUFFER) port->txpos = 0; /* * If we have flow control on, can we now release it? */ if (port->start) { if (txq_length < fst_txq_low) { netif_wake_queue(port_to_dev (port)); port->start = 0; } } dev_kfree_skb(skb); } else { /* * Nothing to send so break out of the while loop */ break; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -