int RIORFlushEnable(unsigned long iPortP, struct CmdBlk *CmdBlkP) { struct Port *PortP = (struct Port *) iPortP; struct PKT __iomem *PacketP; unsigned long flags; rio_spin_lock_irqsave(&PortP->portSem, flags); while (can_remove_receive(&PacketP, PortP)) { remove_receive(PortP); put_free_end(PortP->HostP, PacketP); } if (readw(&PortP->PhbP->handshake) == PHB_HANDSHAKE_SET) { /* ** MAGIC! (Basically, handshake the RX buffer, so that ** the RTAs upstream can be re-enabled.) */ rio_dprintk(RIO_DEBUG_CMD, "Util: Set RX handshake bit\n"); writew(PHB_HANDSHAKE_SET | PHB_HANDSHAKE_RESET, &PortP->PhbP->handshake); } rio_spin_unlock_irqrestore(&PortP->portSem, flags); return RIOUnUse(iPortP, CmdBlkP); }
/* ** Routine for handling received data for tty drivers */ static void RIOReceive(struct rio_info *p, struct Port *PortP) { struct tty_struct *TtyP; unsigned short transCount; struct PKT __iomem *PacketP; register unsigned int DataCnt; unsigned char __iomem *ptr; unsigned char *buf; int copied = 0; static int intCount, RxIntCnt; /* ** The receive data process is to remove packets from the ** PHB until there aren't any more or the current cblock ** is full. When this occurs, there will be some left over ** data in the packet, that we must do something with. ** As we haven't unhooked the packet from the read list ** yet, we can just leave the packet there, having first ** made a note of how far we got. This means that we need ** a pointer per port saying where we start taking the ** data from - this will normally be zero, but when we ** run out of space it will be set to the offset of the ** next byte to copy from the packet data area. The packet ** length field is decremented by the number of bytes that ** we successfully removed from the packet. When this reaches ** zero, we reset the offset pointer to be zero, and free ** the packet from the front of the queue. */ intCount++; TtyP = PortP->gs.tty; if (!TtyP) { rio_dprintk(RIO_DEBUG_INTR, "RIOReceive: tty is null. \n"); return; } if (PortP->State & RIO_THROTTLE_RX) { rio_dprintk(RIO_DEBUG_INTR, "RIOReceive: Throttled. Can't handle more input.\n"); return; } if (PortP->State & RIO_DELETED) { while (can_remove_receive(&PacketP, PortP)) { remove_receive(PortP); put_free_end(PortP->HostP, PacketP); } } else { /* ** loop, just so long as: ** i ) there's some data ( i.e. can_remove_receive ) ** ii ) we haven't been blocked ** iii ) there's somewhere to put the data ** iv ) we haven't outstayed our welcome */ transCount = 1; while (can_remove_receive(&PacketP, PortP) && transCount) { RxIntCnt++; /* ** check that it is not a command! */ if (readb(&PacketP->len) & PKT_CMD_BIT) { rio_dprintk(RIO_DEBUG_INTR, "RIO: unexpected command packet received on PHB\n"); /* rio_dprint(RIO_DEBUG_INTR, (" sysport = %d\n", p->RIOPortp->PortNum)); */ rio_dprintk(RIO_DEBUG_INTR, " dest_unit = %d\n", readb(&PacketP->dest_unit)); rio_dprintk(RIO_DEBUG_INTR, " dest_port = %d\n", readb(&PacketP->dest_port)); rio_dprintk(RIO_DEBUG_INTR, " src_unit = %d\n", readb(&PacketP->src_unit)); rio_dprintk(RIO_DEBUG_INTR, " src_port = %d\n", readb(&PacketP->src_port)); rio_dprintk(RIO_DEBUG_INTR, " len = %d\n", readb(&PacketP->len)); rio_dprintk(RIO_DEBUG_INTR, " control = %d\n", readb(&PacketP->control)); rio_dprintk(RIO_DEBUG_INTR, " csum = %d\n", readw(&PacketP->csum)); rio_dprintk(RIO_DEBUG_INTR, " data bytes: "); for (DataCnt = 0; DataCnt < PKT_MAX_DATA_LEN; DataCnt++) rio_dprintk(RIO_DEBUG_INTR, "%d\n", readb(&PacketP->data[DataCnt])); remove_receive(PortP); put_free_end(PortP->HostP, PacketP); continue; /* with next packet */ } /* ** How many characters can we move 'upstream' ? ** ** Determine the minimum of the amount of data ** available and the amount of space in which to ** put it. ** ** 1. Get the packet length by masking 'len' ** for only the length bits. ** 2. Available space is [buffer size] - [space used] ** ** Transfer count is the minimum of packet length ** and available space. */ transCount = tty_buffer_request_room(TtyP, readb(&PacketP->len) & PKT_LEN_MASK); rio_dprintk(RIO_DEBUG_REC, "port %d: Copy %d bytes\n", PortP->PortNum, transCount); /* ** To use the following 'kkprintfs' for debugging - change the '#undef' ** to '#define', (this is the only place ___DEBUG_IT___ occurs in the ** driver). */ ptr = (unsigned char __iomem *) PacketP->data + PortP->RxDataStart; tty_prepare_flip_string(TtyP, &buf, transCount); rio_memcpy_fromio(buf, ptr, transCount); PortP->RxDataStart += transCount; writeb(readb(&PacketP->len)-transCount, &PacketP->len); copied += transCount; if (readb(&PacketP->len) == 0) { /* ** If we have emptied the packet, then we can ** free it, and reset the start pointer for ** the next packet. */ remove_receive(PortP); put_free_end(PortP->HostP, PacketP); PortP->RxDataStart = 0; } } } if (copied) { rio_dprintk(RIO_DEBUG_REC, "port %d: pushing tty flip buffer: %d total bytes copied.\n", PortP->PortNum, copied); tty_flip_buffer_push(TtyP); } return; }
void RIOServiceHost(struct rio_info *p, struct Host *HostP, int From) { rio_spin_lock(&HostP->HostLock); if ((HostP->Flags & RUN_STATE) != RC_RUNNING) { static int t = 0; rio_spin_unlock(&HostP->HostLock); if ((t++ % 200) == 0) rio_dprintk(RIO_DEBUG_INTR, "Interrupt but host not running. flags=%x.\n", (int) HostP->Flags); return; } rio_spin_unlock(&HostP->HostLock); if (readw(&HostP->ParmMapP->rup_intr)) { writew(0, &HostP->ParmMapP->rup_intr); p->RIORupCount++; RupIntr++; rio_dprintk(RIO_DEBUG_INTR, "rio: RUP interrupt on host %Zd\n", HostP - p->RIOHosts); RIOPollHostCommands(p, HostP); } if (readw(&HostP->ParmMapP->rx_intr)) { int port; writew(0, &HostP->ParmMapP->rx_intr); p->RIORxCount++; RxIntr++; rio_dprintk(RIO_DEBUG_INTR, "rio: RX interrupt on host %Zd\n", HostP - p->RIOHosts); /* ** Loop through every port. If the port is mapped into ** the system ( i.e. has /dev/ttyXXXX associated ) then it is ** worth checking. If the port isn't open, grab any packets ** hanging on its receive queue and stuff them on the free ** list; check for commands on the way. */ for (port = p->RIOFirstPortsBooted; port < p->RIOLastPortsBooted + PORTS_PER_RTA; port++) { struct Port *PortP = p->RIOPortp[port]; struct tty_struct *ttyP; struct PKT __iomem *PacketP; /* ** not mapped in - most of the RIOPortp[] information ** has not been set up! ** Optimise: ports come in bundles of eight. */ if (!PortP->Mapped) { port += 7; continue; /* with the next port */ } /* ** If the host board isn't THIS host board, check the next one. ** optimise: ports come in bundles of eight. */ if (PortP->HostP != HostP) { port += 7; continue; } /* ** Let us see - is the port open? If not, then don't service it. */ if (!(PortP->PortState & PORT_ISOPEN)) { continue; } /* ** find corresponding tty structure. The process of mapping ** the ports puts these here. */ ttyP = PortP->gs.tty; /* ** Lock the port before we begin working on it. */ rio_spin_lock(&PortP->portSem); /* ** Process received data if there is any. */ if (can_remove_receive(&PacketP, PortP)) RIOReceive(p, PortP); /* ** If there is no data left to be read from the port, and ** it's handshake bit is set, then we must clear the handshake, ** so that that downstream RTA is re-enabled. */ if (!can_remove_receive(&PacketP, PortP) && (readw(&PortP->PhbP->handshake) == PHB_HANDSHAKE_SET)) { /* ** MAGIC! ( Basically, handshake the RX buffer, so that ** the RTAs upstream can be re-enabled. ) */ rio_dprintk(RIO_DEBUG_INTR, "Set RX handshake bit\n"); writew(PHB_HANDSHAKE_SET | PHB_HANDSHAKE_RESET, &PortP->PhbP->handshake); } rio_spin_unlock(&PortP->portSem); } } if (readw(&HostP->ParmMapP->tx_intr)) { int port; writew(0, &HostP->ParmMapP->tx_intr); p->RIOTxCount++; TxIntr++; rio_dprintk(RIO_DEBUG_INTR, "rio: TX interrupt on host %Zd\n", HostP - p->RIOHosts); /* ** Loop through every port. ** If the port is mapped into the system ( i.e. has /dev/ttyXXXX ** associated ) then it is worth checking. */ for (port = p->RIOFirstPortsBooted; port < p->RIOLastPortsBooted + PORTS_PER_RTA; port++) { struct Port *PortP = p->RIOPortp[port]; struct tty_struct *ttyP; struct PKT __iomem *PacketP; /* ** not mapped in - most of the RIOPortp[] information ** has not been set up! */ if (!PortP->Mapped) { port += 7; continue; /* with the next port */ } /* ** If the host board isn't running, then its data structures ** are no use to us - continue quietly. */ if (PortP->HostP != HostP) { port += 7; continue; /* with the next port */ } /* ** Let us see - is the port open? If not, then don't service it. */ if (!(PortP->PortState & PORT_ISOPEN)) { continue; } rio_dprintk(RIO_DEBUG_INTR, "rio: Looking into port %d.\n", port); /* ** Lock the port before we begin working on it. */ rio_spin_lock(&PortP->portSem); /* ** If we can't add anything to the transmit queue, then ** we need do none of this processing. */ if (!can_add_transmit(&PacketP, PortP)) { rio_dprintk(RIO_DEBUG_INTR, "Can't add to port, so skipping.\n"); rio_spin_unlock(&PortP->portSem); continue; } /* ** find corresponding tty structure. The process of mapping ** the ports puts these here. */ ttyP = PortP->gs.tty; /* If ttyP is NULL, the port is getting closed. Forget about it. */ if (!ttyP) { rio_dprintk(RIO_DEBUG_INTR, "no tty, so skipping.\n"); rio_spin_unlock(&PortP->portSem); continue; } /* ** If there is more room available we start up the transmit ** data process again. This can be direct I/O, if the cookmode ** is set to COOK_RAW or COOK_MEDIUM, or will be a call to the ** riotproc( T_OUTPUT ) if we are in COOK_WELL mode, to fetch ** characters via the line discipline. We must always call ** the line discipline, ** so that user input characters can be echoed correctly. ** ** ++++ Update +++++ ** With the advent of double buffering, we now see if ** TxBufferOut-In is non-zero. If so, then we copy a packet ** to the output place, and set it going. If this empties ** the buffer, then we must issue a wakeup( ) on OUT. ** If it frees space in the buffer then we must issue ** a wakeup( ) on IN. ** ** ++++ Extra! Extra! If PortP->WflushFlag is set, then we ** have to send a WFLUSH command down the PHB, to mark the ** end point of a WFLUSH. We also need to clear out any ** data from the double buffer! ( note that WflushFlag is a ** *count* of the number of WFLUSH commands outstanding! ) ** ** ++++ And there's more! ** If an RTA is powered off, then on again, and rebooted, ** whilst it has ports open, then we need to re-open the ports. ** ( reasonable enough ). We can't do this when we spot the ** re-boot, in interrupt time, because the queue is probably ** full. So, when we come in here, we need to test if any ** ports are in this condition, and re-open the port before ** we try to send any more data to it. Now, the re-booted ** RTA will be discarding packets from the PHB until it ** receives this open packet, but don't worry tooo much ** about that. The one thing that is interesting is the ** combination of this effect and the WFLUSH effect! */ /* For now don't handle RTA reboots. -- REW. Reenabled. Otherwise RTA reboots didn't work. Duh. -- REW */ if (PortP->MagicFlags) { if (PortP->MagicFlags & MAGIC_REBOOT) { /* ** well, the RTA has been rebooted, and there is room ** on its queue to add the open packet that is required. ** ** The messy part of this line is trying to decide if ** we need to call the Param function as a tty or as ** a modem. ** DONT USE CLOCAL AS A TEST FOR THIS! ** ** If we can't param the port, then move on to the ** next port. */ PortP->InUse = NOT_INUSE; rio_spin_unlock(&PortP->portSem); if (RIOParam(PortP, OPEN, ((PortP->Cor2Copy & (COR2_RTSFLOW | COR2_CTSFLOW)) == (COR2_RTSFLOW | COR2_CTSFLOW)) ? 1 : 0, DONT_SLEEP) == RIO_FAIL) { continue; /* with next port */ } rio_spin_lock(&PortP->portSem); PortP->MagicFlags &= ~MAGIC_REBOOT; } /* ** As mentioned above, this is a tacky hack to cope ** with WFLUSH */ if (PortP->WflushFlag) { rio_dprintk(RIO_DEBUG_INTR, "Want to WFLUSH mark this port\n"); if (PortP->InUse) rio_dprintk(RIO_DEBUG_INTR, "FAILS - PORT IS IN USE\n"); } while (PortP->WflushFlag && can_add_transmit(&PacketP, PortP) && (PortP->InUse == NOT_INUSE)) { int p; struct PktCmd __iomem *PktCmdP; rio_dprintk(RIO_DEBUG_INTR, "Add WFLUSH marker to data queue\n"); /* ** make it look just like a WFLUSH command */ PktCmdP = (struct PktCmd __iomem *) &PacketP->data[0]; writeb(WFLUSH, &PktCmdP->Command); p = PortP->HostPort % (u16) PORTS_PER_RTA; /* ** If second block of ports for 16 port RTA, add 8 ** to index 8-15. */ if (PortP->SecondBlock) p += PORTS_PER_RTA; writeb(p, &PktCmdP->PhbNum); /* ** to make debuggery easier */ writeb('W', &PacketP->data[2]); writeb('F', &PacketP->data[3]); writeb('L', &PacketP->data[4]); writeb('U', &PacketP->data[5]); writeb('S', &PacketP->data[6]); writeb('H', &PacketP->data[7]); writeb(' ', &PacketP->data[8]); writeb('0' + PortP->WflushFlag, &PacketP->data[9]); writeb(' ', &PacketP->data[10]); writeb(' ', &PacketP->data[11]); writeb('\0', &PacketP->data[12]); /* ** its two bytes long! */ writeb(PKT_CMD_BIT | 2, &PacketP->len); /* ** queue it! */ if (!(PortP->State & RIO_DELETED)) { add_transmit(PortP); /* ** Count chars tx'd for port statistics reporting */ if (PortP->statsGather) PortP->txchars += 2; } if (--(PortP->WflushFlag) == 0) { PortP->MagicFlags &= ~MAGIC_FLUSH; } rio_dprintk(RIO_DEBUG_INTR, "Wflush count now stands at %d\n", PortP->WflushFlag); } if (PortP->MagicFlags & MORE_OUTPUT_EYGOR) { if (PortP->MagicFlags & MAGIC_FLUSH) { PortP->MagicFlags |= MORE_OUTPUT_EYGOR; } else { if (!can_add_transmit(&PacketP, PortP)) { rio_spin_unlock(&PortP->portSem); continue; } rio_spin_unlock(&PortP->portSem); RIOTxEnable((char *) PortP); rio_spin_lock(&PortP->portSem); PortP->MagicFlags &= ~MORE_OUTPUT_EYGOR; } } } /* ** If we can't add anything to the transmit queue, then ** we need do none of the remaining processing. */ if (!can_add_transmit(&PacketP, PortP)) { rio_spin_unlock(&PortP->portSem); continue; } rio_spin_unlock(&PortP->portSem); RIOTxEnable((char *) PortP); } } }