📄 ipw2100.c
字号:
aligned_len = len & (~0x3); for (i = 0; i < aligned_len; i += 4, buf += 4, aligned_addr += 4) read_register(dev, IPW_REG_AUTOINCREMENT_DATA, (u32 *) buf); /* copy the last nibble */ dif_len = len - aligned_len; write_register(dev, IPW_REG_INDIRECT_ACCESS_ADDRESS, aligned_addr); for (i = 0; i < dif_len; i++, buf++) read_register_byte(dev, IPW_REG_INDIRECT_ACCESS_DATA + i, buf);}static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev){ return (dev->base_addr && (readl ((void __iomem *)(dev->base_addr + IPW_REG_DOA_DEBUG_AREA_START)) == IPW_DATA_DOA_DEBUG_VALUE));}static int ipw2100_get_ordinal(struct ipw2100_priv *priv, u32 ord, void *val, u32 * len){ struct ipw2100_ordinals *ordinals = &priv->ordinals; u32 addr; u32 field_info; u16 field_len; u16 field_count; u32 total_length; if (ordinals->table1_addr == 0) { printk(KERN_WARNING DRV_NAME ": attempt to use fw ordinals " "before they have been loaded.\n"); return -EINVAL; } if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) { if (*len < IPW_ORD_TAB_1_ENTRY_SIZE) { *len = IPW_ORD_TAB_1_ENTRY_SIZE; printk(KERN_WARNING DRV_NAME ": ordinal buffer length too small, need %zd\n", IPW_ORD_TAB_1_ENTRY_SIZE); return -EINVAL; } read_nic_dword(priv->net_dev, ordinals->table1_addr + (ord << 2), &addr); read_nic_dword(priv->net_dev, addr, val); *len = IPW_ORD_TAB_1_ENTRY_SIZE; return 0; } if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) { ord -= IPW_START_ORD_TAB_2; /* get the address of statistic */ read_nic_dword(priv->net_dev, ordinals->table2_addr + (ord << 3), &addr); /* get the second DW of statistics ; * two 16-bit words - first is length, second is count */ read_nic_dword(priv->net_dev, ordinals->table2_addr + (ord << 3) + sizeof(u32), &field_info); /* get each entry length */ field_len = *((u16 *) & field_info); /* get number of entries */ field_count = *(((u16 *) & field_info) + 1); /* abort if no enought memory */ total_length = field_len * field_count; if (total_length > *len) { *len = total_length; return -EINVAL; } *len = total_length; if (!total_length) return 0; /* read the ordinal data from the SRAM */ read_nic_memory(priv->net_dev, addr, total_length, val); return 0; } printk(KERN_WARNING DRV_NAME ": ordinal %d neither in table 1 nor " "in table 2\n", ord); return -EINVAL;}static int ipw2100_set_ordinal(struct ipw2100_priv *priv, u32 ord, u32 * val, u32 * len){ struct ipw2100_ordinals *ordinals = &priv->ordinals; u32 addr; if (IS_ORDINAL_TABLE_ONE(ordinals, ord)) { if (*len != IPW_ORD_TAB_1_ENTRY_SIZE) { *len = IPW_ORD_TAB_1_ENTRY_SIZE; IPW_DEBUG_INFO("wrong size\n"); return -EINVAL; } read_nic_dword(priv->net_dev, ordinals->table1_addr + (ord << 2), &addr); write_nic_dword(priv->net_dev, addr, *val); *len = IPW_ORD_TAB_1_ENTRY_SIZE; return 0; } IPW_DEBUG_INFO("wrong table\n"); if (IS_ORDINAL_TABLE_TWO(ordinals, ord)) return -EINVAL; return -EINVAL;}static char *snprint_line(char *buf, size_t count, const u8 * data, u32 len, u32 ofs){ int out, i, j, l; char c; out = snprintf(buf, count, "%08X", ofs); for (l = 0, i = 0; i < 2; i++) { out += snprintf(buf + out, count - out, " "); for (j = 0; j < 8 && l < len; j++, l++) out += snprintf(buf + out, count - out, "%02X ", data[(i * 8 + j)]); for (; j < 8; j++) out += snprintf(buf + out, count - out, " "); } out += snprintf(buf + out, count - out, " "); for (l = 0, i = 0; i < 2; i++) { out += snprintf(buf + out, count - out, " "); for (j = 0; j < 8 && l < len; j++, l++) { c = data[(i * 8 + j)]; if (!isascii(c) || !isprint(c)) c = '.'; out += snprintf(buf + out, count - out, "%c", c); } for (; j < 8; j++) out += snprintf(buf + out, count - out, " "); } return buf;}static void printk_buf(int level, const u8 * data, u32 len){ char line[81]; u32 ofs = 0; if (!(ipw2100_debug_level & level)) return; while (len) { printk(KERN_DEBUG "%s\n", snprint_line(line, sizeof(line), &data[ofs], min(len, 16U), ofs)); ofs += 16; len -= min(len, 16U); }}#define MAX_RESET_BACKOFF 10static inline void schedule_reset(struct ipw2100_priv *priv){ unsigned long now = get_seconds(); /* If we haven't received a reset request within the backoff period, * then we can reset the backoff interval so this reset occurs * immediately */ if (priv->reset_backoff && (now - priv->last_reset > priv->reset_backoff)) priv->reset_backoff = 0; priv->last_reset = get_seconds(); if (!(priv->status & STATUS_RESET_PENDING)) { IPW_DEBUG_INFO("%s: Scheduling firmware restart (%ds).\n", priv->net_dev->name, priv->reset_backoff); netif_carrier_off(priv->net_dev); netif_stop_queue(priv->net_dev); priv->status |= STATUS_RESET_PENDING; if (priv->reset_backoff) queue_delayed_work(priv->workqueue, &priv->reset_work, priv->reset_backoff * HZ); else queue_work(priv->workqueue, &priv->reset_work); if (priv->reset_backoff < MAX_RESET_BACKOFF) priv->reset_backoff++; wake_up_interruptible(&priv->wait_command_queue); } else IPW_DEBUG_INFO("%s: Firmware restart already in progress.\n", priv->net_dev->name);}#define HOST_COMPLETE_TIMEOUT (2 * HZ)static int ipw2100_hw_send_command(struct ipw2100_priv *priv, struct host_command *cmd){ struct list_head *element; struct ipw2100_tx_packet *packet; unsigned long flags; int err = 0; IPW_DEBUG_HC("Sending %s command (#%d), %d bytes\n", command_types[cmd->host_command], cmd->host_command, cmd->host_command_length); printk_buf(IPW_DL_HC, (u8 *) cmd->host_command_parameters, cmd->host_command_length); spin_lock_irqsave(&priv->low_lock, flags); if (priv->fatal_error) { IPW_DEBUG_INFO ("Attempt to send command while hardware in fatal error condition.\n"); err = -EIO; goto fail_unlock; } if (!(priv->status & STATUS_RUNNING)) { IPW_DEBUG_INFO ("Attempt to send command while hardware is not running.\n"); err = -EIO; goto fail_unlock; } if (priv->status & STATUS_CMD_ACTIVE) { IPW_DEBUG_INFO ("Attempt to send command while another command is pending.\n"); err = -EBUSY; goto fail_unlock; } if (list_empty(&priv->msg_free_list)) { IPW_DEBUG_INFO("no available msg buffers\n"); goto fail_unlock; } priv->status |= STATUS_CMD_ACTIVE; priv->messages_sent++; element = priv->msg_free_list.next; packet = list_entry(element, struct ipw2100_tx_packet, list); packet->jiffy_start = jiffies; /* initialize the firmware command packet */ packet->info.c_struct.cmd->host_command_reg = cmd->host_command; packet->info.c_struct.cmd->host_command_reg1 = cmd->host_command1; packet->info.c_struct.cmd->host_command_len_reg = cmd->host_command_length; packet->info.c_struct.cmd->sequence = cmd->host_command_sequence; memcpy(packet->info.c_struct.cmd->host_command_params_reg, cmd->host_command_parameters, sizeof(packet->info.c_struct.cmd->host_command_params_reg)); list_del(element); DEC_STAT(&priv->msg_free_stat); list_add_tail(element, &priv->msg_pend_list); INC_STAT(&priv->msg_pend_stat); ipw2100_tx_send_commands(priv); ipw2100_tx_send_data(priv); spin_unlock_irqrestore(&priv->low_lock, flags); /* * We must wait for this command to complete before another * command can be sent... but if we wait more than 3 seconds * then there is a problem. */ err = wait_event_interruptible_timeout(priv->wait_command_queue, !(priv-> status & STATUS_CMD_ACTIVE), HOST_COMPLETE_TIMEOUT); if (err == 0) { IPW_DEBUG_INFO("Command completion failed out after %dms.\n", 1000 * (HOST_COMPLETE_TIMEOUT / HZ)); priv->fatal_error = IPW2100_ERR_MSG_TIMEOUT; priv->status &= ~STATUS_CMD_ACTIVE; schedule_reset(priv); return -EIO; } if (priv->fatal_error) { printk(KERN_WARNING DRV_NAME ": %s: firmware fatal error\n", priv->net_dev->name); return -EIO; } /* !!!!! HACK TEST !!!!! * When lots of debug trace statements are enabled, the driver * doesn't seem to have as many firmware restart cycles... * * As a test, we're sticking in a 1/100s delay here */ schedule_timeout_uninterruptible(msecs_to_jiffies(10)); return 0; fail_unlock: spin_unlock_irqrestore(&priv->low_lock, flags); return err;}/* * Verify the values and data access of the hardware * No locks needed or used. No functions called. */static int ipw2100_verify(struct ipw2100_priv *priv){ u32 data1, data2; u32 address; u32 val1 = 0x76543210; u32 val2 = 0xFEDCBA98; /* Domain 0 check - all values should be DOA_DEBUG */ for (address = IPW_REG_DOA_DEBUG_AREA_START; address < IPW_REG_DOA_DEBUG_AREA_END; address += sizeof(u32)) { read_register(priv->net_dev, address, &data1); if (data1 != IPW_DATA_DOA_DEBUG_VALUE) return -EIO; } /* Domain 1 check - use arbitrary read/write compare */ for (address = 0; address < 5; address++) { /* The memory area is not used now */ write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32, val1); write_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36, val2); read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x32, &data1); read_register(priv->net_dev, IPW_REG_DOMAIN_1_OFFSET + 0x36, &data2); if (val1 == data1 && val2 == data2) return 0; } return -EIO;}/* * * Loop until the CARD_DISABLED bit is the same value as the * supplied parameter * * TODO: See if it would be more efficient to do a wait/wake * cycle and have the completion event trigger the wakeup * */#define IPW_CARD_DISABLE_COMPLETE_WAIT 100 // 100 millistatic int ipw2100_wait_for_card_state(struct ipw2100_priv *priv, int state){ int i; u32 card_state; u32 len = sizeof(card_state); int err; for (i = 0; i <= IPW_CARD_DISABLE_COMPLETE_WAIT * 1000; i += 50) { err = ipw2100_get_ordinal(priv, IPW_ORD_CARD_DISABLED, &card_state, &len); if (err) { IPW_DEBUG_INFO("Query of CARD_DISABLED ordinal " "failed.\n"); return 0; } /* We'll break out if either the HW state says it is * in the state we want, or if HOST_COMPLETE command * finishes */ if ((card_state == state) || ((priv->status & STATUS_ENABLED) ? IPW_HW_STATE_ENABLED : IPW_HW_STATE_DISABLED) == state) { if (state == IPW_HW_STATE_ENABLED) priv->status |= STATUS_ENABLED; else priv->status &= ~STATUS_ENABLED; return 0; } udelay(50); } IPW_DEBUG_INFO("ipw2100_wait_for_card_state to %s state timed out\n", state ? "DISABLED" : "ENABLED"); return -EIO;}/********************************************************************* Procedure : sw_reset_and_clock Purpose : Asserts s/w reset, asserts clock initialization and waits for clock stabilization ********************************************************************/static int sw_reset_and_clock(struct ipw2100_priv *priv){ int i; u32 r; // assert s/w reset write_register(priv->net_dev, IPW_REG_RESET_REG, IPW_AUX_HOST_RESET_REG_SW_RESET); // wait for clock stabilization for (i = 0; i < 1000; i++) { udelay(IPW_WAIT_RESET_ARC_COMPLETE_DELAY); // check clock ready bit read_register(priv->net_dev, IPW_REG_RESET_REG, &r); if (r & IPW_AUX_HOST_RESET_REG_PRINCETON_RESET) break; } if (i == 1000) return -EIO; // TODO: better error value /* set "initialization complete" bit to move adapter to * D0 state */ write_register(priv->net_dev, IPW_REG_GP_CNTRL, IPW_AUX_HOST_GP_CNTRL_BIT_INIT_DONE); /* wait for clock stabilization */ for (i = 0; i < 10000; i++) { udelay(IPW_WAIT_CLOCK_STABILIZATION_DELAY * 4); /* check clock ready bit */ read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r); if (r & IPW_AUX_HOST_GP_CNTRL_BIT_CLOCK_READY) break; } if (i == 10000) return -EIO; /* TODO: better error value */ /* set D0 standby bit */ read_register(priv->net_dev, IPW_REG_GP_CNTRL, &r); write_register(priv->net_dev, IPW_REG_GP_CNTRL, r | IPW_AUX_HOST_GP_CNTRL_BIT_HOST_ALLOWS_STANDBY); return 0;}/********************************************************************* Procedure : ipw2100_download_firmware Purpose : Initiaze adapter after power on. The sequence is: 1. assert s/w reset first! 2. awake clocks & wait for clock stabilization
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -