📄 ipw2100.c
字号:
3. hold ARC (don't ask me why...) 4. load Dino ucode and reset/clock init again 5. zero-out shared mem 6. download f/w *******************************************************************/static int ipw2100_download_firmware(struct ipw2100_priv *priv){ u32 address; int err;#ifndef CONFIG_PM /* Fetch the firmware and microcode */ struct ipw2100_fw ipw2100_firmware;#endif if (priv->fatal_error) { IPW_DEBUG_ERROR("%s: ipw2100_download_firmware called after " "fatal error %d. Interface must be brought down.\n", priv->net_dev->name, priv->fatal_error); return -EINVAL; }#ifdef CONFIG_PM if (!ipw2100_firmware.version) { err = ipw2100_get_firmware(priv, &ipw2100_firmware); if (err) { IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n", priv->net_dev->name, err); priv->fatal_error = IPW2100_ERR_FW_LOAD; goto fail; } }#else err = ipw2100_get_firmware(priv, &ipw2100_firmware); if (err) { IPW_DEBUG_ERROR("%s: ipw2100_get_firmware failed: %d\n", priv->net_dev->name, err); priv->fatal_error = IPW2100_ERR_FW_LOAD; goto fail; }#endif priv->firmware_version = ipw2100_firmware.version; /* s/w reset and clock stabilization */ err = sw_reset_and_clock(priv); if (err) { IPW_DEBUG_ERROR("%s: sw_reset_and_clock failed: %d\n", priv->net_dev->name, err); goto fail; } err = ipw2100_verify(priv); if (err) { IPW_DEBUG_ERROR("%s: ipw2100_verify failed: %d\n", priv->net_dev->name, err); goto fail; } /* Hold ARC */ write_nic_dword(priv->net_dev, IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x80000000); /* allow ARC to run */ write_register(priv->net_dev, IPW_REG_RESET_REG, 0); /* load microcode */ err = ipw2100_ucode_download(priv, &ipw2100_firmware); if (err) { printk(KERN_ERR DRV_NAME ": %s: Error loading microcode: %d\n", priv->net_dev->name, err); goto fail; } /* release ARC */ write_nic_dword(priv->net_dev, IPW_INTERNAL_REGISTER_HALT_AND_RESET, 0x00000000); /* s/w reset and clock stabilization (again!!!) */ err = sw_reset_and_clock(priv); if (err) { printk(KERN_ERR DRV_NAME ": %s: sw_reset_and_clock failed: %d\n", priv->net_dev->name, err); goto fail; } /* load f/w */ err = ipw2100_fw_download(priv, &ipw2100_firmware); if (err) { IPW_DEBUG_ERROR("%s: Error loading firmware: %d\n", priv->net_dev->name, err); goto fail; }#ifndef CONFIG_PM /* * When the .resume method of the driver is called, the other * part of the system, i.e. the ide driver could still stay in * the suspend stage. This prevents us from loading the firmware * from the disk. --YZ */ /* free any storage allocated for firmware image */ ipw2100_release_firmware(priv, &ipw2100_firmware);#endif /* zero out Domain 1 area indirectly (Si requirement) */ for (address = IPW_HOST_FW_SHARED_AREA0; address < IPW_HOST_FW_SHARED_AREA0_END; address += 4) write_nic_dword(priv->net_dev, address, 0); for (address = IPW_HOST_FW_SHARED_AREA1; address < IPW_HOST_FW_SHARED_AREA1_END; address += 4) write_nic_dword(priv->net_dev, address, 0); for (address = IPW_HOST_FW_SHARED_AREA2; address < IPW_HOST_FW_SHARED_AREA2_END; address += 4) write_nic_dword(priv->net_dev, address, 0); for (address = IPW_HOST_FW_SHARED_AREA3; address < IPW_HOST_FW_SHARED_AREA3_END; address += 4) write_nic_dword(priv->net_dev, address, 0); for (address = IPW_HOST_FW_INTERRUPT_AREA; address < IPW_HOST_FW_INTERRUPT_AREA_END; address += 4) write_nic_dword(priv->net_dev, address, 0); return 0; fail: ipw2100_release_firmware(priv, &ipw2100_firmware); return err;}static inline void ipw2100_enable_interrupts(struct ipw2100_priv *priv){ if (priv->status & STATUS_INT_ENABLED) return; priv->status |= STATUS_INT_ENABLED; write_register(priv->net_dev, IPW_REG_INTA_MASK, IPW_INTERRUPT_MASK);}static inline void ipw2100_disable_interrupts(struct ipw2100_priv *priv){ if (!(priv->status & STATUS_INT_ENABLED)) return; priv->status &= ~STATUS_INT_ENABLED; write_register(priv->net_dev, IPW_REG_INTA_MASK, 0x0);}static void ipw2100_initialize_ordinals(struct ipw2100_priv *priv){ struct ipw2100_ordinals *ord = &priv->ordinals; IPW_DEBUG_INFO("enter\n"); read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_1, &ord->table1_addr); read_register(priv->net_dev, IPW_MEM_HOST_SHARED_ORDINALS_TABLE_2, &ord->table2_addr); read_nic_dword(priv->net_dev, ord->table1_addr, &ord->table1_size); read_nic_dword(priv->net_dev, ord->table2_addr, &ord->table2_size); ord->table2_size &= 0x0000FFFF; IPW_DEBUG_INFO("table 1 size: %d\n", ord->table1_size); IPW_DEBUG_INFO("table 2 size: %d\n", ord->table2_size); IPW_DEBUG_INFO("exit\n");}static inline void ipw2100_hw_set_gpio(struct ipw2100_priv *priv){ u32 reg = 0; /* * Set GPIO 3 writable by FW; GPIO 1 writable * by driver and enable clock */ reg = (IPW_BIT_GPIO_GPIO3_MASK | IPW_BIT_GPIO_GPIO1_ENABLE | IPW_BIT_GPIO_LED_OFF); write_register(priv->net_dev, IPW_REG_GPIO, reg);}static inline int rf_kill_active(struct ipw2100_priv *priv){#define MAX_RF_KILL_CHECKS 5#define RF_KILL_CHECK_DELAY 40 unsigned short value = 0; u32 reg = 0; int i; if (!(priv->hw_features & HW_FEATURE_RFKILL)) { priv->status &= ~STATUS_RF_KILL_HW; return 0; } for (i = 0; i < MAX_RF_KILL_CHECKS; i++) { udelay(RF_KILL_CHECK_DELAY); read_register(priv->net_dev, IPW_REG_GPIO, ®); value = (value << 1) | ((reg & IPW_BIT_GPIO_RF_KILL) ? 0 : 1); } if (value == 0) priv->status |= STATUS_RF_KILL_HW; else priv->status &= ~STATUS_RF_KILL_HW; return (value == 0);}static int ipw2100_get_hw_features(struct ipw2100_priv *priv){ u32 addr, len; u32 val; /* * EEPROM_SRAM_DB_START_ADDRESS using ordinal in ordinal table 1 */ len = sizeof(addr); if (ipw2100_get_ordinal (priv, IPW_ORD_EEPROM_SRAM_DB_BLOCK_START_ADDRESS, &addr, &len)) { IPW_DEBUG_INFO("failed querying ordinals at line %d\n", __LINE__); return -EIO; } IPW_DEBUG_INFO("EEPROM address: %08X\n", addr); /* * EEPROM version is the byte at offset 0xfd in firmware * We read 4 bytes, then shift out the byte we actually want */ read_nic_dword(priv->net_dev, addr + 0xFC, &val); priv->eeprom_version = (val >> 24) & 0xFF; IPW_DEBUG_INFO("EEPROM version: %d\n", priv->eeprom_version); /* * HW RF Kill enable is bit 0 in byte at offset 0x21 in firmware * * notice that the EEPROM bit is reverse polarity, i.e. * bit = 0 signifies HW RF kill switch is supported * bit = 1 signifies HW RF kill switch is NOT supported */ read_nic_dword(priv->net_dev, addr + 0x20, &val); if (!((val >> 24) & 0x01)) priv->hw_features |= HW_FEATURE_RFKILL; IPW_DEBUG_INFO("HW RF Kill: %ssupported.\n", (priv->hw_features & HW_FEATURE_RFKILL) ? "" : "not "); return 0;}/* * Start firmware execution after power on and intialization * The sequence is: * 1. Release ARC * 2. Wait for f/w initialization completes; */static int ipw2100_start_adapter(struct ipw2100_priv *priv){ int i; u32 inta, inta_mask, gpio; IPW_DEBUG_INFO("enter\n"); if (priv->status & STATUS_RUNNING) return 0; /* * Initialize the hw - drive adapter to DO state by setting * init_done bit. Wait for clk_ready bit and Download * fw & dino ucode */ if (ipw2100_download_firmware(priv)) { printk(KERN_ERR DRV_NAME ": %s: Failed to power on the adapter.\n", priv->net_dev->name); return -EIO; } /* Clear the Tx, Rx and Msg queues and the r/w indexes * in the firmware RBD and TBD ring queue */ ipw2100_queues_initialize(priv); ipw2100_hw_set_gpio(priv); /* TODO -- Look at disabling interrupts here to make sure none * get fired during FW initialization */ /* Release ARC - clear reset bit */ write_register(priv->net_dev, IPW_REG_RESET_REG, 0); /* wait for f/w intialization complete */ IPW_DEBUG_FW("Waiting for f/w initialization to complete...\n"); i = 5000; do { schedule_timeout_uninterruptible(msecs_to_jiffies(40)); /* Todo... wait for sync command ... */ read_register(priv->net_dev, IPW_REG_INTA, &inta); /* check "init done" bit */ if (inta & IPW2100_INTA_FW_INIT_DONE) { /* reset "init done" bit */ write_register(priv->net_dev, IPW_REG_INTA, IPW2100_INTA_FW_INIT_DONE); break; } /* check error conditions : we check these after the firmware * check so that if there is an error, the interrupt handler * will see it and the adapter will be reset */ if (inta & (IPW2100_INTA_FATAL_ERROR | IPW2100_INTA_PARITY_ERROR)) { /* clear error conditions */ write_register(priv->net_dev, IPW_REG_INTA, IPW2100_INTA_FATAL_ERROR | IPW2100_INTA_PARITY_ERROR); } } while (i--); /* Clear out any pending INTAs since we aren't supposed to have * interrupts enabled at this point... */ read_register(priv->net_dev, IPW_REG_INTA, &inta); read_register(priv->net_dev, IPW_REG_INTA_MASK, &inta_mask); inta &= IPW_INTERRUPT_MASK; /* Clear out any pending interrupts */ if (inta & inta_mask) write_register(priv->net_dev, IPW_REG_INTA, inta); IPW_DEBUG_FW("f/w initialization complete: %s\n", i ? "SUCCESS" : "FAILED"); if (!i) { printk(KERN_WARNING DRV_NAME ": %s: Firmware did not initialize.\n", priv->net_dev->name); return -EIO; } /* allow firmware to write to GPIO1 & GPIO3 */ read_register(priv->net_dev, IPW_REG_GPIO, &gpio); gpio |= (IPW_BIT_GPIO_GPIO1_MASK | IPW_BIT_GPIO_GPIO3_MASK); write_register(priv->net_dev, IPW_REG_GPIO, gpio); /* Ready to receive commands */ priv->status |= STATUS_RUNNING; /* The adapter has been reset; we are not associated */ priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED); IPW_DEBUG_INFO("exit\n"); return 0;}static inline void ipw2100_reset_fatalerror(struct ipw2100_priv *priv){ if (!priv->fatal_error) return; priv->fatal_errors[priv->fatal_index++] = priv->fatal_error; priv->fatal_index %= IPW2100_ERROR_QUEUE; priv->fatal_error = 0;}/* NOTE: Our interrupt is disabled when this method is called */static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv){ u32 reg; int i; IPW_DEBUG_INFO("Power cycling the hardware.\n"); ipw2100_hw_set_gpio(priv); /* Step 1. Stop Master Assert */ write_register(priv->net_dev, IPW_REG_RESET_REG, IPW_AUX_HOST_RESET_REG_STOP_MASTER); /* Step 2. Wait for stop Master Assert * (not more then 50us, otherwise ret error */ i = 5; do { udelay(IPW_WAIT_RESET_MASTER_ASSERT_COMPLETE_DELAY); read_register(priv->net_dev, IPW_REG_RESET_REG, ®); if (reg & IPW_AUX_HOST_RESET_REG_MASTER_DISABLED) break; } while (i--); priv->status &= ~STATUS_RESET_PENDING; if (!i) { IPW_DEBUG_INFO ("exit - waited too long for master assert stop\n"); return -EIO; } write_register(priv->net_dev, IPW_REG_RESET_REG, IPW_AUX_HOST_RESET_REG_SW_RESET); /* Reset any fatal_error conditions */ ipw2100_reset_fatalerror(priv); /* At this point, the adapter is now stopped and disabled */ priv->status &= ~(STATUS_RUNNING | STATUS_ASSOCIATING | STATUS_ASSOCIATED | STATUS_ENABLED); return 0;}/* * Send the CARD_DISABLE_PHY_OFF comamnd to the card to disable it * * After disabling, if the card was associated, a STATUS_ASSN_LOST will be sent. * * STATUS_CARD_DISABLE_NOTIFICATION will be sent regardless of * if STATUS_ASSN_LOST is sent. */static int ipw2100_hw_phy_off(struct ipw2100_priv *priv){#define HW_PHY_OFF_LOOP_DELAY (HZ / 5000) struct host_command cmd = { .host_command = CARD_DISABLE_PHY_OFF, .host_command_sequence = 0, .host_command_length = 0, }; int err, i; u32 val1, val2; IPW_DEBUG_HC("CARD_DISABLE_PHY_OFF\n"); /* Turn off the radio */ err = ipw2100_hw_send_command(priv, &cmd); if (err) return err; for (i = 0; i < 2500; i++) { read_nic_dword(priv->net_dev, IPW2100_CONTROL_REG, &val1); read_nic_dword(priv->net_dev, IPW2100_COMMAND, &val2); if ((val1 & IPW2100_CONTROL_PHY_OFF) && (val2 & IPW2100_COMMAND_PHY_OFF)) return 0; schedule_timeout_uninterruptible(HW_PHY_OFF_LOOP_DELAY); } return -EIO;}static int ipw2100_enable_adapter(struct ipw2100_priv *priv){ struct host_command cmd = { .host_command = HOST_COMPLETE, .host_command_sequence = 0, .host_command_length = 0 }; int err = 0; IPW_DEBUG_HC("HOST_COMPLETE\n"); if (priv->status & STATUS_ENABLED) return 0; down(&priv->adapter_sem); if (rf_kill_active(priv)) { IPW_DEBUG_HC("Command aborted due to RF kill active.\n"); goto fail_up; } err = ipw2100_hw_send_command(priv, &cmd); if (err) { IPW_DEBUG_INFO("Failed to send HOST_COMPLETE command\n"); goto fail_up;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -