int RIOFoadWakeup(struct rio_info *p) { int port; struct Port *PortP; unsigned long flags; for (port = 0; port < RIO_PORTS; port++) { PortP = p->RIOPortp[port]; rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->Config = 0; PortP->State = 0; PortP->InUse = NOT_INUSE; PortP->PortState = 0; PortP->FlushCmdBodge = 0; PortP->ModemLines = 0; PortP->ModemState = 0; PortP->CookMode = 0; PortP->ParamSem = 0; PortP->Mapped = 0; PortP->WflushFlag = 0; PortP->MagicFlags = 0; PortP->RxDataStart = 0; PortP->TxBufferIn = 0; PortP->TxBufferOut = 0; rio_spin_unlock_irqrestore(&PortP->portSem, flags); } return (0); }
/**************************************** * Put a packet onto the end of the * free list ****************************************/ void put_free_end(struct Host *HostP, struct PKT __iomem *PktP) { struct rio_free_list __iomem *tmp_pointer; unsigned short old_end, new_end; unsigned long flags; rio_spin_lock_irqsave(&HostP->HostLock, flags); /************************************************* * Put a packet back onto the back of the free list * ************************************************/ rio_dprintk(RIO_DEBUG_PFE, "put_free_end(PktP=%p)\n", PktP); if ((old_end = readw(&HostP->ParmMapP->free_list_end)) != TPNULL) { new_end = RIO_OFF(HostP->Caddr, PktP); tmp_pointer = (struct rio_free_list __iomem *) RIO_PTR(HostP->Caddr, old_end); writew(new_end, &tmp_pointer->next); writew(old_end, &((struct rio_free_list __iomem *) PktP)->prev); writew(TPNULL, &((struct rio_free_list __iomem *) PktP)->next); writew(new_end, &HostP->ParmMapP->free_list_end); } else { /* First packet on the free list this should never happen! */ rio_dprintk(RIO_DEBUG_PFE, "put_free_end(): This should never happen\n"); writew(RIO_OFF(HostP->Caddr, PktP), &HostP->ParmMapP->free_list_end); tmp_pointer = (struct rio_free_list __iomem *) PktP; writew(TPNULL, &tmp_pointer->prev); writew(TPNULL, &tmp_pointer->next); } rio_dprintk(RIO_DEBUG_CMD, "Before unlock: %p\n", &HostP->HostLock); rio_spin_unlock_irqrestore(&HostP->HostLock, flags); }
void RIOFixPhbs(struct rio_info *p, struct Host *HostP, unsigned int unit) { unsigned short link, port; struct Port *PortP; unsigned long flags; int PortN = HostP->Mapping[unit].SysPort; rio_dprintk(RIO_DEBUG_ROUTE, "RIOFixPhbs unit %d sysport %d\n", unit, PortN); if (PortN != -1) { unsigned short dest_unit = HostP->Mapping[unit].ID2; PortP = p->RIOPortp[HostP->Mapping[dest_unit - 1].SysPort]; link = readw(&PortP->PhbP->link); for (port = 0; port < PORTS_PER_RTA; port++, PortN++) { unsigned short dest_port = port + 8; u16 __iomem *TxPktP; struct PKT __iomem *Pkt; PortP = p->RIOPortp[PortN]; rio_spin_lock_irqsave(&PortP->portSem, flags); if (!PortP->TxStart) { rio_dprintk(RIO_DEBUG_ROUTE, "Tx pkts not set up yet\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); break; } for (TxPktP = PortP->TxStart; TxPktP <= PortP->TxEnd; TxPktP++) { Pkt = (struct PKT __iomem *) RIO_PTR(HostP->Caddr, readw(TxPktP)); Pkt = (struct PKT __iomem *) ((unsigned long) Pkt & ~PKT_IN_USE); writeb(dest_unit, &Pkt->dest_unit); writeb(dest_port, &Pkt->dest_port); } rio_dprintk(RIO_DEBUG_ROUTE, "phb dest: Old %x:%x New %x:%x\n", readw(&PortP->PhbP->destination) & 0xff, (readw(&PortP->PhbP->destination) >> 8) & 0xff, dest_unit, dest_port); writew(dest_unit + (dest_port << 8), &PortP->PhbP->destination); writew(link, &PortP->PhbP->link); rio_spin_unlock_irqrestore(&PortP->portSem, flags); } if (link > 3) return; if (((unit * 8) + 7) > readw(&HostP->LinkStrP[link].last_port)) { rio_dprintk(RIO_DEBUG_ROUTE, "last port on host link %d: %d\n", link, (unit * 8) + 7); writew((unit * 8) + 7, &HostP->LinkStrP[link].last_port); } }
int RIOWFlushMark(unsigned long iPortP, struct CmdBlk *CmdBlkP) { struct Port *PortP = (struct Port *) iPortP; unsigned long flags; rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->WflushFlag++; PortP->MagicFlags |= MAGIC_FLUSH; rio_spin_unlock_irqrestore(&PortP->portSem, flags); return RIOUnUse(iPortP, CmdBlkP); }
/* ** User process needs the config table - build it from first ** principles. ** * FIXME: SMP locking */ int RIOApel(struct rio_info *p) { int Host; int link; int Rup; int Next = 0; struct Map *MapP; struct Host *HostP; unsigned long flags; rio_dprintk(RIO_DEBUG_TABLE, "Generating a table to return to config.rio\n"); memset(&p->RIOConnectTable[0], 0, sizeof(struct Map) * TOTAL_MAP_ENTRIES); for (Host = 0; Host < RIO_HOSTS; Host++) { rio_dprintk(RIO_DEBUG_TABLE, "Processing host %d\n", Host); HostP = &p->RIOHosts[Host]; rio_spin_lock_irqsave(&HostP->HostLock, flags); MapP = &p->RIOConnectTable[Next++]; MapP->HostUniqueNum = HostP->UniqueNum; if ((HostP->Flags & RUN_STATE) != RC_RUNNING) { rio_spin_unlock_irqrestore(&HostP->HostLock, flags); continue; } MapP->RtaUniqueNum = 0; MapP->ID = 0; MapP->Flags = SLOT_IN_USE; MapP->SysPort = NO_PORT; for (link = 0; link < LINKS_PER_UNIT; link++) MapP->Topology[link] = HostP->Topology[link]; memcpy(MapP->Name, HostP->Name, MAX_NAME_LEN); for (Rup = 0; Rup < MAX_RUP; Rup++) { if (HostP->Mapping[Rup].Flags & (SLOT_IN_USE | SLOT_TENTATIVE)) { p->RIOConnectTable[Next] = HostP->Mapping[Rup]; if (HostP->Mapping[Rup].Flags & SLOT_IN_USE) p->RIOConnectTable[Next].Flags |= SLOT_IN_USE; if (HostP->Mapping[Rup].Flags & SLOT_TENTATIVE) p->RIOConnectTable[Next].Flags |= SLOT_TENTATIVE; if (HostP->Mapping[Rup].Flags & RTA16_SECOND_SLOT) p->RIOConnectTable[Next].Flags |= RTA16_SECOND_SLOT; Next++; } } rio_spin_unlock_irqrestore(&HostP->HostLock, flags); } return 0; }
int RIOUnUse(unsigned long iPortP, struct CmdBlk *CmdBlkP) { struct Port *PortP = (struct Port *) iPortP; unsigned long flags; rio_spin_lock_irqsave(&PortP->portSem, flags); 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. */ writew(1, &PortP->HostP->ParmMapP->tx_intr); /* What to do here .. wakeup( (caddr_t)&(PortP->InUse) ); */ rio_spin_unlock_irqrestore(&PortP->portSem, flags); return 0; }
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); }
/* ** Incoming on the ROUTE_RUP ** I wrote this while I was tired. Forgive me. */ int RIORouteRup( struct rio_info *p, uint Rup, struct Host *HostP, PKT *PacketP ) { struct PktCmd *PktCmdP = (struct PktCmd *)PacketP->data; struct PktCmd_M *PktReplyP; struct CmdBlk *CmdBlkP; struct Port *PortP; struct Map *MapP; struct Top *TopP; int ThisLink, ThisLinkMin, ThisLinkMax; int port; int Mod, Mod1, Mod2; ushort RtaType; uint RtaUniq; uint ThisUnit, ThisUnit2; /* 2 ids to accommodate 16 port RTA */ uint OldUnit, NewUnit, OldLink, NewLink; char *MyType, *MyName; int Lies; unsigned long flags; #ifdef STACK RIOStackCheck("RIORouteRup"); #endif #ifdef CHECK CheckPacketP(PacketP); CheckHostP(HostP); CheckRup(Rup); CheckHost(Host); #endif /* ** Is this unit telling us it's current link topology? */ if ( RBYTE(PktCmdP->Command) == ROUTE_TOPOLOGY ) { MapP = HostP->Mapping; /* ** The packet can be sent either by the host or by an RTA. ** If it comes from the host, then we need to fill in the ** Topology array in the host structure. If it came in ** from an RTA then we need to fill in the Mapping structure's ** Topology array for the unit. */ if ( Rup >= (ushort)MAX_RUP ) { ThisUnit = HOST_ID; TopP = HostP->Topology; MyType = "Host"; MyName = HostP->Name; ThisLinkMin = ThisLinkMax = Rup - MAX_RUP; } else { ThisUnit = Rup+1; TopP = HostP->Mapping[Rup].Topology; MyType = "RTA"; MyName = HostP->Mapping[Rup].Name; ThisLinkMin = 0; ThisLinkMax = LINKS_PER_UNIT - 1; } /* ** Lies will not be tolerated. ** If any pair of links claim to be connected to the same ** place, then ignore this packet completely. */ Lies = 0; for ( ThisLink=ThisLinkMin + 1; ThisLink <= ThisLinkMax; ThisLink++) { /* ** it won't lie about network interconnect, total disconnects ** and no-IDs. (or at least, it doesn't *matter* if it does) */ if ( RBYTE(PktCmdP->RouteTopology[ThisLink].Unit) > (ushort)MAX_RUP ) continue; for ( NewLink=ThisLinkMin; NewLink < ThisLink; NewLink++ ) { if ( (RBYTE(PktCmdP->RouteTopology[ThisLink].Unit) == RBYTE(PktCmdP->RouteTopology[NewLink].Unit)) && (RBYTE(PktCmdP->RouteTopology[ThisLink].Link) == RBYTE(PktCmdP->RouteTopology[NewLink].Link)) ) { Lies++; } } } if ( Lies ) { rio_dprintk (RIO_DEBUG_ROUTE, "LIES! DAMN LIES! %d LIES!\n",Lies); rio_dprintk (RIO_DEBUG_ROUTE, "%d:%c %d:%c %d:%c %d:%c\n", RBYTE(PktCmdP->RouteTopology[0].Unit), 'A'+RBYTE(PktCmdP->RouteTopology[0].Link), RBYTE(PktCmdP->RouteTopology[1].Unit), 'A'+RBYTE(PktCmdP->RouteTopology[1].Link), RBYTE(PktCmdP->RouteTopology[2].Unit), 'A'+RBYTE(PktCmdP->RouteTopology[2].Link), RBYTE(PktCmdP->RouteTopology[3].Unit), 'A'+RBYTE(PktCmdP->RouteTopology[3].Link)); return TRUE; } /* ** now, process each link. */ for ( ThisLink=ThisLinkMin; ThisLink <= ThisLinkMax; ThisLink++) { /* ** this is what it was connected to */ OldUnit = TopP[ThisLink].Unit; OldLink = TopP[ThisLink].Link; /* ** this is what it is now connected to */ NewUnit = RBYTE(PktCmdP->RouteTopology[ThisLink].Unit); NewLink = RBYTE(PktCmdP->RouteTopology[ThisLink].Link); if ( OldUnit != NewUnit || OldLink != NewLink ) { /* ** something has changed! */ if ( NewUnit > MAX_RUP && NewUnit != ROUTE_DISCONNECT && NewUnit != ROUTE_NO_ID && NewUnit != ROUTE_INTERCONNECT ) { rio_dprintk (RIO_DEBUG_ROUTE, "I have a link from %s %s to unit %d:%d - I don't like it.\n", MyType, MyName, NewUnit, NewLink); } else { /* ** put the new values in */ TopP[ThisLink].Unit = NewUnit; TopP[ThisLink].Link = NewLink; RIOSetChange(p); if ( OldUnit <= MAX_RUP ) { /* ** If something has become bust, then re-enable them messages */ if (! p->RIONoMessage) RIOConCon(p,HostP,ThisUnit,ThisLink,OldUnit,OldLink,DISCONNECT); } if ( ( NewUnit <= MAX_RUP ) && !p->RIONoMessage ) RIOConCon(p,HostP,ThisUnit,ThisLink,NewUnit,NewLink,CONNECT); if ( NewUnit == ROUTE_NO_ID ) rio_dprintk (RIO_DEBUG_ROUTE, "%s %s (%c) is connected to an unconfigured unit.\n", MyType,MyName,'A'+ThisLink); if ( NewUnit == ROUTE_INTERCONNECT ) { if (! p->RIONoMessage) cprintf("%s '%s' (%c) is connected to another network.\n", MyType,MyName,'A'+ThisLink); } /* ** perform an update for 'the other end', so that these messages ** only appears once. Only disconnect the other end if it is pointing ** at us! */ if ( OldUnit == HOST_ID ) { if ( HostP->Topology[OldLink].Unit == ThisUnit && HostP->Topology[OldLink].Link == ThisLink ) { rio_dprintk (RIO_DEBUG_ROUTE, "SETTING HOST (%c) TO DISCONNECTED!\n", OldLink+'A'); HostP->Topology[OldLink].Unit = ROUTE_DISCONNECT; HostP->Topology[OldLink].Link = NO_LINK; } else { rio_dprintk (RIO_DEBUG_ROUTE, "HOST(%c) WAS NOT CONNECTED TO %s (%c)!\n", OldLink+'A',HostP->Mapping[ThisUnit-1].Name,ThisLink+'A'); } } else if ( OldUnit <= MAX_RUP ) { if ( HostP->Mapping[OldUnit-1].Topology[OldLink].Unit == ThisUnit && HostP->Mapping[OldUnit-1].Topology[OldLink].Link == ThisLink ) { rio_dprintk (RIO_DEBUG_ROUTE, "SETTING RTA %s (%c) TO DISCONNECTED!\n", HostP->Mapping[OldUnit-1].Name,OldLink+'A'); HostP->Mapping[OldUnit-1].Topology[OldLink].Unit=ROUTE_DISCONNECT; HostP->Mapping[OldUnit-1].Topology[OldLink].Link=NO_LINK; } else { rio_dprintk (RIO_DEBUG_ROUTE, "RTA %s (%c) WAS NOT CONNECTED TO %s (%c)\n", HostP->Mapping[OldUnit-1].Name,OldLink+'A', HostP->Mapping[ThisUnit-1].Name,ThisLink+'A'); } } if ( NewUnit == HOST_ID ) { rio_dprintk (RIO_DEBUG_ROUTE, "MARKING HOST (%c) CONNECTED TO %s (%c)\n", NewLink+'A',MyName,ThisLink+'A'); HostP->Topology[NewLink].Unit = ThisUnit; HostP->Topology[NewLink].Link = ThisLink; } else if ( NewUnit <= MAX_RUP ) { rio_dprintk (RIO_DEBUG_ROUTE, "MARKING RTA %s (%c) CONNECTED TO %s (%c)\n", HostP->Mapping[NewUnit-1].Name,NewLink+'A',MyName,ThisLink+'A'); HostP->Mapping[NewUnit-1].Topology[NewLink].Unit=ThisUnit; HostP->Mapping[NewUnit-1].Topology[NewLink].Link=ThisLink; } } RIOSetChange(p); RIOCheckIsolated(p, HostP, OldUnit ); } } return TRUE; } /* ** The only other command we recognise is a route_request command */ if ( RBYTE(PktCmdP->Command) != ROUTE_REQUEST ) { rio_dprintk (RIO_DEBUG_ROUTE, "Unknown command %d received on rup %d host %d ROUTE_RUP\n", RBYTE(PktCmdP->Command),Rup,(int)HostP); return TRUE; } RtaUniq = (RBYTE(PktCmdP->UniqNum[0])) + (RBYTE(PktCmdP->UniqNum[1]) << 8) + (RBYTE(PktCmdP->UniqNum[2]) << 16) + (RBYTE(PktCmdP->UniqNum[3]) << 24); /* ** Determine if 8 or 16 port RTA */ RtaType = GetUnitType(RtaUniq); rio_dprintk (RIO_DEBUG_ROUTE, "Received a request for an ID for serial number %x\n", RtaUniq); Mod = RBYTE(PktCmdP->ModuleTypes); Mod1 = LONYBLE(Mod); if (RtaType == TYPE_RTA16) { /* ** Only one ident is set for a 16 port RTA. To make compatible ** with 8 port, set 2nd ident in Mod2 to the same as Mod1. */ Mod2 = Mod1; rio_dprintk (RIO_DEBUG_ROUTE, "Backplane type is %s (all ports)\n", p->RIOModuleTypes[Mod1].Name); } else { Mod2 = HINYBLE(Mod); rio_dprintk (RIO_DEBUG_ROUTE, "Module types are %s (ports 0-3) and %s (ports 4-7)\n", p->RIOModuleTypes[Mod1].Name, p->RIOModuleTypes[Mod2].Name); } if ( RtaUniq == 0xffffffff ) { ShowPacket( DBG_SPECIAL, PacketP ); } /* ** try to unhook a command block from the command free list. */ if ( !(CmdBlkP = RIOGetCmdBlk()) ) { rio_dprintk (RIO_DEBUG_ROUTE, "No command blocks to route RTA! come back later.\n"); return 0; } /* ** Fill in the default info on the command block */ CmdBlkP->Packet.dest_unit = Rup; CmdBlkP->Packet.dest_port = ROUTE_RUP; CmdBlkP->Packet.src_unit = HOST_ID; CmdBlkP->Packet.src_port = ROUTE_RUP; CmdBlkP->Packet.len = PKT_CMD_BIT | 1; CmdBlkP->PreFuncP = CmdBlkP->PostFuncP = NULL; PktReplyP = (struct PktCmd_M *)CmdBlkP->Packet.data; if (! RIOBootOk(p, HostP, RtaUniq)) { rio_dprintk (RIO_DEBUG_ROUTE, "RTA %x tried to get an ID, but does not belong - FOAD it!\n", RtaUniq); PktReplyP->Command = ROUTE_FOAD; HostP->Copy("RT_FOAD", PktReplyP->CommandText, 7); RIOQueueCmdBlk(HostP, Rup, CmdBlkP); return TRUE; } /* ** Check to see if the RTA is configured for this host */ for ( ThisUnit=0; ThisUnit<MAX_RUP; ThisUnit++ ) { rio_dprintk (RIO_DEBUG_ROUTE, "Entry %d Flags=%s %s UniqueNum=0x%x\n", ThisUnit, HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE ? "Slot-In-Use":"Not In Use", HostP->Mapping[ThisUnit].Flags & SLOT_TENTATIVE ? "Slot-Tentative":"Not Tentative", HostP->Mapping[ThisUnit].RtaUniqueNum); /* ** We have an entry for it. */ if ( (HostP->Mapping[ThisUnit].Flags & (SLOT_IN_USE | SLOT_TENTATIVE)) && (HostP->Mapping[ThisUnit].RtaUniqueNum == RtaUniq) ) { if (RtaType == TYPE_RTA16) { ThisUnit2 = HostP->Mapping[ThisUnit].ID2 - 1; rio_dprintk (RIO_DEBUG_ROUTE, "Found unit 0x%x at slots %d+%d\n", RtaUniq,ThisUnit,ThisUnit2); } else rio_dprintk (RIO_DEBUG_ROUTE, "Found unit 0x%x at slot %d\n", RtaUniq,ThisUnit); /* ** If we have no knowledge of booting it, then the host has ** been re-booted, and so we must kill the RTA, so that it ** will be booted again (potentially with new bins) ** and it will then re-ask for an ID, which we will service. */ if ( (HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE) && !(HostP->Mapping[ThisUnit].Flags & RTA_BOOTED) ) { if ( !(HostP->Mapping[ThisUnit].Flags & MSG_DONE) ) { if ( !p->RIONoMessage ) cprintf("RTA '%s' is being updated.\n",HostP->Mapping[ThisUnit].Name); HostP->Mapping[ThisUnit].Flags |= MSG_DONE; } PktReplyP->Command = ROUTE_FOAD; HostP->Copy("RT_FOAD",PktReplyP->CommandText,7); RIOQueueCmdBlk(HostP, Rup, CmdBlkP); return TRUE; } /* ** Send the ID (entry) to this RTA. The ID number is implicit as ** the offset into the table. It is worth noting at this stage ** that offset zero in the table contains the entries for the ** RTA with ID 1!!!! */ PktReplyP->Command = ROUTE_ALLOCATE; PktReplyP->IDNum = ThisUnit+1; if (RtaType == TYPE_RTA16) { if (HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE) /* ** Adjust the phb and tx pkt dest_units for 2nd block of 8 ** only if the RTA has ports associated (SLOT_IN_USE) */ RIOFixPhbs(p, HostP, ThisUnit2); PktReplyP->IDNum2 = ThisUnit2+1; rio_dprintk (RIO_DEBUG_ROUTE, "RTA '%s' has been allocated IDs %d+%d\n", HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum, PktReplyP->IDNum2); } else { PktReplyP->IDNum2 = ROUTE_NO_ID; rio_dprintk (RIO_DEBUG_ROUTE, "RTA '%s' has been allocated ID %d\n", HostP->Mapping[ThisUnit].Name,PktReplyP->IDNum); } HostP->Copy("RT_ALLOCAT",PktReplyP->CommandText,10); RIOQueueCmdBlk( HostP, Rup, CmdBlkP); /* ** If this is a freshly booted RTA, then we need to re-open ** the ports, if any where open, so that data may once more ** flow around the system! */ if ( (HostP->Mapping[ThisUnit].Flags & RTA_NEWBOOT) && (HostP->Mapping[ThisUnit].SysPort != NO_PORT) ) { /* ** look at the ports associated with this beast and ** see if any where open. If they was, then re-open ** them, using the info from the tty flags. */ for ( port=0; port<PORTS_PER_RTA; port++ ) { PortP = p->RIOPortp[port+HostP->Mapping[ThisUnit].SysPort]; if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) ) { rio_dprintk (RIO_DEBUG_ROUTE, "Re-opened this port\n"); rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->MagicFlags |= MAGIC_REBOOT; rio_spin_unlock_irqrestore(&PortP->portSem, flags); } } if (RtaType == TYPE_RTA16) { for ( port=0; port<PORTS_PER_RTA; port++ ) { PortP = p->RIOPortp[port+HostP->Mapping[ThisUnit2].SysPort]; if ( PortP->State & (RIO_MOPEN|RIO_LOPEN) ) { rio_dprintk (RIO_DEBUG_ROUTE, "Re-opened this port\n"); rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->MagicFlags |= MAGIC_REBOOT; rio_spin_unlock_irqrestore(&PortP->portSem, flags); } } } } /* ** keep a copy of the module types! */ HostP->UnixRups[ThisUnit].ModTypes = Mod; if (RtaType == TYPE_RTA16) HostP->UnixRups[ThisUnit2].ModTypes = Mod; /* ** If either of the modules on this unit is read-only or write-only ** or none-xprint, then we need to transfer that info over to the ** relevant ports. */ if ( HostP->Mapping[ThisUnit].SysPort != NO_PORT ) { for ( port=0; port<PORTS_PER_MODULE; port++ ) { p->RIOPortp[port+HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK; p->RIOPortp[port+HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port]; p->RIOPortp[port+PORTS_PER_MODULE+HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK; p->RIOPortp[port+PORTS_PER_MODULE+HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port]; } if (RtaType == TYPE_RTA16) { for ( port=0; port<PORTS_PER_MODULE; port++ ) { p->RIOPortp[port+HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK; p->RIOPortp[port+HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port]; p->RIOPortp[port+PORTS_PER_MODULE+HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK; p->RIOPortp[port+PORTS_PER_MODULE+HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port]; } } } /* ** Job done, get on with the interrupts! */ return TRUE; } } /* ** There is no table entry for this RTA at all. ** ** Lets check to see if we actually booted this unit - if not, ** then we reset it and it will go round the loop of being booted ** we can then worry about trying to fit it into the table. */ for ( ThisUnit=0; ThisUnit<HostP->NumExtraBooted; ThisUnit++ ) if ( HostP->ExtraUnits[ThisUnit] == RtaUniq ) break; if ( ThisUnit == HostP->NumExtraBooted && ThisUnit != MAX_EXTRA_UNITS ) { /* ** if the unit wasn't in the table, and the table wasn't full, then ** we reset the unit, because we didn't boot it. ** However, if the table is full, it could be that we did boot ** this unit, and so we won't reboot it, because it isn't really ** all that disasterous to keep the old bins in most cases. This ** is a rather tacky feature, but we are on the edge of reallity ** here, because the implication is that someone has connected ** 16+MAX_EXTRA_UNITS onto one host. */ static int UnknownMesgDone = 0; if ( !UnknownMesgDone ) { if (! p->RIONoMessage) cprintf("One or more unknown RTAs are being updated.\n"); UnknownMesgDone = 1; } PktReplyP->Command = ROUTE_FOAD; HostP->Copy("RT_FOAD",PktReplyP->CommandText,7); } else { /* ** we did boot it (as an extra), and there may now be a table ** slot free (because of a delete), so we will try to make ** a tentative entry for it, so that the configurator can see it ** and fill in the details for us. */ if (RtaType == TYPE_RTA16) { if (RIOFindFreeID(p, HostP, &ThisUnit, &ThisUnit2) == 0) { RIODefaultName(p, HostP, ThisUnit); FillSlot(ThisUnit, ThisUnit2, RtaUniq, HostP); } } else { if (RIOFindFreeID(p, HostP, &ThisUnit, NULL) == 0) { RIODefaultName(p, HostP, ThisUnit); FillSlot(ThisUnit, 0, RtaUniq, HostP); } } PktReplyP->Command = ROUTE_USED; HostP->Copy("RT_USED",PktReplyP->CommandText,7); } RIOQueueCmdBlk( HostP, Rup, CmdBlkP); return TRUE; }
/* ** config.rio has taken a dislike to one of the gross maps entries. ** if the entry is suitably inactive, then we can gob on it and remove ** it from the table. */ int RIODeleteRta(struct rio_info *p, struct Map *MapP) { int host, entry, port, link; int SysPort; struct Host *HostP; struct Map *HostMapP; struct Port *PortP; int work_done = 0; unsigned long lock_flags, sem_flags; rio_dprintk(RIO_DEBUG_TABLE, "Delete entry on host %x, rta %x\n", MapP->HostUniqueNum, MapP->RtaUniqueNum); for (host = 0; host < p->RIONumHosts; host++) { HostP = &p->RIOHosts[host]; rio_spin_lock_irqsave(&HostP->HostLock, lock_flags); if ((HostP->Flags & RUN_STATE) != RC_RUNNING) { rio_spin_unlock_irqrestore(&HostP->HostLock, lock_flags); continue; } for (entry = 0; entry < MAX_RUP; entry++) { if (MapP->RtaUniqueNum == HostP->Mapping[entry].RtaUniqueNum) { HostMapP = &HostP->Mapping[entry]; rio_dprintk(RIO_DEBUG_TABLE, "Found entry offset %d on host %s\n", entry, HostP->Name); /* ** Check all four links of the unit are disconnected */ for (link = 0; link < LINKS_PER_UNIT; link++) { if (HostMapP->Topology[link].Unit != ROUTE_DISCONNECT) { rio_dprintk(RIO_DEBUG_TABLE, "Entry is in use and cannot be deleted!\n"); p->RIOError.Error = UNIT_IS_IN_USE; rio_spin_unlock_irqrestore(&HostP->HostLock, lock_flags); return -EBUSY; } } /* ** Slot has been allocated, BUT not booted/routed/ ** connected/selected or anything else-ed */ SysPort = HostMapP->SysPort; if (SysPort != NO_PORT) { for (port = SysPort; port < SysPort + PORTS_PER_RTA; port++) { PortP = p->RIOPortp[port]; rio_dprintk(RIO_DEBUG_TABLE, "Unmap port\n"); rio_spin_lock_irqsave(&PortP->portSem, sem_flags); PortP->Mapped = 0; if (PortP->State & (RIO_MOPEN | RIO_LOPEN)) { rio_dprintk(RIO_DEBUG_TABLE, "Gob on port\n"); PortP->TxBufferIn = PortP->TxBufferOut = 0; /* What should I do wakeup( &PortP->TxBufferIn ); wakeup( &PortP->TxBufferOut); */ PortP->InUse = NOT_INUSE; /* What should I do wakeup( &PortP->InUse ); signal(PortP->TtyP->t_pgrp,SIGKILL); ttyflush(PortP->TtyP,(FREAD|FWRITE)); */ PortP->State |= RIO_CLOSING | RIO_DELETED; } /* ** For the second slot of a 16 port RTA, the ** driver needs to reset the changes made to ** the phb to port mappings in RIORouteRup. */ if (PortP->SecondBlock) { u16 dest_unit = HostMapP->ID; u16 dest_port = port - SysPort; u16 __iomem *TxPktP; struct PKT __iomem *Pkt; for (TxPktP = PortP->TxStart; TxPktP <= PortP->TxEnd; TxPktP++) { /* ** *TxPktP is the pointer to the ** transmit packet on the host card. ** This needs to be translated into ** a 32 bit pointer so it can be ** accessed from the driver. */ Pkt = (struct PKT __iomem *) RIO_PTR(HostP->Caddr, readw(&*TxPktP)); rio_dprintk(RIO_DEBUG_TABLE, "Tx packet (%x) destination: Old %x:%x New %x:%x\n", readw(TxPktP), readb(&Pkt->dest_unit), readb(&Pkt->dest_port), dest_unit, dest_port); writew(dest_unit, &Pkt->dest_unit); writew(dest_port, &Pkt->dest_port); } rio_dprintk(RIO_DEBUG_TABLE, "Port %d phb destination: Old %x:%x New %x:%x\n", port, readb(&PortP->PhbP->destination) & 0xff, (readb(&PortP->PhbP->destination) >> 8) & 0xff, dest_unit, dest_port); writew(dest_unit + (dest_port << 8), &PortP->PhbP->destination); } rio_spin_unlock_irqrestore(&PortP->portSem, sem_flags); } } rio_dprintk(RIO_DEBUG_TABLE, "Entry nulled.\n"); memset(HostMapP, 0, sizeof(struct Map)); work_done++; } }
int riotopen(struct tty_struct *tty, struct file *filp) { unsigned int SysPort; int repeat_this = 250; struct Port *PortP; /* pointer to the port structure */ unsigned long flags; int retval = 0; func_enter(); /* Make sure driver_data is NULL in case the rio isn't booted jet. Else gs_close is going to oops. */ tty->driver_data = NULL; SysPort = rio_minor(tty); if (p->RIOFailed) { rio_dprintk(RIO_DEBUG_TTY, "System initialisation failed\n"); func_exit(); return -ENXIO; } rio_dprintk(RIO_DEBUG_TTY, "port open SysPort %d (mapped:%d)\n", SysPort, p->RIOPortp[SysPort]->Mapped); /* ** Validate that we have received a legitimate request. ** Currently, just check that we are opening a port on ** a host card that actually exists, and that the port ** has been mapped onto a host. */ if (SysPort >= RIO_PORTS) { /* out of range ? */ rio_dprintk(RIO_DEBUG_TTY, "Illegal port number %d\n", SysPort); func_exit(); return -ENXIO; } /* ** Grab pointer to the port stucture */ PortP = p->RIOPortp[SysPort]; /* Get control struc */ rio_dprintk(RIO_DEBUG_TTY, "PortP: %p\n", PortP); if (!PortP->Mapped) { /* we aren't mapped yet! */ /* ** The system doesn't know which RTA this port ** corresponds to. */ rio_dprintk(RIO_DEBUG_TTY, "port not mapped into system\n"); func_exit(); return -ENXIO; } tty->driver_data = PortP; PortP->gs.tty = tty; PortP->gs.count++; rio_dprintk(RIO_DEBUG_TTY, "%d bytes in tx buffer\n", PortP->gs.xmit_cnt); retval = gs_init_port(&PortP->gs); if (retval) { PortP->gs.count--; return -ENXIO; } /* ** If the host hasn't been booted yet, then ** fail */ if ((PortP->HostP->Flags & RUN_STATE) != RC_RUNNING) { rio_dprintk(RIO_DEBUG_TTY, "Host not running\n"); func_exit(); return -ENXIO; } /* ** If the RTA has not booted yet and the user has choosen to block ** until the RTA is present then we must spin here waiting for ** the RTA to boot. */ /* I find the above code a bit hairy. I find the below code easier to read and shorter. Now, if it works too that would be great... -- REW */ rio_dprintk(RIO_DEBUG_TTY, "Checking if RTA has booted... \n"); while (!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED)) { if (!PortP->WaitUntilBooted) { rio_dprintk(RIO_DEBUG_TTY, "RTA never booted\n"); func_exit(); return -ENXIO; } /* Under Linux you'd normally use a wait instead of this busy-waiting. I'll stick with the old implementation for now. --REW */ if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { rio_dprintk(RIO_DEBUG_TTY, "RTA_wait_for_boot: EINTR in delay \n"); func_exit(); return -EINTR; } if (repeat_this-- <= 0) { rio_dprintk(RIO_DEBUG_TTY, "Waiting for RTA to boot timeout\n"); func_exit(); return -EIO; } } rio_dprintk(RIO_DEBUG_TTY, "RTA has been booted\n"); rio_spin_lock_irqsave(&PortP->portSem, flags); if (p->RIOHalted) { goto bombout; } /* ** If the port is in the final throws of being closed, ** we should wait here (politely), waiting ** for it to finish, so that it doesn't close us! */ while ((PortP->State & RIO_CLOSING) && !p->RIOHalted) { rio_dprintk(RIO_DEBUG_TTY, "Waiting for RIO_CLOSING to go away\n"); if (repeat_this-- <= 0) { rio_dprintk(RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n"); RIOPreemptiveCmd(p, PortP, FCLOSE); retval = -EINTR; goto bombout; } rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { rio_spin_lock_irqsave(&PortP->portSem, flags); retval = -EINTR; goto bombout; } rio_spin_lock_irqsave(&PortP->portSem, flags); } if (!PortP->Mapped) { rio_dprintk(RIO_DEBUG_TTY, "Port unmapped while closing!\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); retval = -ENXIO; func_exit(); return retval; } if (p->RIOHalted) { goto bombout; } /* ** 15.10.1998 ARG - ESIL 0761 part fix ** RIO has it's own CTSFLOW and RTSFLOW flags in 'Config' in the port structure, ** we need to make sure that the flags are clear when the port is opened. */ /* Uh? Suppose I turn these on and then another process opens the port again? The flags get cleared! Not good. -- REW */ if (!(PortP->State & (RIO_LOPEN | RIO_MOPEN))) { PortP->Config &= ~(RIO_CTSFLOW | RIO_RTSFLOW); } if (!(PortP->firstOpen)) { /* First time ? */ rio_dprintk(RIO_DEBUG_TTY, "First open for this port\n"); PortP->firstOpen++; PortP->CookMode = 0; /* XXX RIOCookMode(tp); */ PortP->InUse = NOT_INUSE; /* Tentative fix for bug PR27. Didn't work. */ /* PortP->gs.xmit_cnt = 0; */ rio_spin_unlock_irqrestore(&PortP->portSem, flags); /* Someone explain to me why this delay/config is here. If I read the docs correctly the "open" command piggybacks the parameters immediately. -- REW */ RIOParam(PortP, OPEN, 1, OK_TO_SLEEP); /* Open the port */ rio_spin_lock_irqsave(&PortP->portSem, flags); /* ** wait for the port to be not closed. */ while (!(PortP->PortState & PORT_ISOPEN) && !p->RIOHalted) { rio_dprintk(RIO_DEBUG_TTY, "Waiting for PORT_ISOPEN-currently %x\n", PortP->PortState); rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { rio_dprintk(RIO_DEBUG_TTY, "Waiting for open to finish broken by signal\n"); RIOPreemptiveCmd(p, PortP, FCLOSE); func_exit(); return -EINTR; } rio_spin_lock_irqsave(&PortP->portSem, flags); } if (p->RIOHalted) { retval = -EIO; bombout: /* RIOClearUp( PortP ); */ rio_spin_unlock_irqrestore(&PortP->portSem, flags); return retval; } rio_dprintk(RIO_DEBUG_TTY, "PORT_ISOPEN found\n"); } rio_dprintk(RIO_DEBUG_TTY, "Modem - test for carrier\n"); /* ** ACTION ** insert test for carrier here. -- ??? ** I already see that test here. What's the deal? -- REW */ if ((PortP->gs.tty->termios->c_cflag & CLOCAL) || (PortP->ModemState & MSVR1_CD)) { rio_dprintk(RIO_DEBUG_TTY, "open(%d) Modem carr on\n", SysPort); /* tp->tm.c_state |= CARR_ON; wakeup((caddr_t) &tp->tm.c_canq); */ PortP->State |= RIO_CARR_ON; wake_up_interruptible(&PortP->gs.open_wait); } else { /* no carrier - wait for DCD */ /* while (!(PortP->gs.tty->termios->c_state & CARR_ON) && !(filp->f_flags & O_NONBLOCK) && !p->RIOHalted ) */ while (!(PortP->State & RIO_CARR_ON) && !(filp->f_flags & O_NONBLOCK) && !p->RIOHalted) { rio_dprintk(RIO_DEBUG_TTY, "open(%d) sleeping for carr on\n", SysPort); /* PortP->gs.tty->termios->c_state |= WOPEN; */ PortP->State |= RIO_WOPEN; rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { rio_spin_lock_irqsave(&PortP->portSem, flags); /* ** ACTION: verify that this is a good thing ** to do here. -- ??? ** I think it's OK. -- REW */ rio_dprintk(RIO_DEBUG_TTY, "open(%d) sleeping for carr broken by signal\n", SysPort); RIOPreemptiveCmd(p, PortP, FCLOSE); /* tp->tm.c_state &= ~WOPEN; */ PortP->State &= ~RIO_WOPEN; rio_spin_unlock_irqrestore(&PortP->portSem, flags); func_exit(); return -EINTR; } rio_spin_lock_irqsave(&PortP->portSem, flags); } PortP->State &= ~RIO_WOPEN; } if (p->RIOHalted) goto bombout; rio_dprintk(RIO_DEBUG_TTY, "Setting RIO_MOPEN\n"); PortP->State |= RIO_MOPEN; if (p->RIOHalted) goto bombout; rio_dprintk(RIO_DEBUG_TTY, "high level open done\n"); /* ** Count opens for port statistics reporting */ if (PortP->statsGather) PortP->opens++; rio_spin_unlock_irqrestore(&PortP->portSem, flags); rio_dprintk(RIO_DEBUG_TTY, "Returning from open\n"); func_exit(); return 0; }
/* ** RIOClose the port. ** The operating system thinks that this is last close for the device. ** As there are two interfaces to the port (Modem and tty), we need to ** check that both are closed before we close the device. */ int riotclose(void *ptr) { struct Port *PortP = ptr; /* pointer to the port structure */ int deleted = 0; int try = -1; /* Disable the timeouts by setting them to -1 */ int repeat_this = -1; /* Congrats to those having 15 years of uptime! (You get to break the driver.) */ unsigned long end_time; struct tty_struct *tty; unsigned long flags; int rv = 0; rio_dprintk(RIO_DEBUG_TTY, "port close SysPort %d\n", PortP->PortNum); /* PortP = p->RIOPortp[SysPort]; */ rio_dprintk(RIO_DEBUG_TTY, "Port is at address %p\n", PortP); /* tp = PortP->TtyP; *//* Get tty */ tty = PortP->gs.tty; rio_dprintk(RIO_DEBUG_TTY, "TTY is at address %p\n", tty); if (PortP->gs.closing_wait) end_time = jiffies + PortP->gs.closing_wait; else end_time = jiffies + MAX_SCHEDULE_TIMEOUT; rio_spin_lock_irqsave(&PortP->portSem, flags); /* ** Setting this flag will make any process trying to open ** this port block until we are complete closing it. */ PortP->State |= RIO_CLOSING; if ((PortP->State & RIO_DELETED)) { rio_dprintk(RIO_DEBUG_TTY, "Close on deleted RTA\n"); deleted = 1; } if (p->RIOHalted) { RIOClearUp(PortP); rv = -EIO; goto close_end; } rio_dprintk(RIO_DEBUG_TTY, "Clear bits\n"); /* ** clear the open bits for this device */ PortP->State &= ~RIO_MOPEN; PortP->State &= ~RIO_CARR_ON; PortP->ModemState &= ~MSVR1_CD; /* ** If the device was open as both a Modem and a tty line ** then we need to wimp out here, as the port has not really ** been finally closed (gee, whizz!) The test here uses the ** bit for the OTHER mode of operation, to see if THAT is ** still active! */ if ((PortP->State & (RIO_LOPEN | RIO_MOPEN))) { /* ** The port is still open for the other task - ** return, pretending that we are still active. */ rio_dprintk(RIO_DEBUG_TTY, "Channel %d still open !\n", PortP->PortNum); PortP->State &= ~RIO_CLOSING; if (PortP->firstOpen) PortP->firstOpen--; rio_spin_unlock_irqrestore(&PortP->portSem, flags); return -EIO; } rio_dprintk(RIO_DEBUG_TTY, "Closing down - everything must go!\n"); PortP->State &= ~RIO_DYNOROD; /* ** This is where we wait for the port ** to drain down before closing. Bye-bye.... ** (We never meant to do this) */ rio_dprintk(RIO_DEBUG_TTY, "Timeout 1 starts\n"); if (!deleted) while ((PortP->InUse != NOT_INUSE) && !p->RIOHalted && (PortP->TxBufferIn != PortP->TxBufferOut)) { if (repeat_this-- <= 0) { rv = -EINTR; rio_dprintk(RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n"); RIOPreemptiveCmd(p, PortP, FCLOSE); goto close_end; } rio_dprintk(RIO_DEBUG_TTY, "Calling timeout to flush in closing\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (RIODelay_ni(PortP, HUNDRED_MS * 10) == RIO_FAIL) { rio_dprintk(RIO_DEBUG_TTY, "RTA EINTR in delay \n"); rv = -EINTR; rio_spin_lock_irqsave(&PortP->portSem, flags); goto close_end; } rio_spin_lock_irqsave(&PortP->portSem, flags); } PortP->TxBufferIn = PortP->TxBufferOut = 0; repeat_this = 0xff; PortP->InUse = 0; if ((PortP->State & (RIO_LOPEN | RIO_MOPEN))) { /* ** The port has been re-opened for the other task - ** return, pretending that we are still active. */ rio_dprintk(RIO_DEBUG_TTY, "Channel %d re-open!\n", PortP->PortNum); PortP->State &= ~RIO_CLOSING; rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (PortP->firstOpen) PortP->firstOpen--; return -EIO; } if (p->RIOHalted) { RIOClearUp(PortP); goto close_end; } /* Can't call RIOShortCommand with the port locked. */ rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (RIOShortCommand(p, PortP, CLOSE, 1, 0) == RIO_FAIL) { RIOPreemptiveCmd(p, PortP, FCLOSE); rio_spin_lock_irqsave(&PortP->portSem, flags); goto close_end; } if (!deleted) while (try && (PortP->PortState & PORT_ISOPEN)) { try--; if (time_after(jiffies, end_time)) { rio_dprintk(RIO_DEBUG_TTY, "Run out of tries - force the bugger shut!\n"); RIOPreemptiveCmd(p, PortP, FCLOSE); break; } rio_dprintk(RIO_DEBUG_TTY, "Close: PortState:ISOPEN is %d\n", PortP->PortState & PORT_ISOPEN); if (p->RIOHalted) { RIOClearUp(PortP); rio_spin_lock_irqsave(&PortP->portSem, flags); goto close_end; } if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { rio_dprintk(RIO_DEBUG_TTY, "RTA EINTR in delay \n"); RIOPreemptiveCmd(p, PortP, FCLOSE); break; } } rio_spin_lock_irqsave(&PortP->portSem, flags); rio_dprintk(RIO_DEBUG_TTY, "Close: try was %d on completion\n", try); /* RIOPreemptiveCmd(p, PortP, FCLOSE); */ /* ** 15.10.1998 ARG - ESIL 0761 part fix ** RIO has it's own CTSFLOW and RTSFLOW flags in 'Config' in the port structure,** we need to make sure that the flags are clear when the port is opened. */ PortP->Config &= ~(RIO_CTSFLOW | RIO_RTSFLOW); /* ** Count opens for port statistics reporting */ if (PortP->statsGather) PortP->closes++; close_end: /* XXX: Why would a "DELETED" flag be reset here? I'd have thought that a "deleted" flag means that the port was permanently gone, but here we can make it reappear by it being in close during the "deletion". */ PortP->State &= ~(RIO_CLOSING | RIO_DELETED); if (PortP->firstOpen) PortP->firstOpen--; rio_spin_unlock_irqrestore(&PortP->portSem, flags); rio_dprintk(RIO_DEBUG_TTY, "Return from close\n"); return rv; } static void RIOClearUp(struct Port *PortP) { rio_dprintk(RIO_DEBUG_TTY, "RIOHalted set\n"); PortP->Config = 0; /* Direct semaphore */ PortP->PortState = 0; PortP->firstOpen = 0; PortP->FlushCmdBodge = 0; PortP->ModemState = PortP->CookMode = 0; PortP->Mapped = 0; PortP->WflushFlag = 0; PortP->MagicFlags = 0; PortP->RxDataStart = 0; PortP->TxBufferIn = 0; PortP->TxBufferOut = 0; } /* ** Put a command onto a port. ** The PortPointer, command, length and arg are passed. ** The len is the length *inclusive* of the command byte, ** and so for a command that takes no data, len==1. ** The arg is a single byte, and is only used if len==2. ** Other values of len aren't allowed, and will cause ** a panic. */ int RIOShortCommand(struct rio_info *p, struct Port *PortP, int command, int len, int arg) { struct PKT __iomem *PacketP; int retries = 20; /* at 10 per second -> 2 seconds */ unsigned long flags; rio_dprintk(RIO_DEBUG_TTY, "entering shortcommand.\n"); if (PortP->State & RIO_DELETED) { rio_dprintk(RIO_DEBUG_TTY, "Short command to deleted RTA ignored\n"); return RIO_FAIL; } rio_spin_lock_irqsave(&PortP->portSem, flags); /* ** If the port is in use for pre-emptive command, then wait for it to ** be free again. */ while ((PortP->InUse != NOT_INUSE) && !p->RIOHalted) { rio_dprintk(RIO_DEBUG_TTY, "Waiting for not in use (%d)\n", retries); rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (retries-- <= 0) { return RIO_FAIL; } if (RIODelay_ni(PortP, HUNDRED_MS) == RIO_FAIL) { return RIO_FAIL; } rio_spin_lock_irqsave(&PortP->portSem, flags); } if (PortP->State & RIO_DELETED) { rio_dprintk(RIO_DEBUG_TTY, "Short command to deleted RTA ignored\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); return RIO_FAIL; } while (!can_add_transmit(&PacketP, PortP) && !p->RIOHalted) { rio_dprintk(RIO_DEBUG_TTY, "Waiting to add short command to queue (%d)\n", retries); rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (retries-- <= 0) { rio_dprintk(RIO_DEBUG_TTY, "out of tries. Failing\n"); return RIO_FAIL; } if (RIODelay_ni(PortP, HUNDRED_MS) == RIO_FAIL) { return RIO_FAIL; } rio_spin_lock_irqsave(&PortP->portSem, flags); } if (p->RIOHalted) { rio_spin_unlock_irqrestore(&PortP->portSem, flags); return RIO_FAIL; } /* ** set the command byte and the argument byte */ writeb(command, &PacketP->data[0]); if (len == 2) writeb(arg, &PacketP->data[1]); /* ** set the length of the packet and set the command bit. */ writeb(PKT_CMD_BIT | len, &PacketP->len); add_transmit(PortP); /* ** Count characters transmitted for port statistics reporting */ if (PortP->statsGather) PortP->txchars += len; rio_spin_unlock_irqrestore(&PortP->portSem, flags); return p->RIOHalted ? RIO_FAIL : ~RIO_FAIL; }
/* ** config.rio has taken a dislike to one of the gross maps entries. ** if the entry is suitably inactive, then we can gob on it and remove ** it from the table. */ int RIODeleteRta(struct rio_info *p, struct Map *MapP) { int host, entry, port, link; int SysPort; struct Host *HostP; struct Map *HostMapP; struct Port *PortP; int work_done = 0; unsigned long lock_flags, sem_flags; ; for (host = 0; host < p->RIONumHosts; host++) { HostP = &p->RIOHosts[host]; rio_spin_lock_irqsave(&HostP->HostLock, lock_flags); if ((HostP->Flags & RUN_STATE) != RC_RUNNING) { rio_spin_unlock_irqrestore(&HostP->HostLock, lock_flags); continue; } for (entry = 0; entry < MAX_RUP; entry++) { if (MapP->RtaUniqueNum == HostP->Mapping[entry].RtaUniqueNum) { HostMapP = &HostP->Mapping[entry]; ; /* ** Check all four links of the unit are disconnected */ for (link = 0; link < LINKS_PER_UNIT; link++) { if (HostMapP->Topology[link].Unit != ROUTE_DISCONNECT) { ; p->RIOError.Error = UNIT_IS_IN_USE; rio_spin_unlock_irqrestore(&HostP->HostLock, lock_flags); return -EBUSY; } } /* ** Slot has been allocated, BUT not booted/routed/ ** connected/selected or anything else-ed */ SysPort = HostMapP->SysPort; if (SysPort != NO_PORT) { for (port = SysPort; port < SysPort + PORTS_PER_RTA; port++) { PortP = p->RIOPortp[port]; ; rio_spin_lock_irqsave(&PortP->portSem, sem_flags); PortP->Mapped = 0; if (PortP->State & (RIO_MOPEN | RIO_LOPEN)) { ; PortP->TxBufferIn = PortP->TxBufferOut = 0; /* What should I do wakeup( &PortP->TxBufferIn ); wakeup( &PortP->TxBufferOut); */ PortP->InUse = NOT_INUSE; /* What should I do wakeup( &PortP->InUse ); signal(PortP->TtyP->t_pgrp,SIGKILL); ttyflush(PortP->TtyP,(FREAD|FWRITE)); */ PortP->State |= RIO_CLOSING | RIO_DELETED; } /* ** For the second slot of a 16 port RTA, the ** driver needs to reset the changes made to ** the phb to port mappings in RIORouteRup. */ if (PortP->SecondBlock) { u16 dest_unit = HostMapP->ID; u16 dest_port = port - SysPort; u16 __iomem *TxPktP; struct PKT __iomem *Pkt; for (TxPktP = PortP->TxStart; TxPktP <= PortP->TxEnd; TxPktP++) { /* ** *TxPktP is the pointer to the ** transmit packet on the host card. ** This needs to be translated into ** a 32 bit pointer so it can be ** accessed from the driver. */ Pkt = (struct PKT __iomem *) RIO_PTR(HostP->Caddr, readw(&*TxPktP)); ; writew(dest_unit, &Pkt->dest_unit); writew(dest_port, &Pkt->dest_port); } ; writew(dest_unit + (dest_port << 8), &PortP->PhbP->destination); } rio_spin_unlock_irqrestore(&PortP->portSem, sem_flags); } } ; memset(HostMapP, 0, sizeof(struct Map)); work_done++; } } rio_spin_unlock_irqrestore(&HostP->HostLock, lock_flags); } /* XXXXX lock me up */ for (entry = 0; entry < TOTAL_MAP_ENTRIES; entry++) { if (p->RIOSavedTable[entry].RtaUniqueNum == MapP->RtaUniqueNum) { memset(&p->RIOSavedTable[entry], 0, sizeof(struct Map)); work_done++; } if (p->RIOConnectTable[entry].RtaUniqueNum == MapP->RtaUniqueNum) { memset(&p->RIOConnectTable[entry], 0, sizeof(struct Map)); work_done++; } } if (work_done) return 0; ; p->RIOError.Error = COULDNT_FIND_ENTRY; return -ENXIO; }
int RIOReMapPorts(struct rio_info *p, struct Host *HostP, struct Map *HostMapP) { struct Port *PortP; unsigned int SubEnt; unsigned int HostPort; unsigned int SysPort; u16 RtaType; unsigned long flags; ; /* ** We need to tell the UnixRups which sysport the rup corresponds to */ HostP->UnixRups[HostMapP->ID - 1].BaseSysPort = HostMapP->SysPort; if (HostMapP->SysPort == NO_PORT) return (0); RtaType = GetUnitType(HostMapP->RtaUniqueNum); ; /* ** now map each of its eight ports */ for (SubEnt = 0; SubEnt < PORTS_PER_RTA; SubEnt++) { ; SysPort = HostMapP->SysPort + SubEnt; /* portnumber within system */ /* portnumber on host */ HostPort = (HostMapP->ID - 1) * PORTS_PER_RTA + SubEnt; ; PortP = p->RIOPortp[SysPort]; ; /* ** Point at all the real neat data structures */ rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->HostP = HostP; PortP->Caddr = HostP->Caddr; /* ** The PhbP cannot be filled in yet ** unless the host has been booted */ if ((HostP->Flags & RUN_STATE) == RC_RUNNING) { struct PHB __iomem *PhbP = PortP->PhbP = &HostP->PhbP[HostPort]; PortP->TxAdd = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->tx_add)); PortP->TxStart = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->tx_start)); PortP->TxEnd = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->tx_end)); PortP->RxRemove = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->rx_remove)); PortP->RxStart = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->rx_start)); PortP->RxEnd = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->rx_end)); } else PortP->PhbP = NULL; /* ** port related flags */ PortP->HostPort = HostPort; /* ** For each part of a 16 port RTA, RupNum is ID - 1. */ PortP->RupNum = HostMapP->ID - 1; if (HostMapP->Flags & RTA16_SECOND_SLOT) { PortP->ID2 = HostMapP->ID2 - 1; PortP->SecondBlock = 1; } else { PortP->ID2 = 0; PortP->SecondBlock = 0; } PortP->RtaUniqueNum = HostMapP->RtaUniqueNum; /* ** If the port was already mapped then thats all we need to do. */ if (PortP->Mapped) { rio_spin_unlock_irqrestore(&PortP->portSem, flags); continue; } else HostMapP->Flags &= ~RTA_NEWBOOT; PortP->State = 0; PortP->Config = 0; /* ** Check out the module type - if it is special (read only etc.) ** then we need to set flags in the PortP->Config. ** Note: For 16 port RTA, all ports are of the same type. */ if (RtaType == TYPE_RTA16) { PortP->Config |= p->RIOModuleTypes[HostP->UnixRups[HostMapP->ID - 1].ModTypes].Flags[SubEnt % PORTS_PER_MODULE]; } else { if (SubEnt < PORTS_PER_MODULE) PortP->Config |= p->RIOModuleTypes[LONYBLE(HostP->UnixRups[HostMapP->ID - 1].ModTypes)].Flags[SubEnt % PORTS_PER_MODULE]; else PortP->Config |= p->RIOModuleTypes[HINYBLE(HostP->UnixRups[HostMapP->ID - 1].ModTypes)].Flags[SubEnt % PORTS_PER_MODULE]; } /* ** more port related flags */ PortP->PortState = 0; PortP->ModemLines = 0; PortP->ModemState = 0; PortP->CookMode = COOK_WELL; PortP->ParamSem = 0; PortP->FlushCmdBodge = 0; PortP->WflushFlag = 0; PortP->MagicFlags = 0; PortP->Lock = 0; PortP->Store = 0; PortP->FirstOpen = 1; /* ** Buffers 'n things */ PortP->RxDataStart = 0; PortP->Cor2Copy = 0; PortP->Name = &HostMapP->Name[0]; PortP->statsGather = 0; PortP->txchars = 0; PortP->rxchars = 0; PortP->opens = 0; PortP->closes = 0; PortP->ioctls = 0; if (PortP->TxRingBuffer) memset(PortP->TxRingBuffer, 0, p->RIOBufferSize); else if (p->RIOBufferSize) { PortP->TxRingBuffer = kzalloc(p->RIOBufferSize, GFP_KERNEL); } PortP->TxBufferOut = 0; PortP->TxBufferIn = 0; PortP->Debug = 0; /* ** LastRxTgl stores the state of the rx toggle bit for this ** port, to be compared with the state of the next pkt received. ** If the same, we have received the same rx pkt from the RTA ** twice. Initialise to a value not equal to PHB_RX_TGL or 0. */ PortP->LastRxTgl = ~(u8) PHB_RX_TGL; /* ** and mark the port as usable */ PortP->Mapped = 1; rio_spin_unlock_irqrestore(&PortP->portSem, flags); } if (HostMapP->SysPort < p->RIOFirstPortsMapped) p->RIOFirstPortsMapped = HostMapP->SysPort; if (HostMapP->SysPort > p->RIOLastPortsMapped) p->RIOLastPortsMapped = HostMapP->SysPort; return 0; }
/* ** RIOParam is used to open or configure a port. You pass it a PortP, ** which will have a tty struct attached to it. You also pass a command, ** either OPEN or CONFIG. The port's setup is taken from the t_ fields ** of the tty struct inside the PortP, and the port is either opened ** or re-configured. You must also tell RIOParam if the device is a modem ** device or not (i.e. top bit of minor number set or clear - take special ** care when deciding on this!). ** RIOParam neither flushes nor waits for drain, and is NOT preemptive. ** ** RIOParam assumes it will be called at splrio(), and also assumes ** that CookMode is set correctly in the port structure. ** ** NB. for MPX ** tty lock must NOT have been previously acquired. */ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag) { struct tty_struct *TtyP; int retval; struct phb_param __iomem *phb_param_ptr; struct PKT __iomem *PacketP; int res; u8 Cor1 = 0, Cor2 = 0, Cor4 = 0, Cor5 = 0; u8 TxXon = 0, TxXoff = 0, RxXon = 0, RxXoff = 0; u8 LNext = 0, TxBaud = 0, RxBaud = 0; int retries = 0xff; unsigned long flags; func_enter(); TtyP = PortP->gs.tty; rio_dprintk(RIO_DEBUG_PARAM, "RIOParam: Port:%d cmd:%d Modem:%d SleepFlag:%d Mapped: %d, tty=%p\n", PortP->PortNum, cmd, Modem, SleepFlag, PortP->Mapped, TtyP); if (!TtyP) { rio_dprintk(RIO_DEBUG_PARAM, "Can't call rioparam with null tty.\n"); func_exit(); return RIO_FAIL; } rio_spin_lock_irqsave(&PortP->portSem, flags); if (cmd == RIOC_OPEN) { /* ** If the port is set to store or lock the parameters, and it is ** paramed with OPEN, we want to restore the saved port termio, but ** only if StoredTermio has been saved, i.e. NOT 1st open after reboot. */ } /* ** wait for space */ while (!(res = can_add_transmit(&PacketP, PortP)) || (PortP->InUse != NOT_INUSE)) { if (retries-- <= 0) { break; } if (PortP->InUse != NOT_INUSE) { rio_dprintk(RIO_DEBUG_PARAM, "Port IN_USE for pre-emptive command\n"); } if (!res) { rio_dprintk(RIO_DEBUG_PARAM, "Port has no space on transmit queue\n"); } if (SleepFlag != OK_TO_SLEEP) { rio_spin_unlock_irqrestore(&PortP->portSem, flags); func_exit(); return RIO_FAIL; } rio_dprintk(RIO_DEBUG_PARAM, "wait for can_add_transmit\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); retval = RIODelay(PortP, HUNDRED_MS); rio_spin_lock_irqsave(&PortP->portSem, flags); if (retval == RIO_FAIL) { rio_dprintk(RIO_DEBUG_PARAM, "wait for can_add_transmit broken by signal\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); func_exit(); return -EINTR; } if (PortP->State & RIO_DELETED) { rio_spin_unlock_irqrestore(&PortP->portSem, flags); func_exit(); return 0; } } if (!res) { rio_spin_unlock_irqrestore(&PortP->portSem, flags); func_exit(); return RIO_FAIL; } rio_dprintk(RIO_DEBUG_PARAM, "can_add_transmit() returns %x\n", res); rio_dprintk(RIO_DEBUG_PARAM, "Packet is %p\n", PacketP); phb_param_ptr = (struct phb_param __iomem *) PacketP->data; switch (TtyP->termios->c_cflag & CSIZE) { case CS5: { rio_dprintk(RIO_DEBUG_PARAM, "5 bit data\n"); Cor1 |= RIOC_COR1_5BITS; break; } case CS6: { rio_dprintk(RIO_DEBUG_PARAM, "6 bit data\n"); Cor1 |= RIOC_COR1_6BITS; break; } case CS7: { rio_dprintk(RIO_DEBUG_PARAM, "7 bit data\n"); Cor1 |= RIOC_COR1_7BITS; break; } case CS8: { rio_dprintk(RIO_DEBUG_PARAM, "8 bit data\n"); Cor1 |= RIOC_COR1_8BITS; break; } } if (TtyP->termios->c_cflag & CSTOPB) { rio_dprintk(RIO_DEBUG_PARAM, "2 stop bits\n"); Cor1 |= RIOC_COR1_2STOP; } else { rio_dprintk(RIO_DEBUG_PARAM, "1 stop bit\n"); Cor1 |= RIOC_COR1_1STOP; } if (TtyP->termios->c_cflag & PARENB) { rio_dprintk(RIO_DEBUG_PARAM, "Enable parity\n"); Cor1 |= RIOC_COR1_NORMAL; } else { rio_dprintk(RIO_DEBUG_PARAM, "Disable parity\n"); Cor1 |= RIOC_COR1_NOP; } if (TtyP->termios->c_cflag & PARODD) { rio_dprintk(RIO_DEBUG_PARAM, "Odd parity\n"); Cor1 |= RIOC_COR1_ODD; } else { rio_dprintk(RIO_DEBUG_PARAM, "Even parity\n"); Cor1 |= RIOC_COR1_EVEN; } /* ** COR 2 */ if (TtyP->termios->c_iflag & IXON) { rio_dprintk(RIO_DEBUG_PARAM, "Enable start/stop output control\n"); Cor2 |= RIOC_COR2_IXON; } else { if (PortP->Config & RIO_IXON) { rio_dprintk(RIO_DEBUG_PARAM, "Force enable start/stop output control\n"); Cor2 |= RIOC_COR2_IXON; } else rio_dprintk(RIO_DEBUG_PARAM, "IXON has been disabled.\n"); } if (TtyP->termios->c_iflag & IXANY) { if (PortP->Config & RIO_IXANY) { rio_dprintk(RIO_DEBUG_PARAM, "Enable any key to restart output\n"); Cor2 |= RIOC_COR2_IXANY; } else rio_dprintk(RIO_DEBUG_PARAM, "IXANY has been disabled due to sanity reasons.\n"); } if (TtyP->termios->c_iflag & IXOFF) { rio_dprintk(RIO_DEBUG_PARAM, "Enable start/stop input control 2\n"); Cor2 |= RIOC_COR2_IXOFF; } if (TtyP->termios->c_cflag & HUPCL) { rio_dprintk(RIO_DEBUG_PARAM, "Hangup on last close\n"); Cor2 |= RIOC_COR2_HUPCL; } if (C_CRTSCTS(TtyP)) { rio_dprintk(RIO_DEBUG_PARAM, "Rx hardware flow control enabled\n"); Cor2 |= RIOC_COR2_CTSFLOW; Cor2 |= RIOC_COR2_RTSFLOW; } else { rio_dprintk(RIO_DEBUG_PARAM, "Rx hardware flow control disabled\n"); Cor2 &= ~RIOC_COR2_CTSFLOW; Cor2 &= ~RIOC_COR2_RTSFLOW; } if (TtyP->termios->c_cflag & CLOCAL) { rio_dprintk(RIO_DEBUG_PARAM, "Local line\n"); } else { rio_dprintk(RIO_DEBUG_PARAM, "Possible Modem line\n"); } /* ** COR 4 (there is no COR 3) */ if (TtyP->termios->c_iflag & IGNBRK) { rio_dprintk(RIO_DEBUG_PARAM, "Ignore break condition\n"); Cor4 |= RIOC_COR4_IGNBRK; } if (!(TtyP->termios->c_iflag & BRKINT)) { rio_dprintk(RIO_DEBUG_PARAM, "Break generates NULL condition\n"); Cor4 |= RIOC_COR4_NBRKINT; } else { rio_dprintk(RIO_DEBUG_PARAM, "Interrupt on break condition\n"); } if (TtyP->termios->c_iflag & INLCR) { rio_dprintk(RIO_DEBUG_PARAM, "Map newline to carriage return on input\n"); Cor4 |= RIOC_COR4_INLCR; } if (TtyP->termios->c_iflag & IGNCR) { rio_dprintk(RIO_DEBUG_PARAM, "Ignore carriage return on input\n"); Cor4 |= RIOC_COR4_IGNCR; } if (TtyP->termios->c_iflag & ICRNL) { rio_dprintk(RIO_DEBUG_PARAM, "Map carriage return to newline on input\n"); Cor4 |= RIOC_COR4_ICRNL; } if (TtyP->termios->c_iflag & IGNPAR) { rio_dprintk(RIO_DEBUG_PARAM, "Ignore characters with parity errors\n"); Cor4 |= RIOC_COR4_IGNPAR; } if (TtyP->termios->c_iflag & PARMRK) { rio_dprintk(RIO_DEBUG_PARAM, "Mark parity errors\n"); Cor4 |= RIOC_COR4_PARMRK; } /* ** Set the RAISEMOD flag to ensure that the modem lines are raised ** on reception of a config packet. ** The download code handles the zero baud condition. */ Cor4 |= RIOC_COR4_RAISEMOD; /* ** COR 5 */ Cor5 = RIOC_COR5_CMOE; /* ** Set to monitor tbusy/tstop (or not). */ if (PortP->MonitorTstate) Cor5 |= RIOC_COR5_TSTATE_ON; else Cor5 |= RIOC_COR5_TSTATE_OFF; /* ** Could set LNE here if you wanted LNext processing. SVR4 will use it. */ if (TtyP->termios->c_iflag & ISTRIP) { rio_dprintk(RIO_DEBUG_PARAM, "Strip input characters\n"); if (!(PortP->State & RIO_TRIAD_MODE)) { Cor5 |= RIOC_COR5_ISTRIP; } } if (TtyP->termios->c_oflag & ONLCR) { rio_dprintk(RIO_DEBUG_PARAM, "Map newline to carriage-return, newline on output\n"); if (PortP->CookMode == COOK_MEDIUM) Cor5 |= RIOC_COR5_ONLCR; } if (TtyP->termios->c_oflag & OCRNL) { rio_dprintk(RIO_DEBUG_PARAM, "Map carriage return to newline on output\n"); if (PortP->CookMode == COOK_MEDIUM) Cor5 |= RIOC_COR5_OCRNL; } if ((TtyP->termios->c_oflag & TABDLY) == TAB3) { rio_dprintk(RIO_DEBUG_PARAM, "Tab delay 3 set\n"); if (PortP->CookMode == COOK_MEDIUM) Cor5 |= RIOC_COR5_TAB3; } /* ** Flow control bytes. */ TxXon = TtyP->termios->c_cc[VSTART]; TxXoff = TtyP->termios->c_cc[VSTOP]; RxXon = TtyP->termios->c_cc[VSTART]; RxXoff = TtyP->termios->c_cc[VSTOP]; /* ** LNEXT byte */ LNext = 0; /* ** Baud rate bytes */ rio_dprintk(RIO_DEBUG_PARAM, "Mapping of rx/tx baud %x (%x)\n", TtyP->termios->c_cflag, CBAUD); switch (TtyP->termios->c_cflag & CBAUD) { #define e(b) case B ## b : RxBaud = TxBaud = RIO_B ## b ;break e(50); e(75); e(110); e(134); e(150); e(200); e(300); e(600); e(1200); e(1800); e(2400); e(4800); e(9600); e(19200); e(38400); e(57600); e(115200); /* e(230400);e(460800); e(921600); */ } rio_dprintk(RIO_DEBUG_PARAM, "tx baud 0x%x, rx baud 0x%x\n", TxBaud, RxBaud); /* ** Leftovers */ if (TtyP->termios->c_cflag & CREAD) rio_dprintk(RIO_DEBUG_PARAM, "Enable receiver\n"); #ifdef RCV1EN if (TtyP->termios->c_cflag & RCV1EN) rio_dprintk(RIO_DEBUG_PARAM, "RCV1EN (?)\n"); #endif #ifdef XMT1EN if (TtyP->termios->c_cflag & XMT1EN) rio_dprintk(RIO_DEBUG_PARAM, "XMT1EN (?)\n"); #endif if (TtyP->termios->c_lflag & ISIG) rio_dprintk(RIO_DEBUG_PARAM, "Input character signal generating enabled\n"); if (TtyP->termios->c_lflag & ICANON) rio_dprintk(RIO_DEBUG_PARAM, "Canonical input: erase and kill enabled\n"); if (TtyP->termios->c_lflag & XCASE) rio_dprintk(RIO_DEBUG_PARAM, "Canonical upper/lower presentation\n"); if (TtyP->termios->c_lflag & ECHO) rio_dprintk(RIO_DEBUG_PARAM, "Enable input echo\n"); if (TtyP->termios->c_lflag & ECHOE) rio_dprintk(RIO_DEBUG_PARAM, "Enable echo erase\n"); if (TtyP->termios->c_lflag & ECHOK) rio_dprintk(RIO_DEBUG_PARAM, "Enable echo kill\n"); if (TtyP->termios->c_lflag & ECHONL) rio_dprintk(RIO_DEBUG_PARAM, "Enable echo newline\n"); if (TtyP->termios->c_lflag & NOFLSH) rio_dprintk(RIO_DEBUG_PARAM, "Disable flush after interrupt or quit\n"); #ifdef TOSTOP if (TtyP->termios->c_lflag & TOSTOP) rio_dprintk(RIO_DEBUG_PARAM, "Send SIGTTOU for background output\n"); #endif #ifdef XCLUDE if (TtyP->termios->c_lflag & XCLUDE) rio_dprintk(RIO_DEBUG_PARAM, "Exclusive use of this line\n"); #endif if (TtyP->termios->c_iflag & IUCLC) rio_dprintk(RIO_DEBUG_PARAM, "Map uppercase to lowercase on input\n"); if (TtyP->termios->c_oflag & OPOST) rio_dprintk(RIO_DEBUG_PARAM, "Enable output post-processing\n"); if (TtyP->termios->c_oflag & OLCUC) rio_dprintk(RIO_DEBUG_PARAM, "Map lowercase to uppercase on output\n"); if (TtyP->termios->c_oflag & ONOCR) rio_dprintk(RIO_DEBUG_PARAM, "No carriage return output at column 0\n"); if (TtyP->termios->c_oflag & ONLRET) rio_dprintk(RIO_DEBUG_PARAM, "Newline performs carriage return function\n"); if (TtyP->termios->c_oflag & OFILL) rio_dprintk(RIO_DEBUG_PARAM, "Use fill characters for delay\n"); if (TtyP->termios->c_oflag & OFDEL) rio_dprintk(RIO_DEBUG_PARAM, "Fill character is DEL\n"); if (TtyP->termios->c_oflag & NLDLY) rio_dprintk(RIO_DEBUG_PARAM, "Newline delay set\n"); if (TtyP->termios->c_oflag & CRDLY) rio_dprintk(RIO_DEBUG_PARAM, "Carriage return delay set\n"); if (TtyP->termios->c_oflag & TABDLY) rio_dprintk(RIO_DEBUG_PARAM, "Tab delay set\n"); /* ** These things are kind of useful in a later life! */ PortP->Cor2Copy = Cor2; if (PortP->State & RIO_DELETED) { rio_spin_unlock_irqrestore(&PortP->portSem, flags); func_exit(); return RIO_FAIL; } /* ** Actually write the info into the packet to be sent */ writeb(cmd, &phb_param_ptr->Cmd); writeb(Cor1, &phb_param_ptr->Cor1); writeb(Cor2, &phb_param_ptr->Cor2); writeb(Cor4, &phb_param_ptr->Cor4); writeb(Cor5, &phb_param_ptr->Cor5); writeb(TxXon, &phb_param_ptr->TxXon); writeb(RxXon, &phb_param_ptr->RxXon); writeb(TxXoff, &phb_param_ptr->TxXoff); writeb(RxXoff, &phb_param_ptr->RxXoff); writeb(LNext, &phb_param_ptr->LNext); writeb(TxBaud, &phb_param_ptr->TxBaud); writeb(RxBaud, &phb_param_ptr->RxBaud); /* ** Set the length/command field */ writeb(12 | PKT_CMD_BIT, &PacketP->len); /* ** The packet is formed - now, whack it off ** to its final destination: */ add_transmit(PortP); /* ** Count characters transmitted for port statistics reporting */ if (PortP->statsGather) PortP->txchars += 12; rio_spin_unlock_irqrestore(&PortP->portSem, flags); rio_dprintk(RIO_DEBUG_PARAM, "add_transmit returned.\n"); /* ** job done. */ func_exit(); return 0; }
void RIOFixPhbs(struct rio_info *p, struct Host *HostP, unsigned int unit) { unsigned short link, port; struct Port *PortP; unsigned long flags; int PortN = HostP->Mapping[unit].SysPort; rio_dprintk(RIO_DEBUG_ROUTE, "RIOFixPhbs unit %d sysport %d\n", unit, PortN); if (PortN != -1) { unsigned short dest_unit = HostP->Mapping[unit].ID2; /* ** Get the link number used for the 1st 8 phbs on this unit. */ PortP = p->RIOPortp[HostP->Mapping[dest_unit - 1].SysPort]; link = readw(&PortP->PhbP->link); for (port = 0; port < PORTS_PER_RTA; port++, PortN++) { unsigned short dest_port = port + 8; u16 __iomem *TxPktP; struct PKT __iomem *Pkt; PortP = p->RIOPortp[PortN]; rio_spin_lock_irqsave(&PortP->portSem, flags); /* ** If RTA is not powered on, the tx packets will be ** unset, so go no further. */ if (!PortP->TxStart) { rio_dprintk(RIO_DEBUG_ROUTE, "Tx pkts not set up yet\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); break; } /* ** For the second slot of a 16 port RTA, the driver needs to ** sort out the phb to port mappings. The dest_unit for this ** group of 8 phbs is set to the dest_unit of the accompanying ** 8 port block. The dest_port of the second unit is set to ** be in the range 8-15 (i.e. 8 is added). Thus, for a 16 port ** RTA with IDs 5 and 6, traffic bound for port 6 of unit 6 ** (being the second map ID) will be sent to dest_unit 5, port ** 14. When this RTA is deleted, dest_unit for ID 6 will be ** restored, and the dest_port will be reduced by 8. ** Transmit packets also have a destination field which needs ** adjusting in the same manner. ** Note that the unit/port bytes in 'dest' are swapped. ** We also need to adjust the phb and rup link numbers for the ** second block of 8 ttys. */ for (TxPktP = PortP->TxStart; TxPktP <= PortP->TxEnd; TxPktP++) { /* ** *TxPktP is the pointer to the transmit packet on the host ** card. This needs to be translated into a 32 bit pointer ** so it can be accessed from the driver. */ Pkt = (struct PKT __iomem *) RIO_PTR(HostP->Caddr, readw(TxPktP)); /* ** If the packet is used, reset it. */ Pkt = (struct PKT __iomem *) ((unsigned long) Pkt & ~PKT_IN_USE); writeb(dest_unit, &Pkt->dest_unit); writeb(dest_port, &Pkt->dest_port); } rio_dprintk(RIO_DEBUG_ROUTE, "phb dest: Old %x:%x New %x:%x\n", readw(&PortP->PhbP->destination) & 0xff, (readw(&PortP->PhbP->destination) >> 8) & 0xff, dest_unit, dest_port); writew(dest_unit + (dest_port << 8), &PortP->PhbP->destination); writew(link, &PortP->PhbP->link); rio_spin_unlock_irqrestore(&PortP->portSem, flags); } /* ** Now make sure the range of ports to be serviced includes ** the 2nd 8 on this 16 port RTA. */ if (link > 3) return; if (((unit * 8) + 7) > readw(&HostP->LinkStrP[link].last_port)) { rio_dprintk(RIO_DEBUG_ROUTE, "last port on host link %d: %d\n", link, (unit * 8) + 7); writew((unit * 8) + 7, &HostP->LinkStrP[link].last_port); } }
/* Enable and start the transmission of packets */ void RIOTxEnable(char *en) { struct Port *PortP; struct rio_info *p; struct tty_struct *tty; int c; struct PKT __iomem *PacketP; unsigned long flags; PortP = (struct Port *) en; p = (struct rio_info *) PortP->p; tty = PortP->gs.tty; rio_dprintk(RIO_DEBUG_INTR, "tx port %d: %d chars queued.\n", PortP->PortNum, PortP->gs.xmit_cnt); if (!PortP->gs.xmit_cnt) return; /* This routine is an order of magnitude simpler than the specialix version. One of the disadvantages is that this version will send an incomplete packet (usually 64 bytes instead of 72) once for every 4k worth of data. Let's just say that this won't influence performance significantly..... */ rio_spin_lock_irqsave(&PortP->portSem, flags); while (can_add_transmit(&PacketP, PortP)) { c = PortP->gs.xmit_cnt; if (c > PKT_MAX_DATA_LEN) c = PKT_MAX_DATA_LEN; /* Don't copy past the end of the source buffer */ if (c > SERIAL_XMIT_SIZE - PortP->gs.xmit_tail) c = SERIAL_XMIT_SIZE - PortP->gs.xmit_tail; { int t; t = (c > 10) ? 10 : c; rio_dprintk(RIO_DEBUG_INTR, "rio: tx port %d: copying %d chars: %s - %s\n", PortP->PortNum, c, firstchars(PortP->gs.xmit_buf + PortP->gs.xmit_tail, t), firstchars(PortP->gs.xmit_buf + PortP->gs.xmit_tail + c - t, t)); } /* If for one reason or another, we can't copy more data, we're done! */ if (c == 0) break; rio_memcpy_toio(PortP->HostP->Caddr, PacketP->data, PortP->gs.xmit_buf + PortP->gs.xmit_tail, c); /* udelay (1); */ writeb(c, &(PacketP->len)); if (!(PortP->State & RIO_DELETED)) { add_transmit(PortP); /* ** Count chars tx'd for port statistics reporting */ if (PortP->statsGather) PortP->txchars += c; } PortP->gs.xmit_tail = (PortP->gs.xmit_tail + c) & (SERIAL_XMIT_SIZE - 1); PortP->gs.xmit_cnt -= c; } rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (PortP->gs.xmit_cnt <= (PortP->gs.wakeup_chars + 2 * PKT_MAX_DATA_LEN)) { rio_dprintk(RIO_DEBUG_INTR, "Waking up.... ldisc:%d (%d/%d)....", (int) (PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)), PortP->gs.wakeup_chars, PortP->gs.xmit_cnt); if ((PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && PortP->gs.tty->ldisc.write_wakeup) (PortP->gs.tty->ldisc.write_wakeup) (PortP->gs.tty); rio_dprintk(RIO_DEBUG_INTR, "(%d/%d)\n", PortP->gs.wakeup_chars, PortP->gs.xmit_cnt); wake_up_interruptible(&PortP->gs.tty->write_wait); } }
int RIORouteRup(struct rio_info *p, unsigned int Rup, struct Host *HostP, struct PKT __iomem * PacketP) { struct PktCmd __iomem *PktCmdP = (struct PktCmd __iomem *) PacketP->data; struct PktCmd_M *PktReplyP; struct CmdBlk *CmdBlkP; struct Port *PortP; struct Map *MapP; struct Top *TopP; int ThisLink, ThisLinkMin, ThisLinkMax; int port; int Mod, Mod1, Mod2; unsigned short RtaType; unsigned int RtaUniq; unsigned int ThisUnit, ThisUnit2; unsigned int OldUnit, NewUnit, OldLink, NewLink; char *MyType, *MyName; int Lies; unsigned long flags; if (readb(&PktCmdP->Command) == ROUTE_TOPOLOGY) { MapP = HostP->Mapping; if (Rup >= (unsigned short) MAX_RUP) { ThisUnit = HOST_ID; TopP = HostP->Topology; MyType = "Host"; MyName = HostP->Name; ThisLinkMin = ThisLinkMax = Rup - MAX_RUP; } else { ThisUnit = Rup + 1; TopP = HostP->Mapping[Rup].Topology; MyType = "RTA"; MyName = HostP->Mapping[Rup].Name; ThisLinkMin = 0; ThisLinkMax = LINKS_PER_UNIT - 1; } Lies = 0; for (ThisLink = ThisLinkMin + 1; ThisLink <= ThisLinkMax; ThisLink++) { if (readb(&PktCmdP->RouteTopology[ThisLink].Unit) > (unsigned short) MAX_RUP) continue; for (NewLink = ThisLinkMin; NewLink < ThisLink; NewLink++) { if ((readb(&PktCmdP->RouteTopology[ThisLink].Unit) == readb(&PktCmdP->RouteTopology[NewLink].Unit)) && (readb(&PktCmdP->RouteTopology[ThisLink].Link) == readb(&PktCmdP->RouteTopology[NewLink].Link))) { Lies++; } } } if (Lies) { rio_dprintk(RIO_DEBUG_ROUTE, "LIES! DAMN LIES! %d LIES!\n", Lies); rio_dprintk(RIO_DEBUG_ROUTE, "%d:%c %d:%c %d:%c %d:%c\n", readb(&PktCmdP->RouteTopology[0].Unit), 'A' + readb(&PktCmdP->RouteTopology[0].Link), readb(&PktCmdP->RouteTopology[1].Unit), 'A' + readb(&PktCmdP->RouteTopology[1].Link), readb(&PktCmdP->RouteTopology[2].Unit), 'A' + readb(&PktCmdP->RouteTopology[2].Link), readb(&PktCmdP->RouteTopology[3].Unit), 'A' + readb(&PktCmdP->RouteTopology[3].Link)); return 1; } for (ThisLink = ThisLinkMin; ThisLink <= ThisLinkMax; ThisLink++) { OldUnit = TopP[ThisLink].Unit; OldLink = TopP[ThisLink].Link; NewUnit = readb(&PktCmdP->RouteTopology[ThisLink].Unit); NewLink = readb(&PktCmdP->RouteTopology[ThisLink].Link); if (OldUnit != NewUnit || OldLink != NewLink) { if (NewUnit > MAX_RUP && NewUnit != ROUTE_DISCONNECT && NewUnit != ROUTE_NO_ID && NewUnit != ROUTE_INTERCONNECT) { rio_dprintk(RIO_DEBUG_ROUTE, "I have a link from %s %s to unit %d:%d - I don't like it.\n", MyType, MyName, NewUnit, NewLink); } else { TopP[ThisLink].Unit = NewUnit; TopP[ThisLink].Link = NewLink; RIOSetChange(p); if (OldUnit <= MAX_RUP) { if (!p->RIONoMessage) RIOConCon(p, HostP, ThisUnit, ThisLink, OldUnit, OldLink, DISCONNECT); } if ((NewUnit <= MAX_RUP) && !p->RIONoMessage) RIOConCon(p, HostP, ThisUnit, ThisLink, NewUnit, NewLink, CONNECT); if (NewUnit == ROUTE_NO_ID) rio_dprintk(RIO_DEBUG_ROUTE, "%s %s (%c) is connected to an unconfigured unit.\n", MyType, MyName, 'A' + ThisLink); if (NewUnit == ROUTE_INTERCONNECT) { if (!p->RIONoMessage) printk(KERN_DEBUG "rio: %s '%s' (%c) is connected to another network.\n", MyType, MyName, 'A' + ThisLink); } if (OldUnit == HOST_ID) { if (HostP->Topology[OldLink].Unit == ThisUnit && HostP->Topology[OldLink].Link == ThisLink) { rio_dprintk(RIO_DEBUG_ROUTE, "SETTING HOST (%c) TO DISCONNECTED!\n", OldLink + 'A'); HostP->Topology[OldLink].Unit = ROUTE_DISCONNECT; HostP->Topology[OldLink].Link = NO_LINK; } else { rio_dprintk(RIO_DEBUG_ROUTE, "HOST(%c) WAS NOT CONNECTED TO %s (%c)!\n", OldLink + 'A', HostP->Mapping[ThisUnit - 1].Name, ThisLink + 'A'); } } else if (OldUnit <= MAX_RUP) { if (HostP->Mapping[OldUnit - 1].Topology[OldLink].Unit == ThisUnit && HostP->Mapping[OldUnit - 1].Topology[OldLink].Link == ThisLink) { rio_dprintk(RIO_DEBUG_ROUTE, "SETTING RTA %s (%c) TO DISCONNECTED!\n", HostP->Mapping[OldUnit - 1].Name, OldLink + 'A'); HostP->Mapping[OldUnit - 1].Topology[OldLink].Unit = ROUTE_DISCONNECT; HostP->Mapping[OldUnit - 1].Topology[OldLink].Link = NO_LINK; } else { rio_dprintk(RIO_DEBUG_ROUTE, "RTA %s (%c) WAS NOT CONNECTED TO %s (%c)\n", HostP->Mapping[OldUnit - 1].Name, OldLink + 'A', HostP->Mapping[ThisUnit - 1].Name, ThisLink + 'A'); } } if (NewUnit == HOST_ID) { rio_dprintk(RIO_DEBUG_ROUTE, "MARKING HOST (%c) CONNECTED TO %s (%c)\n", NewLink + 'A', MyName, ThisLink + 'A'); HostP->Topology[NewLink].Unit = ThisUnit; HostP->Topology[NewLink].Link = ThisLink; } else if (NewUnit <= MAX_RUP) { rio_dprintk(RIO_DEBUG_ROUTE, "MARKING RTA %s (%c) CONNECTED TO %s (%c)\n", HostP->Mapping[NewUnit - 1].Name, NewLink + 'A', MyName, ThisLink + 'A'); HostP->Mapping[NewUnit - 1].Topology[NewLink].Unit = ThisUnit; HostP->Mapping[NewUnit - 1].Topology[NewLink].Link = ThisLink; } } RIOSetChange(p); RIOCheckIsolated(p, HostP, OldUnit); } } return 1; } if (readb(&PktCmdP->Command) != ROUTE_REQUEST) { rio_dprintk(RIO_DEBUG_ROUTE, "Unknown command %d received on rup %d host %p ROUTE_RUP\n", readb(&PktCmdP->Command), Rup, HostP); return 1; } RtaUniq = (readb(&PktCmdP->UniqNum[0])) + (readb(&PktCmdP->UniqNum[1]) << 8) + (readb(&PktCmdP->UniqNum[2]) << 16) + (readb(&PktCmdP->UniqNum[3]) << 24); RtaType = GetUnitType(RtaUniq); rio_dprintk(RIO_DEBUG_ROUTE, "Received a request for an ID for serial number %x\n", RtaUniq); Mod = readb(&PktCmdP->ModuleTypes); Mod1 = LONYBLE(Mod); if (RtaType == TYPE_RTA16) { Mod2 = Mod1; rio_dprintk(RIO_DEBUG_ROUTE, "Backplane type is %s (all ports)\n", p->RIOModuleTypes[Mod1].Name); } else { Mod2 = HINYBLE(Mod); rio_dprintk(RIO_DEBUG_ROUTE, "Module types are %s (ports 0-3) and %s (ports 4-7)\n", p->RIOModuleTypes[Mod1].Name, p->RIOModuleTypes[Mod2].Name); } if (!(CmdBlkP = RIOGetCmdBlk())) { rio_dprintk(RIO_DEBUG_ROUTE, "No command blocks to route RTA! come back later.\n"); return 0; } CmdBlkP->Packet.dest_unit = Rup; CmdBlkP->Packet.dest_port = ROUTE_RUP; CmdBlkP->Packet.src_unit = HOST_ID; CmdBlkP->Packet.src_port = ROUTE_RUP; CmdBlkP->Packet.len = PKT_CMD_BIT | 1; CmdBlkP->PreFuncP = CmdBlkP->PostFuncP = NULL; PktReplyP = (struct PktCmd_M *) CmdBlkP->Packet.data; if (!RIOBootOk(p, HostP, RtaUniq)) { rio_dprintk(RIO_DEBUG_ROUTE, "RTA %x tried to get an ID, but does not belong - FOAD it!\n", RtaUniq); PktReplyP->Command = ROUTE_FOAD; memcpy(PktReplyP->CommandText, "RT_FOAD", 7); RIOQueueCmdBlk(HostP, Rup, CmdBlkP); return 1; } for (ThisUnit = 0; ThisUnit < MAX_RUP; ThisUnit++) { rio_dprintk(RIO_DEBUG_ROUTE, "Entry %d Flags=%s %s UniqueNum=0x%x\n", ThisUnit, HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE ? "Slot-In-Use" : "Not In Use", HostP->Mapping[ThisUnit].Flags & SLOT_TENTATIVE ? "Slot-Tentative" : "Not Tentative", HostP->Mapping[ThisUnit].RtaUniqueNum); if ((HostP->Mapping[ThisUnit].Flags & (SLOT_IN_USE | SLOT_TENTATIVE)) && (HostP->Mapping[ThisUnit].RtaUniqueNum == RtaUniq)) { if (RtaType == TYPE_RTA16) { ThisUnit2 = HostP->Mapping[ThisUnit].ID2 - 1; rio_dprintk(RIO_DEBUG_ROUTE, "Found unit 0x%x at slots %d+%d\n", RtaUniq, ThisUnit, ThisUnit2); } else rio_dprintk(RIO_DEBUG_ROUTE, "Found unit 0x%x at slot %d\n", RtaUniq, ThisUnit); if ((HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE) && !(HostP->Mapping[ThisUnit].Flags & RTA_BOOTED)) { if (!(HostP->Mapping[ThisUnit].Flags & MSG_DONE)) { if (!p->RIONoMessage) printk(KERN_DEBUG "rio: RTA '%s' is being updated.\n", HostP->Mapping[ThisUnit].Name); HostP->Mapping[ThisUnit].Flags |= MSG_DONE; } PktReplyP->Command = ROUTE_FOAD; memcpy(PktReplyP->CommandText, "RT_FOAD", 7); RIOQueueCmdBlk(HostP, Rup, CmdBlkP); return 1; } PktReplyP->Command = ROUTE_ALLOCATE; PktReplyP->IDNum = ThisUnit + 1; if (RtaType == TYPE_RTA16) { if (HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE) RIOFixPhbs(p, HostP, ThisUnit2); PktReplyP->IDNum2 = ThisUnit2 + 1; rio_dprintk(RIO_DEBUG_ROUTE, "RTA '%s' has been allocated IDs %d+%d\n", HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum, PktReplyP->IDNum2); } else { PktReplyP->IDNum2 = ROUTE_NO_ID; rio_dprintk(RIO_DEBUG_ROUTE, "RTA '%s' has been allocated ID %d\n", HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum); } memcpy(PktReplyP->CommandText, "RT_ALLOCAT", 10); RIOQueueCmdBlk(HostP, Rup, CmdBlkP); if ((HostP->Mapping[ThisUnit].Flags & RTA_NEWBOOT) && (HostP->Mapping[ThisUnit].SysPort != NO_PORT)) { for (port = 0; port < PORTS_PER_RTA; port++) { PortP = p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort]; if (PortP->State & (RIO_MOPEN | RIO_LOPEN)) { rio_dprintk(RIO_DEBUG_ROUTE, "Re-opened this port\n"); rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->MagicFlags |= MAGIC_REBOOT; rio_spin_unlock_irqrestore(&PortP->portSem, flags); } } if (RtaType == TYPE_RTA16) { for (port = 0; port < PORTS_PER_RTA; port++) { PortP = p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort]; if (PortP->State & (RIO_MOPEN | RIO_LOPEN)) { rio_dprintk(RIO_DEBUG_ROUTE, "Re-opened this port\n"); rio_spin_lock_irqsave(&PortP->portSem, flags); PortP->MagicFlags |= MAGIC_REBOOT; rio_spin_unlock_irqrestore(&PortP->portSem, flags); } } } } HostP->UnixRups[ThisUnit].ModTypes = Mod; if (RtaType == TYPE_RTA16) HostP->UnixRups[ThisUnit2].ModTypes = Mod; if (HostP->Mapping[ThisUnit].SysPort != NO_PORT) { for (port = 0; port < PORTS_PER_MODULE; port++) { p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK; p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port]; p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK; p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port]; } if (RtaType == TYPE_RTA16) { for (port = 0; port < PORTS_PER_MODULE; port++) { p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK; p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port]; p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK; p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port]; } } } return 1; } } for (ThisUnit = 0; ThisUnit < HostP->NumExtraBooted; ThisUnit++) if (HostP->ExtraUnits[ThisUnit] == RtaUniq) break; if (ThisUnit == HostP->NumExtraBooted && ThisUnit != MAX_EXTRA_UNITS) { static int UnknownMesgDone = 0; if (!UnknownMesgDone) { if (!p->RIONoMessage) printk(KERN_DEBUG "rio: One or more unknown RTAs are being updated.\n"); UnknownMesgDone = 1; } PktReplyP->Command = ROUTE_FOAD; memcpy(PktReplyP->CommandText, "RT_FOAD", 7); } else { if (RtaType == TYPE_RTA16) { if (RIOFindFreeID(p, HostP, &ThisUnit, &ThisUnit2) == 0) { RIODefaultName(p, HostP, ThisUnit); rio_fill_host_slot(ThisUnit, ThisUnit2, RtaUniq, HostP); } } else { if (RIOFindFreeID(p, HostP, &ThisUnit, NULL) == 0) { RIODefaultName(p, HostP, ThisUnit); rio_fill_host_slot(ThisUnit, 0, RtaUniq, HostP); } } PktReplyP->Command = ROUTE_USED; memcpy(PktReplyP->CommandText, "RT_USED", 7); } RIOQueueCmdBlk(HostP, Rup, CmdBlkP); return 1; }
/* ** Incoming command on the COMMAND_RUP to be processed. */ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struct PKT __iomem *PacketP) { struct PktCmd __iomem *PktCmdP = (struct PktCmd __iomem *)PacketP->data; struct Port *PortP; struct UnixRup *UnixRupP; unsigned short SysPort; unsigned short ReportedModemStatus; unsigned short rup; unsigned short subCommand; unsigned long flags; func_enter(); /* ** 16 port RTA note: ** Command rup packets coming from the RTA will have pkt->data[1] (which ** translates to PktCmdP->PhbNum) set to the host port number for the ** particular unit. To access the correct BaseSysPort for a 16 port RTA, ** we can use PhbNum to get the rup number for the appropriate 8 port ** block (for the first block, this should be equal to 'Rup'). */ rup = readb(&PktCmdP->PhbNum) / (unsigned short) PORTS_PER_RTA; UnixRupP = &HostP->UnixRups[rup]; SysPort = UnixRupP->BaseSysPort + (readb(&PktCmdP->PhbNum) % (unsigned short) PORTS_PER_RTA); rio_dprintk(RIO_DEBUG_CMD, "Command on rup %d, port %d\n", rup, SysPort); if (UnixRupP->BaseSysPort == NO_PORT) { rio_dprintk(RIO_DEBUG_CMD, "OBSCURE ERROR!\n"); rio_dprintk(RIO_DEBUG_CMD, "Diagnostics follow. Please WRITE THESE DOWN and report them to Specialix Technical Support\n"); rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Host number %Zd, name ``%s''\n", HostP - p->RIOHosts, HostP->Name); rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Rup number 0x%x\n", rup); if (Rup < (unsigned short) MAX_RUP) { rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for RTA ``%s''\n", HostP->Mapping[Rup].Name); } else rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", ('A' + Rup - MAX_RUP), HostP->Name); rio_dprintk(RIO_DEBUG_CMD, "PACKET information: Destination 0x%x:0x%x\n", readb(&PacketP->dest_unit), readb(&PacketP->dest_port)); rio_dprintk(RIO_DEBUG_CMD, "PACKET information: Source 0x%x:0x%x\n", readb(&PacketP->src_unit), readb(&PacketP->src_port)); rio_dprintk(RIO_DEBUG_CMD, "PACKET information: Length 0x%x (%d)\n", readb(&PacketP->len), readb(&PacketP->len)); rio_dprintk(RIO_DEBUG_CMD, "PACKET information: Control 0x%x (%d)\n", readb(&PacketP->control), readb(&PacketP->control)); rio_dprintk(RIO_DEBUG_CMD, "PACKET information: Check 0x%x (%d)\n", readw(&PacketP->csum), readw(&PacketP->csum)); rio_dprintk(RIO_DEBUG_CMD, "COMMAND information: Host Port Number 0x%x, " "Command Code 0x%x\n", readb(&PktCmdP->PhbNum), readb(&PktCmdP->Command)); return 1; } PortP = p->RIOPortp[SysPort]; rio_spin_lock_irqsave(&PortP->portSem, flags); switch (readb(&PktCmdP->Command)) { case BREAK_RECEIVED: rio_dprintk(RIO_DEBUG_CMD, "Received a break!\n"); /* If the current line disc. is not multi-threading and the current processor is not the default, reset rup_intr and return 0 to ensure that the command packet is not freed. */ /* Call tmgr HANGUP HERE */ /* Fix this later when every thing works !!!! RAMRAJ */ gs_got_break(&PortP->gs); break; case COMPLETE: rio_dprintk(RIO_DEBUG_CMD, "Command complete on phb %d host %Zd\n", readb(&PktCmdP->PhbNum), HostP - p->RIOHosts); subCommand = 1; switch (readb(&PktCmdP->SubCommand)) { case MEMDUMP: rio_dprintk(RIO_DEBUG_CMD, "Memory dump cmd (0x%x) from addr 0x%x\n", readb(&PktCmdP->SubCommand), readw(&PktCmdP->SubAddr)); break; case READ_REGISTER: rio_dprintk(RIO_DEBUG_CMD, "Read register (0x%x)\n", readw(&PktCmdP->SubAddr)); p->CdRegister = (readb(&PktCmdP->ModemStatus) & MSVR1_HOST); break; default: subCommand = 0; break; } if (subCommand) break; rio_dprintk(RIO_DEBUG_CMD, "New status is 0x%x was 0x%x\n", readb(&PktCmdP->PortStatus), PortP->PortState); if (PortP->PortState != readb(&PktCmdP->PortStatus)) { rio_dprintk(RIO_DEBUG_CMD, "Mark status & wakeup\n"); PortP->PortState = readb(&PktCmdP->PortStatus); /* What should we do here ... wakeup( &PortP->PortState ); */ } else rio_dprintk(RIO_DEBUG_CMD, "No change\n"); /* FALLTHROUGH */ case MODEM_STATUS: /* ** Knock out the tbusy and tstop bits, as these are not relevant ** to the check for modem status change (they're just there because ** it's a convenient place to put them!). */ ReportedModemStatus = readb(&PktCmdP->ModemStatus); if ((PortP->ModemState & MSVR1_HOST) == (ReportedModemStatus & MSVR1_HOST)) { rio_dprintk(RIO_DEBUG_CMD, "Modem status unchanged 0x%x\n", PortP->ModemState); /* ** Update ModemState just in case tbusy or tstop states have ** changed. */ PortP->ModemState = ReportedModemStatus; } else { rio_dprintk(RIO_DEBUG_CMD, "Modem status change from 0x%x to 0x%x\n", PortP->ModemState, ReportedModemStatus); PortP->ModemState = ReportedModemStatus; #ifdef MODEM_SUPPORT if (PortP->Mapped) { /***********************************************************\ ************************************************************* *** *** *** M O D E M S T A T E C H A N G E *** *** *** ************************************************************* \***********************************************************/ /* ** If the device is a modem, then check the modem ** carrier. */ if (PortP->gs.tty == NULL) break; if (PortP->gs.tty->termios == NULL) break; if (!(PortP->gs.tty->termios->c_cflag & CLOCAL) && ((PortP->State & (RIO_MOPEN | RIO_WOPEN)))) { rio_dprintk(RIO_DEBUG_CMD, "Is there a Carrier?\n"); /* ** Is there a carrier? */ if (PortP->ModemState & MSVR1_CD) { /* ** Has carrier just appeared? */ if (!(PortP->State & RIO_CARR_ON)) { rio_dprintk(RIO_DEBUG_CMD, "Carrier just came up.\n"); PortP->State |= RIO_CARR_ON; /* ** wakeup anyone in WOPEN */ if (PortP->State & (PORT_ISOPEN | RIO_WOPEN)) wake_up_interruptible(&PortP->gs.open_wait); } } else { /* ** Has carrier just dropped? */ if (PortP->State & RIO_CARR_ON) { if (PortP->State & (PORT_ISOPEN | RIO_WOPEN | RIO_MOPEN)) tty_hangup(PortP->gs.tty); PortP->State &= ~RIO_CARR_ON; rio_dprintk(RIO_DEBUG_CMD, "Carrirer just went down\n"); } } } } #endif } break; default: rio_dprintk(RIO_DEBUG_CMD, "Unknown command %d on CMD_RUP of host %Zd\n", readb(&PktCmdP->Command), HostP - p->RIOHosts); break; } rio_spin_unlock_irqrestore(&PortP->portSem, flags); func_exit(); return 1; }
/* ** Here we go - if there is an empty rup, fill it! ** must be called at splrio() or higher. */ void RIOPollHostCommands(struct rio_info *p, struct Host *HostP) { struct CmdBlk *CmdBlkP; struct UnixRup *UnixRupP; struct PKT __iomem *PacketP; unsigned short 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 (readw(&UnixRupP->RupP->rxcontrol) != RX_RUP_INACTIVE) { int FreeMe; PacketP = (struct PKT __iomem *) RIO_PTR(HostP->Caddr, readw(&UnixRupP->RupP->rxpkt)); switch (readb(&PacketP->dest_port)) { case BOOT_RUP: rio_dprintk(RIO_DEBUG_CMD, "Incoming Boot %s packet '%x'\n", readb(&PacketP->len) & 0x80 ? "Command" : "Data", readb(&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 (readb(&PacketP->data[5]) == MEMDUMP) { rio_dprintk(RIO_DEBUG_CMD, "Memdump from 0x%x complete\n", readw(&(PacketP->data[6]))); rio_memcpy_fromio(p->RIOMemDump, &(PacketP->data[8]), 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", readb(&PacketP->dest_port)); FreeMe = 1; break; } if (FreeMe) { rio_dprintk(RIO_DEBUG_CMD, "Free processed incoming command packet\n"); put_free_end(HostP, PacketP); writew(RX_RUP_INACTIVE, &UnixRupP->RupP->rxcontrol); if (readw(&UnixRupP->RupP->handshake) == PHB_HANDSHAKE_SET) { rio_dprintk(RIO_DEBUG_CMD, "Handshake rup %d\n", Rup); writew(PHB_HANDSHAKE_SET | PHB_HANDSHAKE_RESET, &UnixRupP->RupP->handshake); } } } /* ** IF a command was running on the port, ** and it has completed, then tidy it up. */ if ((CmdBlkP = UnixRupP->CmdPendingP) && /* ASSIGN! */ (readw(&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 %p completed\n", 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) && (readw(&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! */ if (!(CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP) (CmdBlkP->PreArg, CmdBlkP) : 1)) { rio_dprintk(RIO_DEBUG_CMD, "Not ready to start command %p\n", CmdBlkP); } else { rio_dprintk(RIO_DEBUG_CMD, "Start new command %p Cmd byte is 0x%x\n", CmdBlkP, CmdBlkP->Packet.data[0]); /* ** Whammy! blat that pack! */ HostP->Copy(&CmdBlkP->Packet, RIO_PTR(HostP->Caddr, readw(&UnixRupP->RupP->txpkt)), sizeof(struct 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 */ writew(TX_PACKET_READY, &UnixRupP->RupP->txcontrol); /* ** the command block will be freed ** when the command has been processed. */ } } spin_unlock_irqrestore(&UnixRupP->RupLock, flags); } while (Rup); }
/* ** attach a command block to the list of commands to be performed for ** a given rup. */ int RIOQueueCmdBlk(struct Host *HostP, uint Rup, struct CmdBlk *CmdBlkP) { struct CmdBlk **Base; struct UnixRup *UnixRupP; unsigned long flags; if (Rup >= (unsigned short) (MAX_RUP + LINKS_PER_UNIT)) { rio_dprintk(RIO_DEBUG_CMD, "Illegal rup number %d in RIOQueueCmdBlk\n", Rup); RIOFreeCmdBlk(CmdBlkP); return RIO_FAIL; } UnixRupP = &HostP->UnixRups[Rup]; rio_spin_lock_irqsave(&UnixRupP->RupLock, flags); /* ** If the RUP is currently inactive, then put the request ** straight on the RUP.... */ if ((UnixRupP->CmdsWaitingP == NULL) && (UnixRupP->CmdPendingP == NULL) && (readw(&UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE) && (CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP) (CmdBlkP->PreArg, CmdBlkP) : 1)) { rio_dprintk(RIO_DEBUG_CMD, "RUP inactive-placing command straight on. Cmd byte is 0x%x\n", CmdBlkP->Packet.data[0]); /* ** Whammy! blat that pack! */ HostP->Copy(&CmdBlkP->Packet, RIO_PTR(HostP->Caddr, readw(&UnixRupP->RupP->txpkt)), sizeof(struct PKT)); /* ** place command packet on the pending position. */ UnixRupP->CmdPendingP = CmdBlkP; /* ** set the command register */ writew(TX_PACKET_READY, &UnixRupP->RupP->txcontrol); rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); return 0; } rio_dprintk(RIO_DEBUG_CMD, "RUP active - en-queing\n"); if (UnixRupP->CmdsWaitingP != NULL) rio_dprintk(RIO_DEBUG_CMD, "Rup active - command waiting\n"); if (UnixRupP->CmdPendingP != NULL) rio_dprintk(RIO_DEBUG_CMD, "Rup active - command pending\n"); if (readw(&UnixRupP->RupP->txcontrol) != TX_RUP_INACTIVE) rio_dprintk(RIO_DEBUG_CMD, "Rup active - command rup not ready\n"); Base = &UnixRupP->CmdsWaitingP; rio_dprintk(RIO_DEBUG_CMD, "First try to queue cmdblk %p at %p\n", CmdBlkP, Base); while (*Base) { rio_dprintk(RIO_DEBUG_CMD, "Command cmdblk %p here\n", *Base); Base = &((*Base)->NextP); rio_dprintk(RIO_DEBUG_CMD, "Now try to queue cmd cmdblk %p at %p\n", CmdBlkP, Base); } rio_dprintk(RIO_DEBUG_CMD, "Will queue cmdblk %p at %p\n", CmdBlkP, Base); *Base = CmdBlkP; CmdBlkP->NextP = NULL; rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); return 0; }