📄 ethervgbe.c
字号:
freeb(block); if(ctlr->debugflags & DumpTx) print("vgbe: Block[%03d]:%#p has been freed\n", i, block); } ctlr->tx_count -= count; if(ctlr->debugflags & DumpTx) print("vgbe: tx_eof: done [count=%d]\n", count); iunlock(&ctlr->tx_lock); if(ctlr->tx_count) wiob(ctlr, TxCsrS, TxCsr_Wakeup);}static voidvgbeinterrupt(Ureg *, void* arg){ Ether* edev; Ctlr* ctlr; ulong status; edev = (Ether *) arg; if(edev == nil) return; ctlr = edev->ctlr; if(ctlr == nil) return; /* Mask interrupts. */ wiol(ctlr, Imr, 0); status = riol(ctlr, Isr); if(status == 0xffff) goto end; /* acknowledge */ if(status) wiol(ctlr, Isr, status); if((status & Isr_Mask) == 0) goto end; ctlr->stats.intr++; if(ctlr->debugflags & DumpIntr) if(ctlr->debugcount){ print("vgbe: irq: status = %#08ulx\n", status); vgbedumpisr(status); ctlr->debugcount--; } if(status & Isr_RxComplete) vgberxeof(edev); if(status & Isr_TxComplete0) vgbetxeof(edev); if(status & Isr_Stopped) print("vgbe: irq: software shutdown complete\n"); if(status & Isr_RxFifoOvflow) print("vgbe: irq: RX FIFO overflow\n"); if(status & Isr_PhyIntr) print("vgbe: irq: PHY interrupt\n"); if(status & Isr_LinkStatus) print("vgbe: irq: link status change\n"); if(status & Isr_RxNoDesc) print("vgbe: irq: ran out of Rx descriptors\n"); if(status & Isr_RxDmaStall){ print("vgbe: irq: Rx DMA stall\n"); wiol(ctlr, Cr3C, Cr3_IntMask); return; } if(status & Isr_TxDmaStall){ print("vgbe: irq: Tx DMA stall\n"); wiol(ctlr, Cr3C, Cr3_IntMask); return; }end: /* Unmask interrupts. */ wiol(ctlr, Imr, ~0);}static voidvgbetransmit(Ether* edev){ Block* block; Ctlr* ctlr; int i, index, start, count; TxDesc* desc; ulong status, length; ctlr = edev->ctlr; ilock(&ctlr->tx_lock); start = riow(ctlr, TxDscIdx); if(ctlr->debugflags & DumpTx) print("vgbe: transmit (start=%d)\n", start); /* find empty slot */ for(count = 0, i = 0; i < TxCount; i++){ index = (i + start) % TxCount; if(ctlr->tx_blocks[index]) continue; desc = &ctlr->tx_ring[index]; status = le32toh(desc->status); if(status & TxDesc_Status_Own) continue; block = qget(edev->oq); if(block == nil) break; count++; length = BLEN(block); if(ctlr->debugflags & DumpTx) print("vgbe: Tx-Desc[%03d] Block:%#p, addr=%#08ulx, len:%ld\n", index, block, PCIWADDR(block->rp), length); ctlr->tx_blocks[index] = block; /* Initialize Tx descriptor. */ desc->status = htole32((length<<16)|TxDesc_Status_Own); desc->control = htole32(TxDesc_Control_Intr|TxDesc_Control_Normal|((1+1)<<28)); desc->frags[0].addr_lo = htole32((ulong) PCIWADDR(block->rp)); desc->frags[0].addr_hi = htole16(0); desc->frags[0].length = htole16(length); } ctlr->tx_count += count; if(ctlr->debugflags & DumpTx) print("vgbe: transmit: done [count=%d]\n", count); iunlock(&ctlr->tx_lock); if(ctlr->tx_count) wiob(ctlr, TxCsrS, TxCsr_Wakeup); if(count == 0) print("vgbe: transmit: no Tx entry available\n");}static voidvgbeattach(Ether* edev){ Ctlr* ctlr; RxDesc* rxdesc; TxDesc* txdesc; int i; ctlr = edev->ctlr; lock(&ctlr->init_lock); if(ctlr->inited){ unlock(&ctlr->init_lock); return; }// print("vgbe: attach\n"); /* Allocate Rx ring. (TODO: Alignment ?) */ rxdesc = mallocalign(RxCount* sizeof(RxDesc), 256, 0, 0); if(rxdesc == nil){ print("vgbe: unable to alloc Rx ring\n"); unlock(&ctlr->init_lock); return; } ctlr->rx_ring = rxdesc; /* Allocate Rx blocks, initialize Rx ring. */ for(i = 0; i < RxCount; i++) vgbenewrx(ctlr, i); /* Init Rx MAC. */ wiob(ctlr, RxControl, RxControl_MultiCast|RxControl_BroadCast|RxControl_UniCast); wiob(ctlr, RxConfig, RxConfig_VlanOpt0); /* Load Rx ring. */ wiol(ctlr, RxDescLo, (ulong) PCIWADDR(rxdesc)); wiow(ctlr, RxNum, RxCount - 1); wiow(ctlr, RxDscIdx, 0); wiow(ctlr, RxResCnt, RxCount); /* Allocate Tx ring. */ txdesc = mallocalign(TxCount* sizeof(TxDesc), 256, 0, 0); if(txdesc == nil){ print("vgbe: unable to alloc Tx ring\n"); unlock(&ctlr->init_lock); return; } ctlr->tx_ring = txdesc; /* Init DMAs */ wiob(ctlr, DmaCfg0, 4); /* Init Tx MAC. */ wiob(ctlr, TxControl, 0); wiob(ctlr, TxConfig, TxConfig_NonBlk|TxConfig_ArbPrio); /* Load Tx ring. */ wiol(ctlr, TxDescLo, (ulong) PCIWADDR(txdesc)); wiow(ctlr, TxNum, TxCount - 1); wiow(ctlr, TxDscIdx, 0); /* Enable Xon/Xoff */ wiob(ctlr, Cr2S, 0xb|Cr2_XonEnable); /* Enable Rx queue */ wiob(ctlr, RxCsrS, RxCsr_RunQueue); /* Enable Tx queue */ wiob(ctlr, TxCsrS, TxCsr_RunQueue); /* Done */ ctlr->inited = 1; unlock(&ctlr->init_lock); /* Enable interrupts */ wiol(ctlr, Isr, 0xffffffff); wiob(ctlr, Cr3S, Cr3_IntMask); /* Wake up Rx queue */ wiob(ctlr, RxCsrS, RxCsr_Wakeup);}static voidvgbereset(Ctlr* ctlr){// MiiPhy* phy; int timeo, i;// print("vgbe: reset\n"); /* Soft reset the controller. */ wiob(ctlr, Cr1S, Cr1_reset); for(timeo = 0; timeo < Timeout; timeo++) if((riob(ctlr, Cr1S) & Cr1_reset) == 0) break; if(timeo >= Timeout){ print("vgbe: softreset timeout\n"); return; } /* Reload eeprom. */ siob(ctlr, Eecsr, Eecsr_Autold); for(timeo = 0; timeo < Timeout; timeo++) if((riob(ctlr, Eecsr) & Eecsr_Autold) == 0) break; if(timeo >= Timeout){ print("vgbe: eeprom reload timeout\n"); return; } /* Load the MAC address. */ for(i = 0; i < Eaddrlen; i++) ctlr->ea[i] = riob(ctlr, EthAddr+i); /* Initialize interrupts. */ wiol(ctlr, Isr, 0xffffffff); wiol(ctlr, Imr, 0xffffffff); /* Disable interrupts. */ wiol(ctlr, Cr3C, Cr3_IntMask); /* 32 bits addresses only. (TODO: 64 bits ?) */ wiol(ctlr, TxDescHi, 0); wiow(ctlr, DataBufHi, 0); /* Enable MAC (turning off Rx/Tx engines for the moment). */ wiob(ctlr, Cr0C, Cr0_Stop|Cr0_EnableRx|Cr0_EnableTx); wiob(ctlr, Cr0S, Cr0_Start); /* Initialize Rx engine. */ wiow(ctlr, RxCsrC, RxCsr_RunQueue); /* Initialize Tx engine. */ wiow(ctlr, TxCsrC, TxCsr_RunQueue); /* Enable Rx/Tx engines. */ wiob(ctlr, Cr0S, Cr0_EnableRx|Cr0_EnableTx); /* Initialize link management. */ ctlr->mii = malloc(sizeof(Mii)); if(ctlr->mii == nil){ print("vgbe: unable to alloc Mii\n"); return; } ctlr->mii->mir = vgbemiir; ctlr->mii->miw = vgbemiiw; ctlr->mii->ctlr = ctlr; if(mii(ctlr->mii, 1<<1) == 0){ print("vgbe: no phy found\n"); return; }// phy = ctlr->mii->curphy;// print("vgbe: phy:oui %#x\n", phy->oui);}static voidvgbepci(void){ Pcidev* pdev;// print("vgbe: pci\n"); pdev = nil; while(pdev = pcimatch(pdev, 0, 0)){ Ctlr* ctlr; int port, size; if(pdev->ccrb != 0x02 || pdev->ccru != 0) continue; switch((pdev->did<<16) | pdev->vid){ default: continue; case (0x3119<<16)|0x1106: /* VIA Velocity (VT6122) */ break; } if((pdev->pcr & 1) == 0){ print("vgbe: io not enabled [pcr=%#lux]\n", (ulong)pdev->pcr); continue; } pcisetbme(pdev); pcisetpms(pdev, 0); port = pdev->mem[0].bar; size = pdev->mem[0].size; if((port & 1) == 0){ print("vgbe: bar[0]=%#x is not io\n", port); continue; } if(port > 0xff00){ print("vgbe: invalid port %#ux\n", port); continue; } port &= 0xfffe; if(size != 256){ print("vgbe: invalid io size: %d\n", size); continue; } if(ioalloc(port, size, 0, "vge") < 0){ print("vgbe: port %#ux already in use\n", port); continue; } ctlr = malloc(sizeof(Ctlr)); if(ctlr == nil){ print("vgbe: unable to alloc Ctlr\n"); iofree(port); continue; } ctlr->pdev = pdev; ctlr->port = port; ctlr->inited = 0; if(vgbehead != nil) vgbetail->link = ctlr; else vgbehead = ctlr; vgbetail = ctlr; }}static longvgbectl(Ether* edev, void* buf, long n){ Cmdbuf* cb; Ctlr* ctlr; ulong index; char* rptr; RxDesc* rd; TxDesc* td; uchar* p; ctlr = edev->ctlr; cb = parsecmd(buf, n); if(waserror()){ free(cb); nexterror(); } if(cistrcmp(cb->f[0], "reset") == 0){ vgbereset(ctlr); wiob(ctlr, Cr3S, Cr3_IntMask); wiob(ctlr, RxCsrS, RxCsr_RunQueue); wiob(ctlr, RxCsrS, RxCsr_Wakeup); } else if(cistrcmp(cb->f[0], "dumpintr") == 0){ if(cb->nf < 2) error(Ecmdargs); if(cistrcmp(cb->f[1], "on") == 0){ ctlr->debugflags |= DumpIntr; ctlr->debugcount = ~0; } else if(cistrcmp(cb->f[1], "off") == 0) ctlr->debugflags &= ~DumpIntr; else{ ulong count; char* rptr; count = strtoul(cb->f[1], &rptr, 0); if(rptr == cb->f[1]) error("invalid control request"); ctlr->debugflags |= DumpIntr; ctlr->debugcount = count; print("vgbe: debugcount set to %uld\n", count); } } else if(cistrcmp(cb->f[0], "dumprx") == 0){ if(cb->nf < 2) error(Ecmdargs); if(cistrcmp(cb->f[1], "on") == 0) ctlr->debugflags |= DumpRx; else if(cistrcmp(cb->f[1], "off") == 0) ctlr->debugflags &= ~DumpRx; else{ index = strtoul(cb->f[1], &rptr, 0); if((rptr == cb->f[1]) || (index >= RxCount)) error("invalid control request"); rd = &ctlr->rx_ring[index]; print("vgbe: DumpRx[%03uld] status=%#08ulx ctl=%#08ulx len=%#04ux bytes\n", index, rd->status, rd->control, rd->length); } } else if(cistrcmp(cb->f[0], "dumptx") == 0){ if(cb->nf < 2) error(Ecmdargs); if(cistrcmp(cb->f[1], "on") == 0) ctlr->debugflags |= DumpTx; else if(cistrcmp(cb->f[1], "off") == 0) ctlr->debugflags &= ~DumpTx; else{ index = strtoul(cb->f[1], &rptr, 0); if((rptr == cb->f[1]) || (index >= TxCount)) error("invalid control request"); td = &ctlr->tx_ring[index]; print("vgbe: DumpTx[%03uld] status=%#08ulx ctl=%#08ulx len=%#04ux bytes", index, td->status, td->control, td->frags[0].length); p = (uchar*)td; for(index = 0; index < sizeof(TxDesc); index++){ if((index % 16) == 0) print("\nvgbe: "); else print(" "); print("%#02x", p[index]); } } } else if(cistrcmp(cb->f[0], "dumpall") == 0){ if(cb->nf < 2) error(Ecmdargs); if(cistrcmp(cb->f[1], "on") == 0){ ctlr->debugflags = ~0; ctlr->debugcount = ~0; } else if(cistrcmp(cb->f[1], "off") == 0) ctlr->debugflags = 0; else error("invalid control request"); } else error(Ebadctl); free(cb); poperror(); return n;}static voidvgbepromiscuous(void* arg, int on){ USED(arg, on);}/* multicast already on, don't need to do anything */static voidvgbemulticast(void*, uchar*, int){}static intvgbepnp(Ether* edev){ Ctlr* ctlr;// print("vgbe: pnp\n"); if(vgbehead == nil) vgbepci(); for(ctlr = vgbehead; ctlr != nil; ctlr = ctlr->link){ if(ctlr->active) continue; if(edev->port == 0 || edev->port == ctlr->port){ ctlr->active = 1; break; } } if(ctlr == nil) return -1; vgbereset(ctlr); edev->ctlr = ctlr; edev->port = ctlr->port; edev->irq = ctlr->pdev->intl; edev->tbdf = ctlr->pdev->tbdf; edev->mbps = 1000; memmove(edev->ea, ctlr->ea, Eaddrlen); edev->attach = vgbeattach; edev->transmit = vgbetransmit; edev->interrupt = vgbeinterrupt; edev->ifstat = vgbeifstat;// edev->promiscuous = vgbepromiscuous; edev->multicast = vgbemulticast;// edev->shutdown = vgbeshutdown; edev->ctl = vgbectl; edev->arg = edev; return 0;}voidethervgbelink(void){ addethercard("vgbe", vgbepnp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -