📄 tms380tr.c
字号:
/* Parm[0-3]: adapter internal register R13-R15 */ break; default: printk(KERN_INFO "%s: Unknown status", dev->name); break; } if(tms380tr_chipset_init(dev) == 1) { /* Restart of firmware successful */ tp->AdapterOpenFlag = 1; } return;}/* * Internal adapter pointer to RAM data are copied from adapter into * host system. */static int tms380tr_read_ptr(struct net_device *dev){ struct net_local *tp = netdev_priv(dev); unsigned short adapterram; tms380tr_read_ram(dev, (unsigned char *)&tp->intptrs.BurnedInAddrPtr, ADAPTER_INT_PTRS, 16); tms380tr_read_ram(dev, (unsigned char *)&adapterram, cpu_to_be16((unsigned short)tp->intptrs.AdapterRAMPtr), 2); return be16_to_cpu(adapterram); }/* * Reads a number of bytes from adapter to system memory. */static void tms380tr_read_ram(struct net_device *dev, unsigned char *Data, unsigned short Address, int Length){ int i; unsigned short old_sifadx, old_sifadr, InWord; /* Save the current values */ old_sifadx = SIFREADW(SIFADX); old_sifadr = SIFREADW(SIFADR); /* Page number of adapter memory */ SIFWRITEW(0x0001, SIFADX); /* Address offset in adapter RAM */ SIFWRITEW(Address, SIFADR); /* Copy len byte from adapter memory to system data area. */ i = 0; for(;;) { InWord = SIFREADW(SIFINC); *(Data + i) = HIBYTE(InWord); /* Write first byte */ if(++i == Length) /* All is done break */ break; *(Data + i) = LOBYTE(InWord); /* Write second byte */ if (++i == Length) /* All is done break */ break; } /* Restore original values */ SIFWRITEW(old_sifadx, SIFADX); SIFWRITEW(old_sifadr, SIFADR); return;}/* * Cancel all queued packets in the transmission queue. */static void tms380tr_cancel_tx_queue(struct net_local* tp){ TPL *tpl; /* * NOTE: There must not be an active TRANSMIT command pending, when * this function is called. */ if(tp->TransmitCommandActive) return; for(;;) { tpl = tp->TplBusy; if(!tpl->BusyFlag) break; /* "Remove" TPL from busy list. */ tp->TplBusy = tpl->NextTPLPtr; tms380tr_write_tpl_status(tpl, 0); /* Clear VALID bit */ tpl->BusyFlag = 0; /* "free" TPL */ printk(KERN_INFO "Cancel tx (%08lXh).\n", (unsigned long)tpl); if (tpl->DMABuff) dma_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(tpl->Skb); } return;}/* * This function is called whenever a transmit interrupt is generated by the * adapter. For a command complete interrupt, it is checked if we have to * issue a new transmit command or not. */static void tms380tr_tx_status_irq(struct net_device *dev){ struct net_local *tp = netdev_priv(dev); unsigned char HighByte, HighAc, LowAc; TPL *tpl; /* NOTE: At this point the SSB from TRANSMIT STATUS is no longer * available, because the CLEAR SSB command has already been issued. * * Process all complete transmissions. */ for(;;) { tpl = tp->TplBusy; if(!tpl->BusyFlag || (tpl->Status & (TX_VALID | TX_FRAME_COMPLETE)) != TX_FRAME_COMPLETE) { break; } /* "Remove" TPL from busy list. */ tp->TplBusy = tpl->NextTPLPtr ; /* Check the transmit status field only for directed frames*/ if(DIRECTED_FRAME(tpl) && (tpl->Status & TX_ERROR) == 0) { HighByte = GET_TRANSMIT_STATUS_HIGH_BYTE(tpl->Status); HighAc = GET_FRAME_STATUS_HIGH_AC(HighByte); LowAc = GET_FRAME_STATUS_LOW_AC(HighByte); if((HighAc != LowAc) || (HighAc == AC_NOT_RECOGNIZED)) { printk(KERN_DEBUG "%s: (DA=%08lX not recognized)\n", dev->name, *(unsigned long *)&tpl->MData[2+2]); } else { if(tms380tr_debug > 3) printk(KERN_DEBUG "%s: Directed frame tx'd\n", dev->name); } } else { if(!DIRECTED_FRAME(tpl)) { if(tms380tr_debug > 3) printk(KERN_DEBUG "%s: Broadcast frame tx'd\n", dev->name); } } tp->MacStat.tx_packets++; if (tpl->DMABuff) dma_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, DMA_TO_DEVICE); dev_kfree_skb_irq(tpl->Skb); tpl->BusyFlag = 0; /* "free" TPL */ } if(!tp->TplFree->NextTPLPtr->BusyFlag) netif_wake_queue(dev); return;}/* * Called if a frame receive interrupt is generated by the adapter. * Check if the frame is valid and indicate it to system. */static void tms380tr_rcv_status_irq(struct net_device *dev){ struct net_local *tp = netdev_priv(dev); unsigned char *ReceiveDataPtr; struct sk_buff *skb; unsigned int Length, Length2; RPL *rpl; RPL *SaveHead; dma_addr_t dmabuf; /* NOTE: At this point the SSB from RECEIVE STATUS is no longer * available, because the CLEAR SSB command has already been issued. * * Process all complete receives. */ for(;;) { rpl = tp->RplHead; if(rpl->Status & RX_VALID) break; /* RPL still in use by adapter */ /* Forward RPLHead pointer to next list. */ SaveHead = tp->RplHead; tp->RplHead = rpl->NextRPLPtr; /* Get the frame size (Byte swap for Intel). * Do this early (see workaround comment below) */ Length = be16_to_cpu((unsigned short)rpl->FrameSize); /* Check if the Frame_Start, Frame_End and * Frame_Complete bits are set. */ if((rpl->Status & VALID_SINGLE_BUFFER_FRAME) == VALID_SINGLE_BUFFER_FRAME) { ReceiveDataPtr = rpl->MData; /* Workaround for delayed write of FrameSize on ISA * (FrameSize is false but valid-bit is reset) * Frame size is set to zero when the RPL is freed. * Length2 is there because there have also been * cases where the FrameSize was partially written */ Length2 = be16_to_cpu((unsigned short)rpl->FrameSize); if(Length == 0 || Length != Length2) { tp->RplHead = SaveHead; break; /* Return to tms380tr_interrupt */ } tms380tr_update_rcv_stats(tp,ReceiveDataPtr,Length); if(tms380tr_debug > 3) printk(KERN_DEBUG "%s: Packet Length %04X (%d)\n", dev->name, Length, Length); /* Indicate the received frame to system the * adapter does the Source-Routing padding for * us. See: OpenOptions in tms380tr_init_opb() */ skb = rpl->Skb; if(rpl->SkbStat == SKB_UNAVAILABLE) { /* Try again to allocate skb */ skb = dev_alloc_skb(tp->MaxPacketSize); if(skb == NULL) { /* Update Stats ?? */ } else { skb->dev = dev; skb_put(skb, tp->MaxPacketSize); rpl->SkbStat = SKB_DATA_COPY; ReceiveDataPtr = rpl->MData; } } if(skb && (rpl->SkbStat == SKB_DATA_COPY || rpl->SkbStat == SKB_DMA_DIRECT)) { if(rpl->SkbStat == SKB_DATA_COPY) memcpy(skb->data, ReceiveDataPtr, Length); /* Deliver frame to system */ rpl->Skb = NULL; skb_trim(skb,Length); skb->protocol = tr_type_trans(skb,dev); netif_rx(skb); dev->last_rx = jiffies; } } else /* Invalid frame */ { if(rpl->Skb != NULL) dev_kfree_skb_irq(rpl->Skb); /* Skip list. */ if(rpl->Status & RX_START_FRAME) /* Frame start bit is set -> overflow. */ tp->MacStat.rx_errors++; } if (rpl->DMABuff) dma_unmap_single(tp->pdev, rpl->DMABuff, tp->MaxPacketSize, DMA_TO_DEVICE); rpl->DMABuff = 0; /* Allocate new skb for rpl */ rpl->Skb = dev_alloc_skb(tp->MaxPacketSize); /* skb == NULL ? then use local buffer */ if(rpl->Skb == NULL) { rpl->SkbStat = SKB_UNAVAILABLE; rpl->FragList[0].DataAddr = htonl(((char *)tp->LocalRxBuffers[rpl->RPLIndex] - (char *)tp) + tp->dmabuffer); rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex]; } else /* skb != NULL */ { rpl->Skb->dev = dev; skb_put(rpl->Skb, tp->MaxPacketSize); /* Data unreachable for DMA ? then use local buffer */ dmabuf = dma_map_single(tp->pdev, rpl->Skb->data, tp->MaxPacketSize, DMA_FROM_DEVICE); if(tp->dmalimit && (dmabuf + tp->MaxPacketSize > tp->dmalimit)) { rpl->SkbStat = SKB_DATA_COPY; rpl->FragList[0].DataAddr = htonl(((char *)tp->LocalRxBuffers[rpl->RPLIndex] - (char *)tp) + tp->dmabuffer); rpl->MData = tp->LocalRxBuffers[rpl->RPLIndex]; } else { /* DMA directly in skb->data */ rpl->SkbStat = SKB_DMA_DIRECT; rpl->FragList[0].DataAddr = htonl(dmabuf); rpl->MData = rpl->Skb->data; rpl->DMABuff = dmabuf; } } rpl->FragList[0].DataCount = cpu_to_be16((unsigned short)tp->MaxPacketSize); rpl->FrameSize = 0; /* Pass the last RPL back to the adapter */ tp->RplTail->FrameSize = 0; /* Reset the CSTAT field in the list. */ tms380tr_write_rpl_status(tp->RplTail, RX_VALID | RX_FRAME_IRQ); /* Current RPL becomes last one in list. */ tp->RplTail = tp->RplTail->NextRPLPtr; /* Inform adapter about RPL valid. */ tms380tr_exec_sifcmd(dev, CMD_RX_VALID); } return;}/* * This function should be used whenever the status of any RPL must be * modified by the driver, because the compiler may otherwise change the * order of instructions such that writing the RPL status may be executed * at an undesireable time. When this function is used, the status is * always written when the function is called. */static void tms380tr_write_rpl_status(RPL *rpl, unsigned int Status){ rpl->Status = Status; return;}/* * The function updates the statistic counters in mac->MacStat. * It differtiates between directed and broadcast/multicast ( ==functional) * frames. */static void tms380tr_update_rcv_stats(struct net_local *tp, unsigned char DataPtr[], unsigned int Length){ tp->MacStat.rx_packets++; tp->MacStat.rx_bytes += Length; /* Test functional bit */ if(DataPtr[2] & GROUP_BIT) tp->MacStat.multicast++; return;}static int tms380tr_set_mac_address(struct net_device *dev, void *addr){ struct net_local *tp = netdev_priv(dev); struct sockaddr *saddr = addr; if (tp->AdapterOpenFlag || tp->AdapterVirtOpenFlag) { printk(KERN_WARNING "%s: Cannot set MAC/LAA address while card is open\n", dev->name); return -EIO; } memcpy(dev->dev_addr, saddr->sa_data, dev->addr_len); return 0;}#if TMS380TR_DEBUG > 0/* * Dump Packet (data) */static void tms380tr_dump(unsigned char *Data, int length){ int i, j; for (i = 0, j = 0; i < length / 8; i++, j += 8) { printk(KERN_DEBUG "%02x %02x %02x %02x %02x %02x %02x %02x\n", Data[j+0],Data[j+1],Data[j+2],Data[j+3], Data[j+4],Data[j+5],Data[j+6],Data[j+7]); } return;}#endifvoid tmsdev_term(struct net_device *dev){ struct net_local *tp; tp = netdev_priv(dev); dma_unmap_single(tp->pdev, tp->dmabuffer, sizeof(struct net_local), DMA_BIDIRECTIONAL);}int tmsdev_init(struct net_device *dev, struct device *pdev){ struct net_local *tms_local; memset(dev->priv, 0, sizeof(struct net_local)); tms_local = netdev_priv(dev); init_waitqueue_head(&tms_local->wait_for_tok_int); if (pdev->dma_mask) tms_local->dmalimit = *pdev->dma_mask; else return -ENOMEM; tms_local->pdev = pdev; tms_local->dmabuffer = dma_map_single(pdev, (void *)tms_local, sizeof(struct net_local), DMA_BIDIRECTIONAL); if (tms_local->dmabuffer + sizeof(struct net_local) > tms_local->dmalimit) { printk(KERN_INFO "%s: Memory not accessible for DMA\n", dev->name); tmsdev_term(dev); return -ENOMEM; } /* These can be overridden by the card driver if needed */ dev->open = tms380tr_open; dev->stop = tms380tr_close; dev->do_ioctl = NULL; dev->hard_start_xmit = tms380tr_send_packet; dev->tx_timeout = tms380tr_timeout; dev->watchdog_timeo = HZ; dev->get_stats = tms380tr_get_stats; dev->set_multicast_list = &tms380tr_set_multicast_list; dev->set_mac_address = tms380tr_set_mac_address; return 0;}EXPORT_SYMBOL(tms380tr_open);EXPORT_SYMBOL(tms380tr_close);EXPORT_SYMBOL(tms380tr_interrupt);EXPORT_SYMBOL(tmsdev_init);EXPORT_SYMBOL(tmsdev_term);EXPORT_SYMBOL(tms380tr_wait);#ifdef MODULEstatic struct module *TMS380_module = NULL;int init_module(void){ printk(KERN_DEBUG "%s", version); TMS380_module = &__this_module; return 0;}void cleanup_module(void){ TMS380_module = NULL;}#endifMODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -