📄 hwmtm.c
字号:
* current frame, search for the * EOF bit to complete the frame * else * the fragment belongs to the next frame, * exit the loop and process the frame */ SK_BREAK() ; rfsw = 0 ; if (frag_count) { break ; } } n += rbctrl & 0xffff ; r = r->rxd_next ; frag_count++ ; rx_used-- ; } while (!(rbctrl & BMU_EOF)) ; used_frags = frag_count ; DB_RX("EOF set in RxD, used_frags = %d ",used_frags,0,5) ; /* may be next 2 DRV_BUF_FLUSH() can be skipped, because */ /* BMU_ST_BUF will not be changed by the ASIC */ DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; while (rx_used && !(r->rxd_rbctrl & AIX_REVERSE(BMU_ST_BUF))) { DB_RX("Check STF bit in %x",(void *)r,0,5) ; r = r->rxd_next ; DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; frag_count++ ; rx_used-- ; } DB_RX("STF bit found",0,0,5) ; /* * The received frame is finished for the process receive */ rxd = queue->rx_curr_get ; queue->rx_curr_get = r ; queue->rx_free += frag_count ; queue->rx_used = rx_used ; /* * ASIC Errata no. 7 (STF - Bit Bug) */ rxd->rxd_rbctrl &= AIX_REVERSE(~BMU_STF) ; for (r=rxd, i=frag_count ; i ; r=r->rxd_next, i--){ DB_RX("dma_complete for RxD %x",(void *)r,0,5) ; dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR); } smc->hw.fp.err_stats.err_valid++ ; smc->mib.m[MAC0].fddiMACCopied_Ct++ ; /* the length of the data including the FC */ len = (rfsw & RD_LENGTH) - 4 ; DB_RX("frame length = %d",len,0,4) ; /* * check the frame_lenght and all error flags */ if (rfsw & (RX_MSRABT|RX_FS_E|RX_FS_CRC|RX_FS_IMPL)){ if (rfsw & RD_S_MSRABT) { DB_RX("Frame aborted by the FORMAC",0,0,2) ; smc->hw.fp.err_stats.err_abort++ ; } /* * check frame status */ if (rfsw & RD_S_SEAC2) { DB_RX("E-Indicator set",0,0,2) ; smc->hw.fp.err_stats.err_e_indicator++ ; } if (rfsw & RD_S_SFRMERR) { DB_RX("CRC error",0,0,2) ; smc->hw.fp.err_stats.err_crc++ ; } if (rfsw & RX_FS_IMPL) { DB_RX("Implementer frame",0,0,2) ; smc->hw.fp.err_stats.err_imp_frame++ ; } goto abort_frame ; } if (len > FDDI_RAW_MTU-4) { DB_RX("Frame to long error",0,0,2) ; smc->hw.fp.err_stats.err_too_long++ ; goto abort_frame ; } /* * SUPERNET 3 Bug: FORMAC delivers status words * of aborded frames to the BMU */ if (len <= 4) { DB_RX("Frame length = 0",0,0,2) ; goto abort_frame ; } if (len != (n-4)) { DB_RX("BMU: rx len differs: [%d:%d]",len,n,4); smc->os.hwm.rx_len_error++ ; goto abort_frame ; } /* * Check SA == MA */ virt = (u_char far *) rxd->rxd_virt ; DB_RX("FC = %x",*virt,0,2) ; if (virt[12] == MA[5] && virt[11] == MA[4] && virt[10] == MA[3] && virt[9] == MA[2] && virt[8] == MA[1] && (virt[7] & ~GROUP_ADDR_BIT) == MA[0]) { goto abort_frame ; } /* * test if LLC frame */ if (rfsw & RX_FS_LLC) { /* * if pass_llc_promisc is disable * if DA != Multicast or Broadcast or DA!=MA * abort the frame */ if (!smc->os.hwm.pass_llc_promisc) { if(!(virt[1] & GROUP_ADDR_BIT)) { if (virt[6] != MA[5] || virt[5] != MA[4] || virt[4] != MA[3] || virt[3] != MA[2] || virt[2] != MA[1] || virt[1] != MA[0]) { DB_RX("DA != MA and not multi- or broadcast",0,0,2) ; goto abort_frame ; } } } /* * LLC frame received */ DB_RX("LLC - receive",0,0,4) ; mac_drv_rx_complete(smc,rxd,frag_count,len) ; } else { if (!(mb = smt_get_mbuf(smc))) { smc->hw.fp.err_stats.err_no_buf++ ; DB_RX("No SMbuf; receive terminated",0,0,4) ; goto abort_frame ; } data = smtod(mb,char *) - 1 ; /* * copy the frame into a SMT_MBuf */#ifdef USE_OS_CPY hwm_cpy_rxd2mb(rxd,data,len) ;#else for (r=rxd, i=used_frags ; i ; r=r->rxd_next, i--){ n = AIX_REVERSE(r->rxd_rbctrl) & RD_LENGTH ; DB_RX("cp SMT frame to mb: len = %d",n,0,6) ; memcpy(data,r->rxd_virt,n) ; data += n ; } data = smtod(mb,char *) - 1 ;#endif fc = *(char *)mb->sm_data = *data ; mb->sm_len = len - 1 ; /* len - fc */ data++ ; /* * SMT frame received */ switch(fc) { case FC_SMT_INFO : smc->hw.fp.err_stats.err_smt_frame++ ; DB_RX("SMT frame received ",0,0,5) ; if (smc->os.hwm.pass_SMT) { DB_RX("pass SMT frame ",0,0,5) ; mac_drv_rx_complete(smc, rxd, frag_count,len) ; } else { DB_RX("requeue RxD",0,0,5) ; mac_drv_requeue_rxd(smc,rxd,frag_count); } smt_received_pack(smc,mb,(int)(rfsw>>25)) ; break ; case FC_SMT_NSA : smc->hw.fp.err_stats.err_smt_frame++ ; DB_RX("SMT frame received ",0,0,5) ; /* if pass_NSA set pass the NSA frame or */ /* pass_SMT set and the A-Indicator */ /* is not set, pass the NSA frame */ if (smc->os.hwm.pass_NSA || (smc->os.hwm.pass_SMT && !(rfsw & A_INDIC))) { DB_RX("pass SMT frame ",0,0,5) ; mac_drv_rx_complete(smc, rxd, frag_count,len) ; } else { DB_RX("requeue RxD",0,0,5) ; mac_drv_requeue_rxd(smc,rxd,frag_count); } smt_received_pack(smc,mb,(int)(rfsw>>25)) ; break ; case FC_BEACON : if (smc->os.hwm.pass_DB) { DB_RX("pass DB frame ",0,0,5) ; mac_drv_rx_complete(smc, rxd, frag_count,len) ; } else { DB_RX("requeue RxD",0,0,5) ; mac_drv_requeue_rxd(smc,rxd,frag_count); } smt_free_mbuf(smc,mb) ; break ; default : /* * unknown FC abord the frame */ DB_RX("unknown FC error",0,0,2) ; smt_free_mbuf(smc,mb) ; DB_RX("requeue RxD",0,0,5) ; mac_drv_requeue_rxd(smc,rxd,frag_count) ; if ((fc & 0xf0) == FC_MAC) smc->hw.fp.err_stats.err_mac_frame++ ; else smc->hw.fp.err_stats.err_imp_frame++ ; break ; } } DB_RX("next RxD is %x ",queue->rx_curr_get,0,3) ; NDD_TRACE("RHx1",queue->rx_curr_get,0,0) ; continue ; /*--------------------------------------------------------------------*/abort_frame: DB_RX("requeue RxD",0,0,5) ; mac_drv_requeue_rxd(smc,rxd,frag_count) ; DB_RX("next RxD is %x ",queue->rx_curr_get,0,3) ; NDD_TRACE("RHx2",queue->rx_curr_get,0,0) ; }rx_end:#ifdef ALL_RX_COMPLETE mac_drv_all_receives_complete(smc) ;#endif return ; /* lint bug: needs return detect end of function */}static void smt_to_llc(smc,mb)struct s_smc *smc ;SMbuf *mb ;{ u_char fc ; DB_RX("send a queued frame to the llc layer",0,0,4) ; smc->os.hwm.r.len = mb->sm_len ; smc->os.hwm.r.mb_pos = smtod(mb,char *) ; fc = *smc->os.hwm.r.mb_pos ; (void)mac_drv_rx_init(smc,(int)mb->sm_len,(int)fc, smc->os.hwm.r.mb_pos,(int)mb->sm_len) ; smt_free_mbuf(smc,mb) ;}/* * BEGIN_MANUAL_ENTRY(hwm_rx_frag) * void hwm_rx_frag(smc,virt,phys,len,frame_status) * * function MACRO (hardware module, hwmtm.h) * This function calls dma_master for preparing the * system hardware for the DMA transfer and initializes * the current RxD with the length and the physical and * virtual address of the fragment. Furthermore, it sets the * STF and EOF bits depending on the frame status byte, * switches the OWN flag of the RxD, so that it is owned by the * adapter and issues an rx_start. * * para virt virtual pointer to the fragment * len the length of the fragment * frame_status status of the frame, see design description * * NOTE: It is possible to call this function with a fragment length * of zero. * * END_MANUAL_ENTRY */void hwm_rx_frag(smc,virt,phys,len,frame_status)struct s_smc *smc ;char far *virt ;u_long phys ;int len ;int frame_status ;{ struct s_smt_fp_rxd volatile *r ; u_int rbctrl ; NDD_TRACE("RHfB",virt,len,frame_status) ; DB_RX("hwm_rx_frag: len = %d, frame_status = %x\n",len,frame_status,2) ; r = smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put ; r->rxd_virt = virt ; r->rxd_rbadr = AIX_REVERSE(phys) ; rbctrl = AIX_REVERSE( (((u_long)frame_status & (FIRST_FRAG|LAST_FRAG))<<26) | (((u_long) frame_status & FIRST_FRAG) << 21) | BMU_OWN | BMU_CHECK | BMU_EN_IRQ_EOF | len) ; r->rxd_rbctrl = rbctrl ; DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; outpd(ADDR(B0_R1_CSR),CSR_START) ; smc->hw.fp.rx_q[QUEUE_R1].rx_free-- ; smc->hw.fp.rx_q[QUEUE_R1].rx_used++ ; smc->hw.fp.rx_q[QUEUE_R1].rx_curr_put = r->rxd_next ; NDD_TRACE("RHfE",r,AIX_REVERSE(r->rxd_rbadr),0) ;}#ifndef NDIS_OS2/* * BEGIN_MANUAL_ENTRY(mac_drv_rx_frag) * int mac_drv_rx_frag(smc,virt,len) * * function DOWNCALL (hwmtm.c) * mac_drv_rx_frag fills the fragment with a part of the frame. * * para virt the virtual address of the fragment * len the length in bytes of the fragment * * return 0: success code, no errors possible * * END_MANUAL_ENTRY */int mac_drv_rx_frag(smc,virt,len)struct s_smc *smc ;void far *virt ;int len ;{ NDD_TRACE("RHSB",virt,len,smc->os.hwm.r.mb_pos) ; DB_RX("receive from queue: len/virt: = %d/%x",len,virt,4) ; memcpy((char far *)virt,smc->os.hwm.r.mb_pos,len) ; smc->os.hwm.r.mb_pos += len ; NDD_TRACE("RHSE",smc->os.hwm.r.mb_pos,0,0) ; return(0) ;}#endif/* * BEGINN_MANUAL_ENTRY(mac_drv_clear_rx_queue) * * void mac_drv_clear_rx_queue(smc) * struct s_smc *smc ; * * function DOWNCALL (hardware module, hwmtm.c) * mac_drv_clear_rx_queue is called by the OS-specific module * after it has issued a card_stop. * In this case, the frames in the receive queue are obsolete and * should be removed. For removing mac_drv_clear_rx_queue * calls dma_master for each RxD and mac_drv_clear_rxd for each * receive buffer. * * NOTE: calling sequence card_stop: * CLI_FBI(), card_stop(), * mac_drv_clear_tx_queue(), mac_drv_clear_rx_queue(), * * NOTE: The caller is responsible that the BMUs are idle * when this function is called. * * END_MANUAL_ENTRY */void mac_drv_clear_rx_queue(smc)struct s_smc *smc ;{ struct s_smt_fp_rxd volatile *r ; struct s_smt_fp_rxd volatile *next_rxd ; struct s_smt_rx_queue *queue ; int frag_count ; int i ; if (smc->hw.hw_state != STOPPED) { SK_BREAK() ; SMT_PANIC(smc,HWM_E0012,HWM_E0012_MSG) ; return ; } queue = smc->hw.fp.rx[QUEUE_R1] ; DB_RX("clear_rx_queue",0,0,5) ; /* * dma_complete and mac_drv_clear_rxd for all RxDs / receive buffers */ r = queue->rx_curr_get ; while (queue->rx_used) { DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; DB_RX("switch OWN bit of RxD 0x%x ",r,0,5) ; r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ; frag_count = 1 ; DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; r = r->rxd_next ; DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; while (r != queue->rx_curr_put && !(r->rxd_rbctrl & AIX_REVERSE(BMU_ST_BUF))) { DB_RX("Check STF bit in %x",(void *)r,0,5) ; r->rxd_rbctrl &= AIX_REVERSE(~BMU_OWN) ; DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; r = r->rxd_next ; DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; frag_count++ ; } DB_RX("STF bit found",0,0,5) ; next_rxd = r ; for (r=queue->rx_curr_get,i=frag_count; i ; r=r->rxd_next,i--){ DB_RX("dma_complete for RxD %x",(void *)r,0,5) ; dma_complete(smc,(union s_fp_descr volatile *)r,DMA_WR); } DB_RX("mac_drv_clear_rxd: RxD %x frag_count %d ", (void *)queue->rx_curr_get,frag_count,5) ; mac_drv_clear_rxd(smc,queue->rx_curr_get,frag_count) ; queue->rx_curr_get = next_rxd ; queue->rx_used -= frag_count ; queue->rx_free += frag_count ; }}/* ------------------------------------------------------------- SEND FUNCTIONS: -------------------------------------------------------------*//* * BEGIN_MANUAL_ENTRY(hwm_tx_init) * int hwm_tx_init(smc,fc,frag_count,frame_len,frame_status) * * function DOWN_CALL (hardware module, hwmtm.c) * hwm_tx_init checks if the frame can be sent through the * corresponding send queue. * * para fc the frame control. To determine through which * send queue the frame should be transmitted. * 0x50 - 0x57: asynchronous LLC frame * 0xD0 - 0xD7: synchronous LLC frame * 0x41, 0x4F: SMT frame to the network * 0x42: SMT frame to the network and to the local SMT * 0x43: SMT frame to the local SMT * frag_count count of the fragments for this frame * frame_len length of the frame * frame_status status of the frame, the send queue bit is already * specified * * return frame_status * * END_MANUAL_ENTRY */int hwm_tx_init(smc,fc,frag_count,frame_len,frame_status)struct s_smc *smc ;u_char fc ;int frag_count ;int frame_len ;int frame_status ;{ NDD_TRACE("THiB",fc,frag_count,frame_len) ; smc->os.hwm.tx_p = smc->hw.fp.tx[frame_status & QUEUE_A0] ; smc->os.hwm.tx_descr = TX_DESCRIPTOR | (((u_long)(frame_len-1)&3)<<27) ; smc->os.hwm.tx_len = frame_len ; DB_TX("hwm_tx_init: fc = %x, len = %d",fc,frame_len,3) ; if ((fc & ~(FC_SYNC_BIT|FC_LLC_PRIOR)) == FC_ASYNC_LLC) { frame_status |= LAN_TX ; } else { switch (fc) { case FC_SMT_INFO : case FC_SMT_NSA : frame_status |= LAN_TX ; break ; case FC_SMT_LOC : frame_status |= LOC_TX ; break ; case FC_SMT_LAN_LOC : frame_status |= LAN_TX | LOC_TX ; break ; default : SMT_PANIC(smc,HWM_E0010,HWM_E0010_MSG) ; } } if (!smc->hw.mac_ring_is_up) { frame_status &= ~LAN_TX ; frame_status |= RING_DOWN ; DB_TX("Ring is down: terminate LAN_TX",0,0,2) ; } if (frag_count > smc->os.hwm.tx_p->tx_free) {#ifndef NDIS_OS2 mac_drv_clear_txd(smc) ; if (frag_count > smc->os.hwm.tx_p->tx_free) { DB_TX("Out of TxDs, terminate LAN_TX",0,0,2) ; frame_status &= ~LAN_TX ; frame_status |= OUT_OF_TXD ; }#else DB_TX("Out of TxDs, terminate LAN_TX",0,0,2) ; frame_status &= ~LAN_TX ; frame_status |= OUT_OF_TXD ;#endif } DB_TX("frame_status = %x",frame_status,0,3) ; NDD_TRACE("THiE",frame_status,smc->os.hwm.tx_p->tx_free,0) ; return(frame_status) ;}/* * BEGIN_MANUAL_ENTRY(hwm_tx_frag) * void hwm_tx_frag(smc,virt,phys,len,frame_status) * * function DOWNCALL (hardware module, hwmtm.c) * If the frame should be sent to the LAN, this function calls * dma_master, fills the current TxD with the virtual and the * physical address, sets the STF and EOF bits dependent on * the frame status, and requests the BMU to start the * transmit. * If the frame should be sent to the local SMT, an SMT_MBuf * is allocated if the FIRST_FRAG bit is set in the frame_status. * The fragment of the frame is copied into the SMT MBuf. * The function smt_received_pack is called if the LAST_FRAG * bit is set in the frame_status word. * * para virt virtual pointer to the fragment * len the length of the fragment * frame_status status of the frame, see design description * * return nothing returned, no parameter is modified * * NOTE: It is possible to invoke this macro with a fragment length * of zero. * * END_MANUAL_ENTRY */void hwm_tx_frag(smc,virt,phys,len,frame_status)struct s_smc *smc ;char far *virt ;u_long phys ;int len ;int frame_status ;{ struct s_smt_fp_txd volatile *t ; struct s_smt_tx_queue *queue ; u_int tbctrl ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -