📄 sktr.c
字号:
int ioaddr = dev->base_addr; unsigned short cmd; unsigned short SifStsValue; unsigned long loop_counter; WriteValue = ((WriteValue ^ CMD_SYSTEM_IRQ) | CMD_INTERRUPT_ADAPTER); cmd = (unsigned short)WriteValue; loop_counter = 0,5 * 800000; do { SifStsValue = inw(ioaddr + SIFSTS); } while((SifStsValue & CMD_INTERRUPT_ADAPTER) && loop_counter--); outw(cmd, ioaddr + SIFCMD); return;}/* * Processes adapter hardware reset, halts adapter and downloads firmware, * clears the halt bit. */static int sktr_reset_adapter(struct device *dev){ struct net_local *tp = (struct net_local *)dev->priv; unsigned short *fw_ptr = (unsigned short *)&sktr_code; unsigned short count, c; int ioaddr = dev->base_addr; /* Hardware adapter reset */ outw(ACL_ARESET, ioaddr + SIFACL); sktr_wait(40); c = inw(ioaddr + SIFACL); sktr_wait(20); if(dev->dma == 0) /* For PCI adapters */ { c &= ~(ACL_SPEED4 | ACL_SPEED16); /* Clear bits */ if(tp->DataRate == SPEED_4) c |= ACL_SPEED4; /* Set 4Mbps */ else c |= ACL_SPEED16; /* Set 16Mbps */ } /* In case a command is pending - forget it */ tp->ScbInUse = 0; c &= ~ACL_ARESET; /* Clear adapter reset bit */ c |= ACL_CPHALT; /* Halt adapter CPU, allow download */ c &= ~ACL_PSDMAEN; /* Clear pseudo dma bit */ outw(c, ioaddr + SIFACL); sktr_wait(40); /* Download firmware via DIO interface: */ do { /* Download first address part */ outw(*fw_ptr, ioaddr + SIFADX); fw_ptr++; /* Download second address part */ outw(*fw_ptr, ioaddr + SIFADD); fw_ptr++; if((count = *fw_ptr) != 0) /* Load loop counter */ { fw_ptr++; /* Download block data */ for(; count > 0; count--) { outw(*fw_ptr, ioaddr + SIFINC); fw_ptr++; } } else /* Stop, if last block downloaded */ { c = inw(ioaddr + SIFACL); c &= (~ACL_CPHALT | ACL_SINTEN); /* Clear CPHALT and start BUD */ outw(c, ioaddr + SIFACL); return (1); } } while(count == 0); return (-1);}/* * Starts bring up diagnostics of token ring adapter and evaluates * diagnostic results. */static int sktr_bringup_diags(struct device *dev){ int loop_cnt, retry_cnt; unsigned short Status; int ioaddr = dev->base_addr; sktr_wait(HALF_SECOND); sktr_exec_sifcmd(dev, EXEC_SOFT_RESET); sktr_wait(HALF_SECOND); retry_cnt = BUD_MAX_RETRIES; /* maximal number of retrys */ do { retry_cnt--; if(sktr_debug > 3) printk(KERN_INFO "BUD-Status: \n"); loop_cnt = BUD_MAX_LOOPCNT; /* maximum: three seconds*/ do { /* Inspect BUD results */ loop_cnt--; sktr_wait(HALF_SECOND); Status = inw(ioaddr + SIFSTS); Status &= STS_MASK; if(sktr_debug > 3) printk(KERN_INFO " %04X \n", Status); /* BUD successfully completed */ if(Status == STS_INITIALIZE) return (1); /* Unrecoverable hardware error, BUD not completed? */ } while((loop_cnt > 0) && ((Status & (STS_ERROR | STS_TEST)) != (STS_ERROR | STS_TEST))); /* Error preventing completion of BUD */ if(retry_cnt > 0) { printk(KERN_INFO "%s: Adapter Software Reset.\n", dev->name); sktr_exec_sifcmd(dev, EXEC_SOFT_RESET); sktr_wait(HALF_SECOND); } } while(retry_cnt > 0); Status = inw(ioaddr + SIFSTS); Status &= STS_ERROR_MASK; /* Hardware error occurred! */ printk(KERN_INFO "%s: Bring Up Diagnostics Error (%04X) occurred\n", dev->name, Status); return (-1);}/* * Copy initialisation data to adapter memory, beginning at address * 1:0A00; Starting DMA test and evaluating result bits. */static int sktr_init_adapter(struct device *dev){ struct net_local *tp = (struct net_local *)dev->priv; const unsigned char SCB_Test[6] = {0x00, 0x00, 0xC1, 0xE2, 0xD4, 0x8B}; const unsigned char SSB_Test[8] = {0xFF, 0xFF, 0xD1, 0xD7, 0xC5, 0xD9, 0xC3, 0xD4}; void *ptr = (void *)&tp->ipb; unsigned short *ipb_ptr = (unsigned short *)ptr; unsigned char *cb_ptr = (unsigned char *) &tp->scb; unsigned char *sb_ptr = (unsigned char *) &tp->ssb; unsigned short Status; int i, loop_cnt, retry_cnt; int ioaddr = dev->base_addr; /* Normalize: byte order low/high, word order high/low! (only IPB!) */ tp->ipb.SCB_Addr = SWAPW(virt_to_bus(&tp->scb)); tp->ipb.SSB_Addr = SWAPW(virt_to_bus(&tp->ssb)); /* Maximum: three initialization retries */ retry_cnt = INIT_MAX_RETRIES; do { retry_cnt--; /* Transfer initialization block */ outw(0x0001, ioaddr + SIFADX); /* To address 0001:0A00 of adapter RAM */ outw(0x0A00, ioaddr + SIFADD); /* Write 11 words to adapter RAM */ for(i = 0; i < 11; i++) outw(ipb_ptr[i], ioaddr + SIFINC); /* Execute SCB adapter command */ sktr_exec_sifcmd(dev, CMD_EXECUTE); loop_cnt = INIT_MAX_LOOPCNT; /* Maximum: 11 seconds */ /* While remaining retries, no error and not completed */ do { Status = 0; loop_cnt--; sktr_wait(HALF_SECOND); /* Mask interesting status bits */ Status = inw(ioaddr + SIFSTS); Status &= STS_MASK; } while(((Status &(STS_INITIALIZE | STS_ERROR | STS_TEST)) != 0) && ((Status & STS_ERROR) == 0) && (loop_cnt != 0)); if((Status & (STS_INITIALIZE | STS_ERROR | STS_TEST)) == 0) { /* Initialization completed without error */ i = 0; do { /* Test if contents of SCB is valid */ if(SCB_Test[i] != *(cb_ptr + i)) /* DMA data error: wrong data in SCB */ return (-1); i++; } while(i < 6); i = 0; do { /* Test if contents of SSB is valid */ if(SSB_Test[i] != *(sb_ptr + i)) /* DMA data error: wrong data in SSB */ return (-1); i++; } while (i < 8); return (1); /* Adapter successfully initialized */ } else { if((Status & STS_ERROR) != 0) { /* Initialization error occurred */ Status = inw(ioaddr + SIFSTS); Status &= STS_ERROR_MASK; /* ShowInitialisationErrorCode(Status); */ return (-1); /* Unrecoverable error */ } else { if(retry_cnt > 0) { /* Reset adapter and try init again */ sktr_exec_sifcmd(dev, EXEC_SOFT_RESET); sktr_wait(HALF_SECOND); } } } } while(retry_cnt > 0); return (-1);}/* * Check for outstanding commands in command queue and tries to execute * command immediately. Corresponding command flag in command queue is cleared. */static void sktr_chk_outstanding_cmds(struct device *dev){ struct net_local *tp = (struct net_local *)dev->priv; unsigned long Addr = 0; unsigned char i = 0; if(tp->CMDqueue == 0) return; /* No command execution */ /* If SCB in use: no command */ if(tp->ScbInUse == 1) return; /* Check if adapter is opened, avoiding COMMAND_REJECT * interrupt by the adapter! */ if(tp->AdapterOpenFlag == 0) { if(tp->CMDqueue & OC_OPEN) { /* Execute OPEN command */ tp->CMDqueue ^= OC_OPEN; /* Copy the 18 bytes of the product ID */ while((AdapterName[i] != '\0') && (i < PROD_ID_SIZE)) { tp->ProductID[i] = AdapterName[i]; i++; } Addr = htonl(virt_to_bus(&tp->ocpl)); tp->scb.Parm[0] = LOWORD(Addr); tp->scb.Parm[1] = HIWORD(Addr); tp->scb.CMD = OPEN; } else /* No OPEN command queued, but adapter closed. Note: * We'll try to re-open the adapter in DriverPoll() */ return; /* No adapter command issued */ } else { /* Adapter is open; evaluate command queue: try to execute * outstanding commands (depending on priority!) CLOSE * command queued */ if(tp->CMDqueue & OC_CLOSE) { tp->CMDqueue ^= OC_CLOSE; tp->AdapterOpenFlag = 0; tp->scb.Parm[0] = 0; /* Parm[0], Parm[1] are ignored */ tp->scb.Parm[1] = 0; /* but should be set to zero! */ tp->scb.CMD = CLOSE; if(!tp->HaltInProgress) tp->CMDqueue |= OC_OPEN; /* re-open adapter */ else tp->CMDqueue = 0; /* no more commands */ } else { if(tp->CMDqueue & OC_RECEIVE) { tp->CMDqueue ^= OC_RECEIVE; Addr = htonl(virt_to_bus(tp->RplHead)); tp->scb.Parm[0] = LOWORD(Addr); tp->scb.Parm[1] = HIWORD(Addr); tp->scb.CMD = RECEIVE; } else { if(tp->CMDqueue & OC_TRANSMIT_HALT) { /* NOTE: TRANSMIT.HALT must be checked * before TRANSMIT. */ tp->CMDqueue ^= OC_TRANSMIT_HALT; tp->scb.CMD = TRANSMIT_HALT; /* Parm[0] and Parm[1] are ignored * but should be set to zero! */ tp->scb.Parm[0] = 0; tp->scb.Parm[1] = 0; } else { if(tp->CMDqueue & OC_TRANSMIT) { /* NOTE: TRANSMIT must be * checked after TRANSMIT.HALT */ if(tp->TransmitCommandActive) { if(!tp->TransmitHaltScheduled) { tp->TransmitHaltScheduled = 1; sktr_exec_cmd(dev, OC_TRANSMIT_HALT) ; } tp->TransmitCommandActive = 0; return; } tp->CMDqueue ^= OC_TRANSMIT; sktr_cancel_tx_queue(tp); Addr = htonl(virt_to_bus(tp->TplBusy)); tp->scb.Parm[0] = LOWORD(Addr); tp->scb.Parm[1] = HIWORD(Addr); tp->scb.CMD = TRANSMIT; tp->TransmitCommandActive = 1; } else { if(tp->CMDqueue & OC_MODIFY_OPEN_PARMS) { tp->CMDqueue ^= OC_MODIFY_OPEN_PARMS; tp->scb.Parm[0] = tp->ocpl.OPENOptions; /* new OPEN options*/ tp->scb.Parm[0] |= ENABLE_FULL_DUPLEX_SELECTION; tp->scb.Parm[1] = 0; /* is ignored but should be zero */ tp->scb.CMD = MODIFY_OPEN_PARMS; } else { if(tp->CMDqueue & OC_SET_FUNCT_ADDR) { tp->CMDqueue ^= OC_SET_FUNCT_ADDR; tp->scb.Parm[0] = LOWORD(tp->ocpl.FunctAddr); tp->scb.Parm[1] = HIWORD(tp->ocpl.FunctAddr); tp->scb.CMD = SET_FUNCT_ADDR; } else { if(tp->CMDqueue & OC_SET_GROUP_ADDR) { tp->CMDqueue ^= OC_SET_GROUP_ADDR; tp->scb.Parm[0] = LOWORD(tp->ocpl.GroupAddr); tp->scb.Parm[1] = HIWORD(tp->ocpl.GroupAddr); tp->scb.CMD = SET_GROUP_ADDR; } else { if(tp->CMDqueue & OC_READ_ERROR_LOG) { tp->CMDqueue ^= OC_READ_ERROR_LOG; Addr = htonl(virt_to_bus(&tp->errorlogtable)); tp->scb.Parm[0] = LOWORD(Addr); tp->scb.Parm[1] = HIWORD(Addr); tp->scb.CMD = READ_ERROR_LOG; } else { printk(KERN_WARNING "CheckForOutstandingCommand: unknown Command\n"); tp->CMDqueue = 0; return; } } } } } } } } } tp->ScbInUse = 1; /* Set semaphore: SCB in use. */ /* Execute SCB and generate IRQ when done. */ sktr_exec_sifcmd(dev, CMD_EXECUTE | CMD_SCB_REQUEST); return;}/* * IRQ conditions: signal loss on the ring, transmit or receive of beacon * frames (disabled if bit 1 of OPEN option is set); report error MAC * frame transmit (disabled if bit 2 of OPEN option is set); open or short * cirquit fault on the lobe is detected; remove MAC frame received; * error counter overflow (255); opened adapter is the only station in ring. * After some of the IRQs the adapter is closed! */static void sktr_ring_status_irq(struct device *dev){ struct net_local *tp = (struct net_local *)dev->priv; tp->CurrentRingStatus = SWAPB(tp->ssb.Parm[0]); /* First: fill up statistics */ if(tp->ssb.Parm[0] & SIGNAL_LOSS) { printk(KERN_INFO "%s: Signal Loss\n", dev->name); tp->MacStat.line_errors++; } /* Adapter is closed, but initialized */ if(tp->ssb.Parm[0] & LOBE_WIRE_FAULT) { printk(KERN_INFO "%s: Lobe Wire Fault, Reopen Adapter\n", dev->name); tp->MacStat.line_errors++; } if(tp->ssb.Parm[0] & RING_RECOVERY) printk(KERN_INFO "%s: Ring Recovery\n", dev->name); /* Counter overflow: read error log */ if(tp->ssb.Parm[0] & COUNTER_OVERFLOW) { printk(KERN_INFO "%s: Counter Overflow\n", dev->name); sktr_exec_cmd(dev, OC_READ_ERROR_LOG); } /* Adapter is closed, but initialized */ if(tp->ssb.Parm[0] & REMOVE_RECEIVED) printk(KERN_INFO "%s: Remove Received, Reopen Adapter\n", dev->name); /* Adapter is closed, but initialized */ if(tp->ssb.Parm[0] & AUTO_REMOVAL_ERROR) printk(KERN_INFO "%s: Auto Removal Error, Reopen Adapter\n", dev->name); if(tp->ssb.Parm[0] & HARD_ERROR) printk(KERN_INFO "%s: Hard Error\n", dev->name); if(tp->ssb.Parm[0] & SOFT_ERROR) printk(KERN_INFO "%s: Soft Error\n", dev->name); if(tp->ssb.Parm[0] & TRANSMIT_BEACON) printk(KERN_INFO "%s: Transmit Beacon\n", dev->name); if(tp->ssb.Parm[0] & SINGLE_STATION) printk(KERN_INFO "%s: Single Station\n", dev->name); /* Check if adapter has been closed */ if(tp->ssb.Parm[0] & ADAPTER_CLOSED) { printk(KERN_INFO "%s: Adapter closed (Reopening)," "QueueSkb %d, CurrentRingStat %x\n", dev->name, tp->QueueSkb, tp->CurrentRingStatus); tp->AdapterOpenFlag = 0; sktr_open_adapter(dev); } return;}/* * Issued if adapter has encountered an unrecoverable hardware * or software error. */static void sktr_chk_irq(struct device *dev){ int i; unsigned short AdapterCheckBlock[4]; unsigned short ioaddr = dev->base_addr; struct net_local *tp = (struct net_local *)dev->priv; tp->AdapterOpenFlag = 0; /* Adapter closed now */ /* Page number of adapter memory */ outw(0x0001, ioaddr + SIFADX); /* Address offset */ outw(CHECKADDR, ioaddr + SIFADR); /* Reading 8 byte adapter check block. */ for(i = 0; i < 4; i++) AdapterCheckBlock[i] = inw(ioaddr + SIFINC);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -