// SPDX-License-Identifier: GPL-2.0-or-later /****************************************************************************** * * (C)Copyright 1998,1999 SysKonnect, * a business unit of Schneider & Koch & Co. Datensysteme GmbH. * * See the file "skfddi.c" for further information. * * The information in this file is provided "AS IS" without warranty. * ******************************************************************************/ #define HWMTM #ifndef FDDI #define FDDI #endif #include "h/types.h" #include "h/fddi.h" #include "h/smc.h" #include "h/supern_2.h" #include "h/skfbiinc.h" /* ------------------------------------------------------------- DOCUMENTATION ------------------------------------------------------------- BEGIN_MANUAL_ENTRY(DOCUMENTATION) T B D END_MANUAL_ENTRY */ /* ------------------------------------------------------------- LOCAL VARIABLES: ------------------------------------------------------------- */ #ifdef COMMON_MB_POOL static SMbuf *mb_start; static SMbuf *mb_free; static int mb_init = FALSE ; static int call_count; #endif /* ------------------------------------------------------------- EXTERNE VARIABLES: ------------------------------------------------------------- */ #ifdef DEBUG #ifndef DEBUG_BRD extern struct smt_debug debug ; #endif #endif #ifdef NDIS_OS2 extern u_char offDepth ; extern u_char force_irq_pending ; #endif /* ------------------------------------------------------------- LOCAL FUNCTIONS: ------------------------------------------------------------- */ static void queue_llc_rx(struct s_smc *smc, SMbuf *mb); static void smt_to_llc(struct s_smc *smc, SMbuf *mb); static void init_txd_ring(struct s_smc *smc); static void init_rxd_ring(struct s_smc *smc); static void queue_txd_mb(struct s_smc *smc, SMbuf *mb); static u_long init_descr_ring(struct s_smc *smc, union s_fp_descr volatile *start, int count); static u_long repair_txd_ring(struct s_smc *smc, struct s_smt_tx_queue *queue); static u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue); static SMbuf* get_llc_rx(struct s_smc *smc); static SMbuf* get_txd_mb(struct s_smc *smc); static void mac_drv_clear_txd(struct s_smc *smc); /* ------------------------------------------------------------- EXTERNAL FUNCTIONS: ------------------------------------------------------------- */ /* The external SMT functions are listed in cmtdef.h */ extern void* mac_drv_get_space(struct s_smc *smc, unsigned int size); extern void* mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size); extern void mac_drv_fill_rxd(struct s_smc *smc); extern void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd); extern void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, int frag_count, int len); extern void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, int frag_count); extern void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, int frag_count); #ifdef USE_OS_CPY extern void hwm_cpy_rxd2mb(void); extern void hwm_cpy_txd2mb(void); #endif #ifdef ALL_RX_COMPLETE extern void mac_drv_all_receives_complete(void); #endif extern u_long mac_drv_virt2phys(struct s_smc *smc, void *virt); extern u_long dma_master(struct s_smc *smc, void *virt, int len, int flag); #ifdef NDIS_OS2 extern void post_proc(void); #else extern void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr, int flag); #endif extern int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead, int la_len); /* ------------------------------------------------------------- PUBLIC FUNCTIONS: ------------------------------------------------------------- */ void process_receive(struct s_smc *smc); void fddi_isr(struct s_smc *smc); void smt_free_mbuf(struct s_smc *smc, SMbuf *mb); void init_driver_fplus(struct s_smc *smc); void mac_drv_rx_mode(struct s_smc *smc, int mode); void init_fddi_driver(struct s_smc *smc, u_char *mac_addr); void mac_drv_clear_tx_queue(struct s_smc *smc); void mac_drv_clear_rx_queue(struct s_smc *smc); void hwm_tx_frag(struct s_smc *smc, char far *virt, u_long phys, int len, int frame_status); void hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len, int frame_status); int mac_drv_init(struct s_smc *smc); int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, int frame_len, int frame_status); u_int mac_drv_check_space(void); SMbuf* smt_get_mbuf(struct s_smc *smc); #ifdef DEBUG void mac_drv_debug_lev(struct s_smc *smc, int flag, int lev); #endif /* ------------------------------------------------------------- MACROS: ------------------------------------------------------------- */ #ifndef UNUSED #ifdef lint #define UNUSED … #else #define UNUSED(x) … #endif #endif #ifdef USE_CAN_ADDR #define MA … #define GROUP_ADDR_BIT … #else #define MA … #define GROUP_ADDR_BIT … #endif #define RXD_TXD_COUNT … #ifdef MB_OUTSIDE_SMC #define EXT_VIRT_MEM … #define EXT_VIRT_MEM_2 … #else #define EXT_VIRT_MEM … #endif /* * define critical read for 16 Bit drivers */ #if defined(NDIS_OS2) || defined(ODI2) #define CR_READ … #else #define CR_READ(var) … #endif #define IMASK_SLOW … /* ------------------------------------------------------------- INIT- AND SMT FUNCTIONS: ------------------------------------------------------------- */ /* * BEGIN_MANUAL_ENTRY(mac_drv_check_space) * u_int mac_drv_check_space() * * function DOWNCALL (drvsr.c) * This function calculates the needed non virtual * memory for MBufs, RxD and TxD descriptors etc. * needed by the driver. * * return u_int memory in bytes * * END_MANUAL_ENTRY */ u_int mac_drv_check_space(void) { … } /* * BEGIN_MANUAL_ENTRY(mac_drv_init) * void mac_drv_init(smc) * * function DOWNCALL (drvsr.c) * In this function the hardware module allocates it's * memory. * The operating system dependent module should call * mac_drv_init once, after the adatper is detected. * END_MANUAL_ENTRY */ int mac_drv_init(struct s_smc *smc) { … } /* * BEGIN_MANUAL_ENTRY(init_driver_fplus) * init_driver_fplus(smc) * * Sets hardware modul specific values for the mode register 2 * (e.g. the byte alignment for the received frames, the position of the * least significant byte etc.) * END_MANUAL_ENTRY */ void init_driver_fplus(struct s_smc *smc) { … } static u_long init_descr_ring(struct s_smc *smc, union s_fp_descr volatile *start, int count) { … } static void init_txd_ring(struct s_smc *smc) { … } static void init_rxd_ring(struct s_smc *smc) { … } /* * BEGIN_MANUAL_ENTRY(init_fddi_driver) * void init_fddi_driver(smc,mac_addr) * * initializes the driver and it's variables * * END_MANUAL_ENTRY */ void init_fddi_driver(struct s_smc *smc, u_char *mac_addr) { … } SMbuf *smt_get_mbuf(struct s_smc *smc) { … } void smt_free_mbuf(struct s_smc *smc, SMbuf *mb) { … } /* * BEGIN_MANUAL_ENTRY(mac_drv_repair_descr) * void mac_drv_repair_descr(smc) * * function called from SMT (HWM / hwmtm.c) * The BMU is idle when this function is called. * Mac_drv_repair_descr sets up the physical address * for all receive and transmit queues where the BMU * should continue. * It may be that the BMU was reseted during a fragmented * transfer. In this case there are some fragments which will * never completed by the BMU. The OWN bit of this fragments * must be switched to be owned by the host. * * Give a start command to the receive BMU. * Start the transmit BMUs if transmit frames pending. * * END_MANUAL_ENTRY */ void mac_drv_repair_descr(struct s_smc *smc) { … } static u_long repair_txd_ring(struct s_smc *smc, struct s_smt_tx_queue *queue) { … } /* * Repairs the receive descriptor ring and returns the physical address * where the BMU should continue working. * * o The physical address where the BMU was stopped has to be * determined. This is the next RxD after rx_curr_get with an OWN * bit set. * o The BMU should start working at beginning of the next frame. * RxDs with an OWN bit set but with a reset STF bit should be * skipped and owned by the driver (OWN = 0). */ static u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue) { … } /* ------------------------------------------------------------- INTERRUPT SERVICE ROUTINE: ------------------------------------------------------------- */ /* * BEGIN_MANUAL_ENTRY(fddi_isr) * void fddi_isr(smc) * * function DOWNCALL (drvsr.c) * interrupt service routine, handles the interrupt requests * generated by the FDDI adapter. * * NOTE: The operating system dependent module must guarantee that the * interrupts of the adapter are disabled when it calls fddi_isr. * * About the USE_BREAK_ISR mechanismn: * * The main requirement of this mechanismn is to force an timer IRQ when * leaving process_receive() with leave_isr set. process_receive() may * be called at any time from anywhere! * To be sure we don't miss such event we set 'force_irq' per default. * We have to force and Timer IRQ if 'smc->os.hwm.leave_isr' AND * 'force_irq' are set. 'force_irq' may be reset if a receive complete * IRQ is pending. * * END_MANUAL_ENTRY */ void fddi_isr(struct s_smc *smc) { … } /* ------------------------------------------------------------- RECEIVE FUNCTIONS: ------------------------------------------------------------- */ #ifndef NDIS_OS2 /* * BEGIN_MANUAL_ENTRY(mac_drv_rx_mode) * void mac_drv_rx_mode(smc,mode) * * function DOWNCALL (fplus.c) * Corresponding to the parameter mode, the operating system * dependent module can activate several receive modes. * * para mode = 1: RX_ENABLE_ALLMULTI enable all multicasts * = 2: RX_DISABLE_ALLMULTI disable "enable all multicasts" * = 3: RX_ENABLE_PROMISC enable promiscuous * = 4: RX_DISABLE_PROMISC disable promiscuous * = 5: RX_ENABLE_NSA enable rec. of all NSA frames * (disabled after 'driver reset' & 'set station address') * = 6: RX_DISABLE_NSA disable rec. of all NSA frames * * = 21: RX_ENABLE_PASS_SMT ( see description ) * = 22: RX_DISABLE_PASS_SMT ( " " ) * = 23: RX_ENABLE_PASS_NSA ( " " ) * = 24: RX_DISABLE_PASS_NSA ( " " ) * = 25: RX_ENABLE_PASS_DB ( " " ) * = 26: RX_DISABLE_PASS_DB ( " " ) * = 27: RX_DISABLE_PASS_ALL ( " " ) * = 28: RX_DISABLE_LLC_PROMISC ( " " ) * = 29: RX_ENABLE_LLC_PROMISC ( " " ) * * * RX_ENABLE_PASS_SMT / RX_DISABLE_PASS_SMT * * If the operating system dependent module activates the * mode RX_ENABLE_PASS_SMT, the hardware module * duplicates all SMT frames with the frame control * FC_SMT_INFO and passes them to the LLC receive channel * by calling mac_drv_rx_init. * The SMT Frames which are sent by the local SMT and the NSA * frames whose A- and C-Indicator is not set are also duplicated * and passed. * The receive mode RX_DISABLE_PASS_SMT disables the passing * of SMT frames. * * RX_ENABLE_PASS_NSA / RX_DISABLE_PASS_NSA * * If the operating system dependent module activates the * mode RX_ENABLE_PASS_NSA, the hardware module * duplicates all NSA frames with frame control FC_SMT_NSA * and a set A-Indicator and passed them to the LLC * receive channel by calling mac_drv_rx_init. * All NSA Frames which are sent by the local SMT * are also duplicated and passed. * The receive mode RX_DISABLE_PASS_NSA disables the passing * of NSA frames with the A- or C-Indicator set. * * NOTE: For fear that the hardware module receives NSA frames with * a reset A-Indicator, the operating system dependent module * has to call mac_drv_rx_mode with the mode RX_ENABLE_NSA * before activate the RX_ENABLE_PASS_NSA mode and after every * 'driver reset' and 'set station address'. * * RX_ENABLE_PASS_DB / RX_DISABLE_PASS_DB * * If the operating system dependent module activates the * mode RX_ENABLE_PASS_DB, direct BEACON frames * (FC_BEACON frame control) are passed to the LLC receive * channel by mac_drv_rx_init. * The receive mode RX_DISABLE_PASS_DB disables the passing * of direct BEACON frames. * * RX_DISABLE_PASS_ALL * * Disables all special receives modes. It is equal to * call mac_drv_set_rx_mode successively with the * parameters RX_DISABLE_NSA, RX_DISABLE_PASS_SMT, * RX_DISABLE_PASS_NSA and RX_DISABLE_PASS_DB. * * RX_ENABLE_LLC_PROMISC * * (default) all received LLC frames and all SMT/NSA/DBEACON * frames depending on the attitude of the flags * PASS_SMT/PASS_NSA/PASS_DBEACON will be delivered to the * LLC layer * * RX_DISABLE_LLC_PROMISC * * all received SMT/NSA/DBEACON frames depending on the * attitude of the flags PASS_SMT/PASS_NSA/PASS_DBEACON * will be delivered to the LLC layer. * all received LLC frames with a directed address, Multicast * or Broadcast address will be delivered to the LLC * layer too. * * END_MANUAL_ENTRY */ void mac_drv_rx_mode(struct s_smc *smc, int mode) { … } #endif /* ifndef NDIS_OS2 */ /* * process receive queue */ void process_receive(struct s_smc *smc) { … } static void smt_to_llc(struct s_smc *smc, SMbuf *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(struct s_smc *smc, char far *virt, u_long phys, int len, int frame_status) { … } /* * 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(struct s_smc *smc) { … } /* ------------------------------------------------------------- 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(struct s_smc *smc, u_char fc, int frag_count, int frame_len, int 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(struct s_smc *smc, char far *virt, u_long phys, int len, int frame_status) { … } /* * queues a receive for later send */ static void queue_llc_rx(struct s_smc *smc, SMbuf *mb) { … } /* * get a SMbuf from the llc_rx_queue */ static SMbuf *get_llc_rx(struct s_smc *smc) { … } /* * queues a transmit SMT MBuf during the time were the MBuf is * queued the TxD ring */ static void queue_txd_mb(struct s_smc *smc, SMbuf *mb) { … } /* * get a SMbuf from the txd_tx_queue */ static SMbuf *get_txd_mb(struct s_smc *smc) { … } /* * SMT Send function */ void smt_send_mbuf(struct s_smc *smc, SMbuf *mb, int fc) { … } /* BEGIN_MANUAL_ENTRY(mac_drv_clear_txd) * void mac_drv_clear_txd(smc) * * function DOWNCALL (hardware module, hwmtm.c) * mac_drv_clear_txd searches in both send queues for TxD's * which were finished by the adapter. It calls dma_complete * for each TxD. If the last fragment of an LLC frame is * reached, it calls mac_drv_tx_complete to release the * send buffer. * * return nothing * * END_MANUAL_ENTRY */ static void mac_drv_clear_txd(struct s_smc *smc) { … } /* * BEGINN_MANUAL_ENTRY(mac_drv_clear_tx_queue) * * void mac_drv_clear_tx_queue(smc) * struct s_smc *smc ; * * function DOWNCALL (hardware module, hwmtm.c) * mac_drv_clear_tx_queue is called from the SMT when * the RMT state machine has entered the ISOLATE state. * This function is also called by the os-specific module * after it has called the function card_stop(). * In this case, the frames in the send queues are obsolete and * should be removed. * * note calling sequence: * 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_tx_queue(struct s_smc *smc) { … } /* ------------------------------------------------------------- TEST FUNCTIONS: ------------------------------------------------------------- */ #ifdef DEBUG /* * BEGIN_MANUAL_ENTRY(mac_drv_debug_lev) * void mac_drv_debug_lev(smc,flag,lev) * * function DOWNCALL (drvsr.c) * To get a special debug info the user can assign a debug level * to any debug flag. * * para flag debug flag, possible values are: * = 0: reset all debug flags (the defined level is * ignored) * = 1: debug.d_smtf * = 2: debug.d_smt * = 3: debug.d_ecm * = 4: debug.d_rmt * = 5: debug.d_cfm * = 6: debug.d_pcm * * = 10: debug.d_os.hwm_rx (hardware module receive path) * = 11: debug.d_os.hwm_tx(hardware module transmit path) * = 12: debug.d_os.hwm_gen(hardware module general flag) * * lev debug level * * END_MANUAL_ENTRY */ void mac_drv_debug_lev(struct s_smc *smc, int flag, int lev) { switch(flag) { case (int)NULL: DB_P.d_smtf = DB_P.d_smt = DB_P.d_ecm = DB_P.d_rmt = 0 ; DB_P.d_cfm = 0 ; DB_P.d_os.hwm_rx = DB_P.d_os.hwm_tx = DB_P.d_os.hwm_gen = 0 ; #ifdef SBA DB_P.d_sba = 0 ; #endif #ifdef ESS DB_P.d_ess = 0 ; #endif break ; case DEBUG_SMTF: DB_P.d_smtf = lev ; break ; case DEBUG_SMT: DB_P.d_smt = lev ; break ; case DEBUG_ECM: DB_P.d_ecm = lev ; break ; case DEBUG_RMT: DB_P.d_rmt = lev ; break ; case DEBUG_CFM: DB_P.d_cfm = lev ; break ; case DEBUG_PCM: DB_P.d_pcm = lev ; break ; case DEBUG_SBA: #ifdef SBA DB_P.d_sba = lev ; #endif break ; case DEBUG_ESS: #ifdef ESS DB_P.d_ess = lev ; #endif break ; case DB_HWM_RX: DB_P.d_os.hwm_rx = lev ; break ; case DB_HWM_TX: DB_P.d_os.hwm_tx = lev ; break ; case DB_HWM_GEN: DB_P.d_os.hwm_gen = lev ; break ; default: break ; } } #endif