📄 np.c
字号:
case NPPANIC: printf("\nPanic from NP100 unit %d!\n",mp->unit); mp->flags &= ~AVAILABLE; mp->flags |= PANIC1; /* Clear device request word */ mp->shmemp->statblock.sb_drw = 0; panicmap = uballoc(mp->devp->ui_ubanum,(caddr_t)panaddr,sizeof(panaddr),0); NPIO(mp,(paddr_t)NPPSADDR,(paddr_t)((int)panicmap & UBADDRMASK),sizeof(panaddr),B_READ); goto out; break; case NPDUMP: mp->flags |= (DUMPREQ | BOARDREQ); /* Clear device request word */ mp->shmemp->statblock.sb_drw = 0; if(NpState & ICPAVAIL) wakeup((caddr_t)&NpState); break; case NPLOAD: mp->flags |= (LOADREQ | BOARDREQ); /* Clear device request word */ mp->shmemp->statblock.sb_drw = 0; if(NpState & ICPAVAIL) wakeup((caddr_t)&NpState); break; default: printf("Bad Req: %x.\n",mp->shmemp->statblock.sb_drw); goto out; } /* Process the Host Command Queue for this device */ NpProcQueue(mp);out: CLEARINT(mp); /* Clear the interrupt */ if(NpDebug & DEBENTRY) printf("npintr...\n"); return(1); /* Interrupt serviced */}/* * This routine, called from the interrupt handler, is used to process the * Host Command Queue for the specified device. */NpProcQueue(mp)struct npmaster *mp;{ register struct CmdQue *cqp; register struct CQE *ep; register struct npreq *rp; register int base; int s; if(NpDebug & DEBENTRY) printf("NpProcQueue\n"); cqp = &mp->shmemp->hostcq; /* Command Queue pointer */ s = spl5(); if(mp->flags & SCANNING) { splx(s); return; } mp->flags |= SCANNING; splx(s); cqp->scanflag | = ON; base = (int)mp->shmemp; /* Shared memory base address */ while(1) { cqp->scanflag |= ON; cqp->chngflag &= ~ON; while(ep = NpRemCQE(cqp,base)) { rp = ep->cqe_reqid; if(NpDebug & DEBCQE) printf("cqe_sts is %x ep = %x\n",ep->cqe_sts,ep); switch (ep->cqe_sts) { case NPDONE: rp->flags |= REQDONE; /* Normal completion */ break; case NPIFC: /* IFC Request */ rp->flags |= IOIFC; break; case NPPERR: /* Protocol Error */ rp->flags |= (NPPERR | REQDONE); break; case NPMERR: /* Memory allocation */ rp->flags |= (NPMERR | REQDONE); break; default: /* Error on Board */ rp->flags |= (IOERR | REQDONE); break; } if(NpDebug & DEBCQE) { printf("flag is %x reqid = %x\n",rp->flags,ep->cqe_reqid); printf("wakeup in procqueue\n"); } if(rp->intr) { if(NpDebug & DEBINTR) printf("calling usr intr at %x\n", rp->intr); /* Call interrupt routine */ (*rp->intr)(mp,rp); } else { if(NpDebug & DEBINTR) printf("waking up %x\n",rp); /* if(rp->flags & NPUIO) iodone(&rp->buf); else wakeup((caddr_t) (rp)); /* Awaken */ wakeup((caddr_t)(rp)); /* Awaken */ if(NpDebug & DEBINTR) printf("AWAKE\n"); } } cqp->scanflag &= ~ON; if(!(cqp->chngflag & ON)) break; } mp->flags &= ~SCANNING; if(NpDebug & DEBENTRY) printf("NpProcQueue...\n");}/* * NpIFC - processes an IFC (Internal Fuction Call) request * NOTE: this function must be called from the user context * on all virtual pageing systems * */NpIFC(mp,rp)register struct npmaster *mp;register struct npreq *rp;{ register struct CQE *ep; if(NpDebug & DEBENTRY) printf("NpIFC\n"); ep = rp->element; rp->flags &= ~IOIFC; switch(ep->cqe_func) { case NPUNLOCK: /* Unlock process, free up mapping registers */ if(NpDebug & DEBIFC) printf("NPUNLOCK\n"); if(rp->mapbase) NpUnMapMem(mp,rp); break; case NPLOCK: /* Lock process, get mapping registers */ if(NpDebug & DEBIFC) printf("NPLOCK\n"); NpMapMem(mp,rp,rp->virtmem,rp->bytecnt); ep->cqe_dma[0] = LOWORD(rp->bufaddr); ep->cqe_dma[1] = HIWORD(rp->bufaddr); break; case NPREMAP: if(NpDebug & DEBIFC) printf("NPREMAP\n"); /* Remap user buffer and update buffer offset */#ifdef USG np_remapmem(rp,rp->virtmem); ep->cqe_dma[0] = LOWORD(rp->bufaddr); ep->cqe_dma[1] = HIWORD(rp->bufaddr); break;#endif default: if(NpDebug & DEBIFC) printf("Bad case %x in IFC\n", ep->cqe_func); rp->flags |= (REQDONE | IOERR); break; }}/* * The following contains various routines for allocating and deallocating * structures used by the NP Driver. Routines are also here for addding * and removing Command Queue Elements from a Command Queue. *//* * Get a free NP Request structure from the list pointed to by head. Returns * a pointer to a npreq or NULL if none left. */struct npreq *NpGetReq(head)struct npreq *head;{ register struct npreq *p; p = head->free; head->free = p->free; if (p->flags & REQALOC) printf("GetReq: Req %x already allocated\n", p); p->flags &= WANTREQ; if (p != head) p->flags |= REQALOC; return(p==head ? (struct npreq *)NULL : p);}/* * Return a NP Request structure to the free list pointed to by head. */NpFreeReq(head,nprp)register struct npreq *head, *nprp;{ int s; if(NpDebug & DEBREQ) printf("NpFreeReq, head is %x rp is %x\n",head,nprp); if (nprp == NULL) { printf("FREEREQ: attempt to free null pointer\n"); return; } if (!(nprp->flags & REQALOC)) { printf("FREEREQ: attempt to free unallocated request %x\n", nprp); return; } if (nprp->flags & REQUSE) printf("FREEREQ: freeing unremoved request %x\n", nprp); s = spl5(); nprp->forw = nprp->back = (struct npreq *)NULL; nprp->free = head->free; head->free = nprp; nprp->flags &= ~REQALOC; splx(s); /* Wake up any processes waiting for a request structure */ if(head->flags & WANTREQ) { head->flags &= ~WANTREQ; wakeup((caddr_t)head); } if(NpDebug & DEBENTRY) printf("NpFreeReq...\n");}/* * Add a Command Queue Element onto the specified Command Queue and * update its Add offset. */NpAddCQE(ep,cqp,mp)struct CQE *ep;struct CmdQue *cqp;struct npmaster *mp;{ register unsign16 *temp; register unsign16 cqe_offset; register int base; base = (int)mp->shmemp; /* Shared memory base address */ temp = (unsign16 *)(base + cqp->cq_add); /* Offset to add element */ cqe_offset = (unsign16)((int)ep - base); if(*temp) { /* Should never happen */ printf("No more room on Command Queue!\n"); return; } else *temp = cqe_offset; /* Enter this request's offset */ /* Update cqe_add where next request is to be added */ cqp->cq_add += sizeof(unsign16); if(cqp->cq_add == cqp->cq_wrap) /* Wrap if necessary */ cqp->cq_add = (unsign16)((int)cqp->cq_cqe - base); cqp->chngflag |= ON; /* Set change flag unconditionally */ /* Interrupt the Board if his scan flag isn't on */ if(!(cqp->scanflag & ON)) INTNI(mp); /* Interrupt the Board */}/* * The NpRemCQE routine is used to remove the next CQE from the Command Queue * specified by cqp. The common offset of shared memory used by the device * is specified by base. NpRemCQE returns a pointer to the next CQE or * NULL if there are none left. This routine will also update the cqe_rem * offset which specifies where the next element to be removed from the * queue is located. */struct CQE *NpRemCQE(cqp,base)struct CmdQue *cqp;int base;{ register unsign16 *temp; register unsign16 cqe_offset; cqp->chngflag &= ~ON; /* Turn off unconditionally */ /* Get address of element to remove */ temp = (unsign16 *)(base +cqp->cq_rem); if(*temp == NULL) /* If none left, go home */ return((struct CQE *) NULL); else cqe_offset = *temp; /* Offset of CQE to remove */ /* Update the Command Queue's cqe_rem offset */ *temp = NULL; /* Clear out this entry */ cqp->cq_rem += sizeof(unsign16); /* Bump offset */ if(cqp->cq_rem == cqp->cq_wrap) /* Wrap if necessary */ cqp->cq_rem = (unsign16)((int)cqp->cq_cqe - base); temp = (unsign16 *)(base + cqe_offset); /* CQE address */ return((struct CQE *)temp); /* is returned */}/* * NpAddReq will add the specified npreq structure to the queue controlled * by head. */NpAddReq(head,rp)register struct npreq *head, *rp;{ int s; if (NpDebug & (DEBENTRY|DEBREQ)) printf("NpAddReq: %x\n",rp); if (rp->flags & REQUSE) printf("ADDREQ: Request %x allready in use\n", rp); s = spl7(); rp->forw = head->forw; rp->forw->back = rp; rp->back = head; head->forw = rp; rp->flags |= REQUSE; splx(s); if(NpDebug & DEBENTRY) printf("NpAddReq...\n");}/* * NpRemReq is used to remove a npreq structure from the queue specified by * head. */NpRemReq(rp)register struct npreq *rp;{ int s; if (NpDebug & (DEBENTRY|DEBREQ)) printf("NpRemReq: %x\n",rp); if (rp == NULL) { printf("REMREQ: null pointer removal requested\n"); return; } if (!(rp->flags & REQUSE)) { printf("REMREQ: trying to rem unused req %x\n", rp); return; } if (!(rp->flags & REQALOC)) { printf("REMREQ: trying to rem unallocated req %x\n", rp); return; } s = spl7(); rp->back->forw = rp->forw; rp->forw->back = rp->back; rp->flags &= ~REQUSE; splx(s); if(NpDebug & DEBENTRY) printf("NpRemReq...\n");}/* * The following routines are used to communicate with the * NI Hardware via the CSR0 commands. These commands are issued during * the hardware initializtion process and may also be used subsequently * by privileged processes who wish to communicate in this way. The * convention for passing data as a Command Block is discussed in detail * in the NI1510 UNIBUS Compatible Ethernet Communications Processor * Hardware Specification. */NpSendCSR0(iobase,src,bcount)struct NPREG *iobase;register unsign16 *src;int bcount;{ register int wcount; int i; int csrflag; unsign16 tmp; if(NpDebug & DEBENTRY) printf("NpSendCSR0\n"); /* Jolt the board into CSR0 command mode if necessary */ if(!(RCSR1(iobase) & NPENB)){ tmp = NPCLEAR; /* MC68000 clr reads before writing */ WCSR0(iobase,tmp); } wcount = (bcount +1) >> 1; /* Convert byte count to word count */ /* Clear timer flag before beginning the timer */ csrflag = NPCLEAR; timeout(NpTimer,&csrflag,DIAGTIME); for(i = 0; (i < wcount) & (csrflag == NPCLEAR); i++) { while(! ((RCSR1(iobase) & NPENB) && (RCSR1(iobase) & NPRDY))) if(csrflag) break; WCSR0(iobase,*src); src++; /* Better do this WCSR is a macro */ } /* Clear the timer entry */ untimeout(NpTimer,&csrflag); /* Error if timer went off */ if(csrflag) return(EIO); if(NpDebug & DEBENTRY) printf("NpSendCSR0...\n"); return(0);}/* * NpSetIntLev sets the UNIBUS interrupt vector to be used by the NP board when * interupting the host. The board is specified by mp. */NpSetIntLevel(mp,level)struct npmaster *mp;int level;{ struct { unsign16 cmd_word; unsign16 int_level; }cmd_block; cmd_block.cmd_word = NPCBI | CBICNT; cmd_block.int_level = level; return(NpSendCSR0(mp->iobase,(unsign16 *)&cmd_block,(int)sizeof(cmd_block)));}/* * NpSetMemAddr is used to declare the shared memory area address to be used * for communication between the driver and the device. This address is used * to access data structures by acting as a base from which defined offsets * locate data. The board is specified by mp. */NpSetMemAddr(mp,addr)struct npmaster *mp;caddr_t addr;{ caddr_t shmaddr; int error; struct { unsign16 cmd_word; unsign16 hi_addr; unsign16 lo_addr; } cmd_block; if(NpDebug & DEBENTRY) printf("NpSetMemAddr\n"); shmaddr = addr; if(NpDebug & DEBMEM) printf("NpSetMemAddr, addr is %x shmaddr is %x.\n",addr,shmaddr); cmd_block.cmd_word = NPCMD | CMDCNT; cmd_block.hi_addr = HIWORD(shmaddr); cmd_block.lo_addr = LOWORD(shmaddr); error = NpSendCSR0(mp->iobase,(unsign16 *)&cmd_block,(int)sizeof(cmd_block)); if(NpDebug & DEBENTRY) printf("NpSetMemAddr...\n"); return(error);}/* * NpSetXeqAddr specifies the address at which the board should begin * execution of its on-board software. It also indicates the shared memory
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -