📄 riocmd.c
字号:
Base = &((*Base)->NextP); rio_dprintk (RIO_DEBUG_CMD, "Now try to queue cmd cmdblk 0x%x at 0x%x\n", (int)CmdBlkP,(int)Base); } rio_dprintk (RIO_DEBUG_CMD, "Will queue cmdblk 0x%x at 0x%x\n",(int)CmdBlkP,(int)Base); *Base = CmdBlkP; CmdBlkP->NextP = NULL; rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); return RIO_SUCCESS;}/*** Here we go - if there is an empty rup, fill it!** must be called at splrio() or higher.*/voidRIOPollHostCommands(p, HostP)struct rio_info * p;struct Host * HostP;{ register struct CmdBlk *CmdBlkP; register struct UnixRup *UnixRupP; struct PKT *PacketP; ushort Rup; unsigned long flags; Rup = MAX_RUP+LINKS_PER_UNIT; do { /* do this loop for each RUP */ /* ** locate the rup we are processing & lock it */ UnixRupP = &HostP->UnixRups[--Rup]; spin_lock_irqsave(&UnixRupP->RupLock, flags); /* ** First check for incoming commands: */ if ( RWORD(UnixRupP->RupP->rxcontrol) != RX_RUP_INACTIVE ) { int FreeMe; PacketP =(PKT *)RIO_PTR(HostP->Caddr,RWORD(UnixRupP->RupP->rxpkt)); ShowPacket( DBG_CMD, PacketP ); switch ( RBYTE(PacketP->dest_port) ) { case BOOT_RUP: rio_dprintk (RIO_DEBUG_CMD, "Incoming Boot %s packet '%x'\n", RBYTE(PacketP->len) & 0x80 ? "Command":"Data", RBYTE(PacketP->data[0])); rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); FreeMe= RIOBootRup(p, Rup,HostP,PacketP); rio_spin_lock_irqsave(&UnixRupP->RupLock, flags); break; case COMMAND_RUP: /* ** Free the RUP lock as loss of carrier causes a ** ttyflush which will (eventually) call another ** routine that uses the RUP lock. */ rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); FreeMe= RIOCommandRup(p, Rup,HostP,PacketP); if (PacketP->data[5] == MEMDUMP) { rio_dprintk (RIO_DEBUG_CMD, "Memdump from 0x%x complete\n", *(ushort *) &(PacketP->data[6])); HostP->Copy( (caddr_t)&(PacketP->data[8]), (caddr_t)p->RIOMemDump, 32 ); } rio_spin_lock_irqsave(&UnixRupP->RupLock, flags); break; case ROUTE_RUP: rio_spin_unlock_irqrestore( &UnixRupP->RupLock, flags); FreeMe = RIORouteRup(p, Rup, HostP, PacketP ); rio_spin_lock_irqsave( &UnixRupP->RupLock, flags ); break; default: rio_dprintk (RIO_DEBUG_CMD, "Unknown RUP %d\n", RBYTE(PacketP->dest_port)); FreeMe = 1; break; } if ( FreeMe ) { rio_dprintk (RIO_DEBUG_CMD, "Free processed incoming command packet\n"); put_free_end(HostP,PacketP); WWORD(UnixRupP->RupP->rxcontrol , RX_RUP_INACTIVE); if ( RWORD(UnixRupP->RupP->handshake)==PHB_HANDSHAKE_SET ) { rio_dprintk (RIO_DEBUG_CMD, "Handshake rup %d\n",Rup); WWORD(UnixRupP->RupP->handshake, PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET); } } } /* ** IF a command was running on the port, ** and it has completed, then tidy it up. */ if ( (CmdBlkP = UnixRupP->CmdPendingP) && /* ASSIGN! */ (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE)) { /* ** we are idle. ** there is a command in pending. ** Therefore, this command has finished. ** So, wakeup whoever is waiting for it (and tell them ** what happened). */ if ( CmdBlkP->Packet.dest_port == BOOT_RUP ) rio_dprintk (RIO_DEBUG_CMD, "Free Boot %s Command Block '%x'\n", CmdBlkP->Packet.len & 0x80 ? "Command":"Data", CmdBlkP->Packet.data[0]); rio_dprintk (RIO_DEBUG_CMD, "Command 0x%x completed\n",(int)CmdBlkP); /* ** Clear the Rup lock to prevent mutual exclusion. */ if ( CmdBlkP->PostFuncP ) { rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); (*CmdBlkP->PostFuncP) (CmdBlkP->PostArg,CmdBlkP); rio_spin_lock_irqsave(&UnixRupP->RupLock, flags); } /* ** ....clear the pending flag.... */ UnixRupP->CmdPendingP = NULL; /* ** ....and return the command block to the freelist. */ RIOFreeCmdBlk( CmdBlkP ); } /* ** If there is a command for this rup, and the rup ** is idle, then process the command */ if ( (CmdBlkP = UnixRupP->CmdsWaitingP) && /* ASSIGN! */ (UnixRupP->CmdPendingP == NULL) && (RWORD(UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE)) { /* ** if the pre-function is non-zero, call it. ** If it returns RIO_FAIL then don't ** send this command yet! */#ifdef CHECK CheckCmdBlkP (CmdBlkP);#endif if ( !(CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP)(CmdBlkP->PreArg, CmdBlkP) : TRUE)) { rio_dprintk (RIO_DEBUG_CMD, "Not ready to start command 0x%x\n",(int)CmdBlkP); } else { rio_dprintk (RIO_DEBUG_CMD, "Start new command 0x%x Cmd byte is 0x%x\n", (int)CmdBlkP, CmdBlkP->Packet.data[0]); /* ** Whammy! blat that pack! */#ifdef CHECK CheckPacketP ((PKT *)RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt));#endif HostP->Copy( (caddr_t)&CmdBlkP->Packet, RIO_PTR(HostP->Caddr, UnixRupP->RupP->txpkt), sizeof(PKT)); /* ** remove the command from the rup command queue... */ UnixRupP->CmdsWaitingP = CmdBlkP->NextP; /* ** ...and place it on the pending position. */ UnixRupP->CmdPendingP = CmdBlkP; /* ** set the command register */ WWORD(UnixRupP->RupP->txcontrol,TX_PACKET_READY); /* ** the command block will be freed ** when the command has been processed. */ } } spin_unlock_irqrestore(&UnixRupP->RupLock, flags); } while ( Rup );}intRIOWFlushMark(iPortP, CmdBlkP)int iPortP;struct CmdBlk *CmdBlkP;{ struct Port * PortP = (struct Port *)iPortP; unsigned long flags; rio_spin_lock_irqsave(&PortP->portSem, flags);#ifdef CHECK CheckPortP( PortP );#endif PortP->WflushFlag++; PortP->MagicFlags |= MAGIC_FLUSH; rio_spin_unlock_irqrestore(&PortP->portSem, flags); return RIOUnUse( iPortP, CmdBlkP );}intRIORFlushEnable(iPortP, CmdBlkP)int iPortP;struct CmdBlk *CmdBlkP; { struct Port * PortP = (struct Port *)iPortP; PKT *PacketP; unsigned long flags; rio_spin_lock_irqsave(&PortP->portSem, flags); while ( can_remove_receive(&PacketP, PortP) ) { remove_receive(PortP); ShowPacket(DBG_PROC, PacketP ); put_free_end( PortP->HostP, PacketP ); } if ( RWORD(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"); WWORD(PortP->PhbP->handshake, PHB_HANDSHAKE_SET|PHB_HANDSHAKE_RESET); } rio_spin_unlock_irqrestore(&PortP->portSem, flags); return RIOUnUse( iPortP, CmdBlkP );}intRIOUnUse(iPortP, CmdBlkP)int iPortP;struct CmdBlk *CmdBlkP; { struct Port * PortP = (struct Port *)iPortP; unsigned long flags; rio_spin_lock_irqsave(&PortP->portSem, flags);#ifdef CHECK CheckPortP( PortP );#endif rio_dprintk (RIO_DEBUG_CMD, "Decrement in use count for port\n"); if (PortP->InUse) { if ( --PortP->InUse != NOT_INUSE ) { rio_spin_unlock_irqrestore(&PortP->portSem, flags); return 0; } } /* ** While PortP->InUse is set (i.e. a preemptive command has been sent to ** the RTA and is awaiting completion), any transmit data is prevented from ** being transferred from the write queue into the transmit packets ** (add_transmit) and no furthur transmit interrupt will be sent for that ** data. The next interrupt will occur up to 500ms later (RIOIntr is called ** twice a second as a saftey measure). This was the case when kermit was ** used to send data into a RIO port. After each packet was sent, TCFLSH ** was called to flush the read queue preemptively. PortP->InUse was ** incremented, thereby blocking the 6 byte acknowledgement packet ** transmitted back. This acknowledgment hung around for 500ms before ** being sent, thus reducing input performance substantially!. ** When PortP->InUse becomes NOT_INUSE, we must ensure that any data ** hanging around in the transmit buffer is sent immediately. */ WWORD(PortP->HostP->ParmMapP->tx_intr, 1); /* What to do here .. wakeup( (caddr_t)&(PortP->InUse) ); */ rio_spin_unlock_irqrestore(&PortP->portSem, flags); return 0;}voidShowPacket(Flags, PacketP)uint Flags;struct PKT *PacketP; {}/*** ** How to use this file:** ** To send a command down a rup, you need to allocate a command block, fill** in the packet information, fill in the command number, fill in the pre-** and post- functions and arguments, and then add the command block to the** queue of command blocks for the port in question. When the port is idle,** then the pre-function will be called. If this returns RIO_FAIL then the** command will be re-queued and tried again at a later date (probably in one** clock tick). If the pre-function returns NOT RIO_FAIL, then the command** packet will be queued on the RUP, and the txcontrol field set to the** command number. When the txcontrol field has changed from being the** command number, then the post-function will be called, with the argument** specified earlier, a pointer to the command block, and the value of** txcontrol.** ** To allocate a command block, call RIOGetCmdBlk(). This returns a pointer** to the command block structure allocated, or NULL if there aren't any.** The block will have been zeroed for you.** ** The structure has the following fields:** ** struct CmdBlk** {** struct CmdBlk *NextP; ** Pointer to next command block **** struct PKT Packet; ** A packet, to copy to the rup **** int (*PreFuncP)(); ** The func to call to check if OK **** int PreArg; ** The arg for the func **** int (*PostFuncP)(); ** The func to call when completed **** int PostArg; ** The arg for the func **** };** ** You need to fill in ALL fields EXCEPT NextP, which is used to link the** blocks together either on the free list or on the Rup list.** ** Packet is an actual packet structure to be filled in with the packet** information associated with the command. You need to fill in everything,** as the command processore doesn't process the command packet in any way.** ** The PreFuncP is called before the packet is enqueued on the host rup.** PreFuncP is called as (*PreFuncP)(PreArg, CmdBlkP);. PreFuncP must** return !RIO_FAIL to have the packet queued on the rup, and RIO_FAIL** if the packet is NOT to be queued.** ** The PostFuncP is called when the command has completed. It is called** as (*PostFuncP)(PostArg, CmdBlkP, txcontrol);. PostFuncP is not expected** to return a value. PostFuncP does NOT need to free the command block,** as this happens automatically after PostFuncP returns.** ** Once the command block has been filled in, it is attached to the correct** queue by calling RIOQueueCmdBlk( HostP, Rup, CmdBlkP ) where HostP is** a pointer to the struct Host, Rup is the NUMBER of the rup (NOT a pointer** to it!), and CmdBlkP is the pointer to the command block allocated using** RIOGetCmdBlk().** */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -