📄 aironet4500_core.c
字号:
/* * Aironet 4500/4800 driver core * * Elmer Joandi, Januar 1999 * Copyright: GPL * * * Revision 0.1 ,started 30.12.1998 * * */ /* CHANGELOG: march 99, stable version 2.0 august 99, stable version 2.2 november 99, integration with 2.3 17.12.99: finally, got SMP near-correct. timing issues remain- on SMP box its 15% slower on tcp 10.03.00 looks like softnet take us back to normal on SMP */#include <linux/module.h>#include <linux/init.h>#include <linux/config.h>#include <linux/kernel.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <linux/if_arp.h>#include <linux/ioport.h>#include <asm/io.h>#include <asm/bitops.h>#include <asm/system.h>#include <asm/byteorder.h>#include <asm/irq.h>#include <linux/time.h>#include <linux/sched.h>#include <linux/delay.h>#include "aironet4500.h"#include <linux/ip.h>int bap_sleep = 10 ;int bap_sleep_after_setup = 1;int sleep_before_command = 1;int bap_sleep_before_write= 1;int sleep_in_command = 1;int both_bap_lock; /* activated at awc_init in this */int bap_setup_spinlock; /* file if numcpu >1 */EXPORT_SYMBOL(bap_sleep);EXPORT_SYMBOL(bap_sleep_after_setup);EXPORT_SYMBOL(sleep_before_command);EXPORT_SYMBOL(bap_sleep_before_write);EXPORT_SYMBOL(sleep_in_command);EXPORT_SYMBOL(both_bap_lock);EXPORT_SYMBOL(bap_setup_spinlock);struct awc_strings awc_status_error_codes[]=awc_reply_error_strings;struct awc_strings awc_command_names[]=awc_command_name_strings;struct awc_strings awc_link_status_names[]=awc_link_status_strings;struct awc_strings awc_rid_names[]=aironet4500_RID_Select_strings;struct awc_strings awc_link_failure_reason_names[]=IEEE_802_11_LINK_STATUS_FAILURE_REASON_STRINGS;const char * awc_print_string( struct awc_strings* strings, int code){ struct awc_strings * str = strings; int i = 0; while (str[i].string != NULL){ if (str[i].par == (code & str[i].mask )){ return str[i].string; }; i++; }; return "UNKNOWN";};int awc_dump_registers(struct net_device * dev){#ifdef AWC_DEBUG int i;#endif int status= inw(dev->base_addr +4*2); int r1= inw(dev->base_addr +5*2); int r2= inw(dev->base_addr +6*2); int r3= inw(dev->base_addr +7*2); printk(KERN_ERR "Command %s , result: %s, at memblk %x(RID %s) , offset %x \n", awc_print_string(awc_command_names,status), awc_print_string(awc_status_error_codes,r1), r2, awc_print_string(awc_rid_names,r2), r3);#ifdef AWC_DEBUG printk(KERN_ERR "%s aironet register dump ",dev->name ); for (i=0; i < 32; i++){ printk("%4x ", inw(dev->base_addr + i*2 ) ); if ( (i+1)%8 == 0){ printk("\n"); printk(KERN_ERR "%02x",(i+1)*2); } }; printk(KERN_ERR " \n");#endif return 0; }; /****************************** COMMAND ******************/inline int awc_command_busy_clear_wait(struct net_device * dev){// long long jiff = jiffies; u16 active_interrupts; int cnt= 0; AWC_ENTRY_EXIT_DEBUG(" entry awc_command_busy_clear_wait "); while (awc_command_busy(dev->base_addr)){ if (cnt > 1000 ){ printk(KERN_ERR "awc command busy too long, clearing\n"); awc_dump_registers(dev); awc_event_ack_ClrStckCmdBsy(dev->base_addr); break; }; if (((struct awc_private*) dev->priv)->ejected) return -1; cnt++; udelay(10); } cnt = 0; while (awc_command_busy(dev->base_addr)){ //if (jiffies - jiff > (HZ/3)){ if (cnt > 30000 ){ printk(KERN_CRIT "awc command busy WAY too long, clearing\n"); awc_dump_registers(dev); awc_event_ack_ClrStckCmdBsy(dev->base_addr); active_interrupts = awc_event_status(dev->base_addr); awc_event_ack(dev->base_addr, active_interrupts); AWC_ENTRY_EXIT_DEBUG("BAD exit\n "); return -1 ; }; if (((struct awc_private*) dev->priv)->ejected) return -1; cnt++; udelay(10); } AWC_ENTRY_EXIT_DEBUG(" exit\n "); return 0; };inline unsigned short awc_issue_command_and_block(struct awc_command * cmd){ int ticks; long long jiff; u16 enabled_interrupts; int cnt = 0;// unsigned long flags; jiff = jiffies; AWC_ENTRY_EXIT_DEBUG(" entry awc_issue_command_and_block "); AWC_LOCK_COMMAND_ISSUING(cmd->priv); if (awc_command_busy_clear_wait(cmd->dev)) goto final; if (cmd->priv->sleeping_bap) udelay(sleep_before_command); awc4500wout(cmd->port,cmd->command,cmd->par0,cmd->par1,cmd->par2);// awc_dump_registers(cmd->dev); if (cmd->priv->sleeping_bap) udelay(sleep_in_command); enabled_interrupts = awc_ints_enabled(cmd->dev->base_addr); awc_ints_enable(cmd->dev->base_addr, enabled_interrupts & ~0x10); if(cmd->priv->enabled_interrupts & 0x10) cmd->priv->enabled_interrupts &= ~0x10; while ( awc_command_read(cmd->port) == cmd->command) { udelay(1); awc_command_write(cmd->port, cmd->command); //if ((jiffies - jiff) > 2){ if (cnt > 2000 ){ printk(" long wait with commmand reg busy in blocking command \n"); awc_dump_registers(cmd->dev); goto final; }; if (cmd->priv->ejected) goto final; cnt++; udelay(10); }; AWC_ENTRY_EXIT_DEBUG(" issued " ); ticks = 0; while ( awc_event_status_Cmd(cmd->port) == 0) { ticks++; if (ticks > 100000){ printk(" long wait with commmand reg busy \n"); awc_dump_registers(cmd->dev); goto final; }; if (ticks > 500){ DEBUG(1, " long wait after issue 10mks * %d ", ticks ); //printk(" long wait with command reg busy about ticks\n"); // sti(); } if (cmd->priv->ejected) goto final; udelay(10); } if (cmd->priv->sleeping_bap) udelay(sleep_in_command); awc_read_response(cmd); AWC_ENTRY_EXIT_DEBUG(" resp read \n"); if (awc_command_busy(cmd->port)) awc_event_ack_ClrStckCmdBsy(cmd->port); awc_event_ack_Cmd(cmd->port); if (cmd->priv->sleeping_bap) udelay(sleep_in_command); if (cmd->status & 0xff00){ printk(KERN_ERR " bad response to command %s, parameter %x \n",awc_print_string(awc_command_names, cmd->command),cmd->par0); awc_dump_registers(cmd->dev); goto final; } AWC_UNLOCK_COMMAND_ISSUING(cmd->priv); AWC_ENTRY_EXIT_DEBUG(" exit \n"); udelay(1); return 0;final: AWC_UNLOCK_COMMAND_ISSUING(cmd->priv); AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); return -1; ;};inline unsigned short awc_issue_command(struct awc_command * cmd){// long long jiff = jiffies; // unsigned short enabled_ints; int cnt = 0;// int i=0; AWC_ENTRY_EXIT_DEBUG(" entry awc_issue_command"); if (!cmd){ printk(KERN_CRIT "cmd == NULL in awc_issue_command\n"); return -1; } if (!cmd->dev){ printk(KERN_CRIT "cmd->dev == NULL in awc_issue_command\n"); return -1; } AWC_LOCK_COMMAND_ISSUING(cmd->priv); if(awc_command_busy_clear_wait(cmd->dev)) goto final; if(!cmd->priv->enabled_interrupts & 0x10){ cmd->priv->enabled_interrupts |= 0x10; awc_ints_enable(cmd->port, cmd->priv->enabled_interrupts ); } cmd->priv->async_command_start = jiffies; cmd->priv->command_semaphore_on++; awc4500wout(cmd->port,cmd->command,cmd->par0,cmd->par1,cmd->par2); while ( awc_command_read(cmd->port) == cmd->command) { awc_command_write(cmd->port, cmd->command); //if ((jiffies - jiff) > 2){ if (cnt > 2000) { printk(" long wait with commmand reg busy in async command \n"); awc_dump_registers(cmd->dev); goto final; }; if (cmd->priv->ejected) goto final; cnt++; udelay(10); }; cmd->priv->cmd = *cmd; AWC_ENTRY_EXIT_DEBUG(" exit \n"); return 0; final: AWC_UNLOCK_COMMAND_ISSUING(cmd->priv); AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); return -1; ;};inline unsigned short awc_issue_command_no_ack(struct net_device * dev, u16 com, u16 par1, u16 par2, u16 par3){ struct awc_private * priv = (struct awc_private *)dev->priv; int cnt = 0; long long jiff; jiff = jiffies; AWC_ENTRY_EXIT_DEBUG(" entry awc_issue_command_no_ack "); AWC_LOCK_COMMAND_ISSUING(priv); if (awc_command_busy_clear_wait(dev)) { printk("aironet4x00 no_ack command (reset) with stuck card \n"); } awc4500wout(dev->base_addr,com, par1, par2,par3); udelay(10); while ( awc_event_status_Cmd(dev->base_addr) == 0) { if (awc_command_read(dev->base_addr) == com) { awc_command_write(dev->base_addr, com); } //if ((jiffies - jiff) > 2){ if (cnt > 2000) { printk(" long wait with commmand reg busy in noack command %d par %d %d %d\n",com,par1,par2,par3); awc_dump_registers(dev); goto final; }; if (priv->ejected) goto final; udelay(10); cnt++; } if (awc_command_busy(dev->base_addr)) awc_event_ack_ClrStckCmdBsy(dev->base_addr); AWC_UNLOCK_COMMAND_ISSUING(priv); AWC_ENTRY_EXIT_DEBUG(" exit \n"); return 0;final: AWC_UNLOCK_COMMAND_ISSUING(priv); AWC_ENTRY_EXIT_DEBUG(" BAD exit \n"); return -1; ;};/******************************** BAP *************************/// inline // too long for inlineint awc_bap_setup(struct awc_command * cmd) { int status; long long jiff; unsigned long flags; int cleared = 0; int cycles = 0; AWC_ENTRY_EXIT_DEBUG(" entry awc_bap_setup "); if ( cmd->priv->sleeping_bap) udelay(bap_sleep); if (cmd->priv->ejected) return -1; if (!cmd->bap || !(cmd->lock_state & (AWC_BAP_SEMALOCKED |AWC_BAP_LOCKED))) DEBUG(1,"no bap or bap not locked cmd %d !!", cmd->command); if (bap_setup_spinlock) my_spin_lock_irqsave(&cmd->priv->bap_setup_spinlock,cmd->priv->bap_setup_spinlock_flags); status = AWC_IN(cmd->bap->offset); if (status & ~0x2000 ){ WAIT61x3; status = AWC_IN(cmd->bap->offset); } if (status & ~0x2000 ){ WAIT61x3; AWC_IN(cmd->dev->base_addr + 0x26); AWC_OUT(cmd->dev->base_addr + 0x26, 0); WAIT61x3; udelay(60); #ifdef AWC_DEBUG printk("b"); #endif status = AWC_IN(cmd->bap->offset); } if (status & 0xC000){ printk(KERN_ERR "bap entered with err or busy bit set %x \n",status); if (cmd->bap->lock != 1) printk(KERN_ERR "bap lock bad same time %x\n",cmd->bap->lock); awc_dump_registers(cmd->dev); // AWC_OUT(cmd->bap->offset, 0x800); } save_flags(flags); cli(); AWC_OUT(cmd->bap->select, cmd->rid); WAIT61x3; AWC_OUT(cmd->bap->offset, cmd->offset); restore_flags(flags); WAIT61x3; jiff = jiffies; while (1) { cycles++; status = AWC_IN(cmd->bap->offset); if ( cmd->priv->sleeping_bap) udelay(bap_sleep); if (cmd->priv->ejected) goto ejected_unlock;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -