📄 wavelan.c
字号:
mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));#endif /* DOESNT_SEEM_TO_WORK */ /* Enable protected register. */ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); fee_wait(ioaddr, 10, 100); /* Unprotect area. */ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n); mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);#ifdef DOESNT_SEEM_TO_WORK /* disabled */ /* or use: */ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR);#endif /* DOESNT_SEEM_TO_WORK */ fee_wait(ioaddr, 10, 100);#endif /* EEPROM_IS_PROTECTED */ /* Write enable. */ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN); fee_wait(ioaddr, 10, 100); /* Write the EEPROM address. */ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); /* Loop on all buffer */ while (n-- > 0) { /* Write the value. */ mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF); /* Write the write command. */ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE); /* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */ mdelay(10); fee_wait(ioaddr, 10, 100); } /* Write disable. */ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); fee_wait(ioaddr, 10, 100);#ifdef EEPROM_IS_PROTECTED /* disabled */ /* Reprotect EEPROM. */ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00); mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); fee_wait(ioaddr, 10, 100);#endif /* EEPROM_IS_PROTECTED */}#endif /* WIRELESS_EXT *//************************ I82586 SUBROUTINES *************************//* * Useful subroutines to manage the Ethernet controller *//*------------------------------------------------------------------*//* * Read bytes from the on-board RAM. * Why does inlining this function make it fail? */static /*inline */ void obram_read(unsigned long ioaddr, u16 o, u8 * b, int n){ outw(o, PIOR1(ioaddr)); insw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1);}/*------------------------------------------------------------------*//* * Write bytes to the on-board RAM. */static inline void obram_write(unsigned long ioaddr, u16 o, u8 * b, int n){ outw(o, PIOR1(ioaddr)); outsw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1);}/*------------------------------------------------------------------*//* * Acknowledge the reading of the status issued by the i82586. */static void wv_ack(struct net_device * dev){ net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; u16 scb_cs; int i; obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), (unsigned char *) &scb_cs, sizeof(scb_cs)); scb_cs &= SCB_ST_INT; if (scb_cs == 0) return; obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *) &scb_cs, sizeof(scb_cs)); set_chan_attn(ioaddr, lp->hacr); for (i = 1000; i > 0; i--) { obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *) &scb_cs, sizeof(scb_cs)); if (scb_cs == 0) break; udelay(10); } udelay(100);#ifdef DEBUG_CONFIG_ERROR if (i <= 0) printk(KERN_INFO "%s: wv_ack(): board not accepting command.\n", dev->name);#endif}/*------------------------------------------------------------------*//* * Set channel attention bit and busy wait until command has * completed, then acknowledge completion of the command. */static inline int wv_synchronous_cmd(struct net_device * dev, const char *str){ net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; u16 scb_cmd; ach_t cb; int i; scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO; obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *) &scb_cmd, sizeof(scb_cmd)); set_chan_attn(ioaddr, lp->hacr); for (i = 1000; i > 0; i--) { obram_read(ioaddr, OFFSET_CU, (unsigned char *) &cb, sizeof(cb)); if (cb.ac_status & AC_SFLD_C) break; udelay(10); } udelay(100); if (i <= 0 || !(cb.ac_status & AC_SFLD_OK)) {#ifdef DEBUG_CONFIG_ERROR printk(KERN_INFO "%s: %s failed; status = 0x%x\n", dev->name, str, cb.ac_status);#endif#ifdef DEBUG_I82586_SHOW wv_scb_show(ioaddr);#endif return -1; } /* Ack the status */ wv_ack(dev); return 0;}/*------------------------------------------------------------------*//* * Configuration commands completion interrupt. * Check if done, and if OK. */static inline intwv_config_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp){ unsigned short mcs_addr; unsigned short status; int ret;#ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: ->wv_config_complete()\n", dev->name);#endif mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t) + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t); /* Read the status of the last command (set mc list). */ obram_read(ioaddr, acoff(mcs_addr, ac_status), (unsigned char *) &status, sizeof(status)); /* If not completed -> exit */ if ((status & AC_SFLD_C) == 0) ret = 0; /* Not ready to be scrapped */ else {#ifdef DEBUG_CONFIG_ERROR unsigned short cfg_addr; unsigned short ias_addr; /* Check mc_config command */ if ((status & AC_SFLD_OK) != AC_SFLD_OK) printk(KERN_INFO "%s: wv_config_complete(): set_multicast_address failed; status = 0x%x\n", dev->name, status); /* check ia-config command */ ias_addr = mcs_addr - sizeof(ac_ias_t); obram_read(ioaddr, acoff(ias_addr, ac_status), (unsigned char *) &status, sizeof(status)); if ((status & AC_SFLD_OK) != AC_SFLD_OK) printk(KERN_INFO "%s: wv_config_complete(): set_MAC_address failed; status = 0x%x\n", dev->name, status); /* Check config command. */ cfg_addr = ias_addr - sizeof(ac_cfg_t); obram_read(ioaddr, acoff(cfg_addr, ac_status), (unsigned char *) &status, sizeof(status)); if ((status & AC_SFLD_OK) != AC_SFLD_OK) printk(KERN_INFO "%s: wv_config_complete(): configure failed; status = 0x%x\n", dev->name, status);#endif /* DEBUG_CONFIG_ERROR */ ret = 1; /* Ready to be scrapped */ }#ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wv_config_complete() - %d\n", dev->name, ret);#endif return ret;}/*------------------------------------------------------------------*//* * Command completion interrupt. * Reclaim as many freed tx buffers as we can. * (called in wavelan_interrupt()). * Note : the spinlock is already grabbed for us. */static int wv_complete(struct net_device * dev, unsigned long ioaddr, net_local * lp){ int nreaped = 0;#ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: ->wv_complete()\n", dev->name);#endif /* Loop on all the transmit buffers */ while (lp->tx_first_in_use != I82586NULL) { unsigned short tx_status; /* Read the first transmit buffer */ obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), (unsigned char *) &tx_status, sizeof(tx_status)); /* If not completed -> exit */ if ((tx_status & AC_SFLD_C) == 0) break; /* Hack for reconfiguration */ if (tx_status == 0xFFFF) if (!wv_config_complete(dev, ioaddr, lp)) break; /* Not completed */ /* We now remove this buffer */ nreaped++; --lp->tx_n_in_use;/*if (lp->tx_n_in_use > 0) printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]);*/ /* Was it the last one? */ if (lp->tx_n_in_use <= 0) lp->tx_first_in_use = I82586NULL; else { /* Next one in the chain */ lp->tx_first_in_use += TXBLOCKZ; if (lp->tx_first_in_use >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) lp->tx_first_in_use -= NTXBLOCKS * TXBLOCKZ; } /* Hack for reconfiguration */ if (tx_status == 0xFFFF) continue; /* Now, check status of the finished command */ if (tx_status & AC_SFLD_OK) { int ncollisions; lp->stats.tx_packets++; ncollisions = tx_status & AC_SFLD_MAXCOL; lp->stats.collisions += ncollisions;#ifdef DEBUG_TX_INFO if (ncollisions > 0) printk(KERN_DEBUG "%s: wv_complete(): tx completed after %d collisions.\n", dev->name, ncollisions);#endif } else { lp->stats.tx_errors++; if (tx_status & AC_SFLD_S10) { lp->stats.tx_carrier_errors++;#ifdef DEBUG_TX_FAIL printk(KERN_DEBUG "%s: wv_complete(): tx error: no CS.\n", dev->name);#endif } if (tx_status & AC_SFLD_S9) { lp->stats.tx_carrier_errors++;#ifdef DEBUG_TX_FAIL printk(KERN_DEBUG "%s: wv_complete(): tx error: lost CTS.\n", dev->name);#endif } if (tx_status & AC_SFLD_S8) { lp->stats.tx_fifo_errors++;#ifdef DEBUG_TX_FAIL printk(KERN_DEBUG "%s: wv_complete(): tx error: slow DMA.\n", dev->name);#endif } if (tx_status & AC_SFLD_S6) { lp->stats.tx_heartbeat_errors++;#ifdef DEBUG_TX_FAIL printk(KERN_DEBUG "%s: wv_complete(): tx error: heart beat.\n", dev->name);#endif } if (tx_status & AC_SFLD_S5) { lp->stats.tx_aborted_errors++;#ifdef DEBUG_TX_FAIL printk(KERN_DEBUG "%s: wv_complete(): tx error: too many collisions.\n", dev->name);#endif } }#ifdef DEBUG_TX_INFO printk(KERN_DEBUG "%s: wv_complete(): tx completed, tx_status 0x%04x\n", dev->name, tx_status);#endif }#ifdef DEBUG_INTERRUPT_INFO if (nreaped > 1) printk(KERN_DEBUG "%s: wv_complete(): reaped %d\n", dev->name, nreaped);#endif /* * Inform upper layers. */ if (lp->tx_n_in_use < NTXBLOCKS - 1) { netif_wake_queue(dev); }#ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wv_complete()\n", dev->name);#endif return nreaped;}/*------------------------------------------------------------------*//* * Reconfigure the i82586, or at least ask for it. * Because wv_82586_config uses a transmission buffer, we must do it * when we are sure that there is one left, so we do it now * or in wavelan_packet_xmit() (I can't find any better place, * wavelan_interrupt is not an option), so you may experience * delays sometimes. */static inline void wv_82586_reconfig(struct net_device * dev){ net_local *lp = (net_local *) dev->priv; unsigned long flags; /* Arm the flag, will be cleard in wv_82586_config() */ lp->reconfig_82586 = 1; /* Check if we can do it now ! */ if((netif_running(dev)) && !(netif_queue_stopped(dev))) { spin_lock_irqsave(&lp->spinlock, flags); /* May fail */ wv_82586_config(dev); spin_unlock_irqrestore(&lp->spinlock, flags); } else {#ifdef DEBUG_CONFIG_INFO printk(KERN_DEBUG "%s: wv_82586_reconfig(): delayed (state = %lX)\n", dev->name, dev->state);#endif }}/********************* DEBUG & INFO SUBROUTINES *********************//* * This routine is used in the code to show information for debugging. * Most of the time, it dumps the contents of hardware structures. */#ifdef DEBUG_PSA_SHOW/*------------------------------------------------------------------*//* * Print the formatted contents of the Parameter Storage Area. */static void wv_psa_show(psa_t * p){ printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n"); printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", p->psa_io_base_addr_1, p->psa_io_base_addr_2, p->psa_io_base_addr_3, p->psa_io_base_addr_4); printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", p->psa_rem_boot_addr_1, p->psa_rem_boot_addr_2, p->psa_rem_boot_addr_3); printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); printk("psa_int_req_no: %d\n", p->psa_int_req_no);#ifdef DEBUG_SHOW_UNUSED printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n", p->psa_unused0[0], p->psa_unused0[1], p->psa_unused0[2], p->psa_unused0[3], p->psa_unused0[4], p->psa_unused0[5], p->psa_unused0[6]);#endif /* DEBUG_SHOW_UNUSED */ printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", p->psa_univ_mac_addr[0], p->psa_univ_mac_addr[1], p->psa_univ_mac_addr[2], p->psa_univ_mac_addr[3], p->psa_univ_mac_addr[4], p->psa_univ_mac_addr[5]); printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", p->psa_local_mac_addr[0], p->psa_local_mac_addr[1], p->psa_local_mac_addr[2], p->psa_local_mac_addr[3], p->psa_local_mac_addr[4], p->psa_local_mac_addr[5]); printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); printk("psa_comp_number: %d, ", p->psa_comp_number); printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -