static ssize_t ieee80211_if_parse_tsf( struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) { struct ieee80211_local *local = sdata->local; unsigned long long tsf; int ret; if (strncmp(buf, "reset", 5) == 0) { if (local->ops->reset_tsf) { drv_reset_tsf(local, sdata); wiphy_info(local->hw.wiphy, "debugfs reset TSF\n"); } } else { ret = strict_strtoull(buf, 10, &tsf); if (ret < 0) return -EINVAL; if (local->ops->set_tsf) { drv_set_tsf(local, sdata, tsf); wiphy_info(local->hw.wiphy, "debugfs set TSF to %#018llx\n", tsf); } } return buflen; }
static ssize_t tsf_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct ieee80211_local *local = file->private_data; unsigned long long tsf; char buf[100]; size_t len; len = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, len)) return -EFAULT; buf[len] = '\0'; if (strncmp(buf, "reset", 5) == 0) { if (local->ops->reset_tsf) { drv_reset_tsf(local); wiphy_info(local->hw.wiphy, "debugfs reset TSF\n"); } } else { tsf = simple_strtoul(buf, NULL, 0); if (local->ops->set_tsf) { drv_set_tsf(local, tsf); wiphy_info(local->hw.wiphy, "debugfs set TSF to %#018llx\n", tsf); } } return count; }
static void carl9170_dbg_message(struct ar9170 *ar, const char *buf, u32 len) { bool restart = false; enum carl9170_restart_reasons reason = CARL9170_RR_NO_REASON; if (len > 3) { if (memcmp(buf, CARL9170_ERR_MAGIC, 3) == 0) { ar->fw.err_counter++; if (ar->fw.err_counter > 3) { restart = true; reason = CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS; } } if (memcmp(buf, CARL9170_BUG_MAGIC, 3) == 0) { ar->fw.bug_counter++; restart = true; reason = CARL9170_RR_FATAL_FIRMWARE_ERROR; } } wiphy_info(ar->hw->wiphy, "FW: %.*s\n", len, buf); if (restart) carl9170_restart(ar, reason); }
static void mwl_tx_ring_cleanup(struct mwl_priv *priv) { int cleaned_tx_desc = 0; int num, i; struct mwl_desc_data *desc; for (num = 0; num < SYSADPT_NUM_OF_DESC_DATA; num++) { skb_queue_purge(&priv->txq[num]); priv->fw_desc_cnt[num] = 0; desc = &priv->desc_data[num]; if (desc->ptx_ring) { for (i = 0; i < SYSADPT_MAX_NUM_TX_DESC; i++) { if (!desc->tx_hndl[i].psk_buff) continue; wiphy_info(priv->hw->wiphy, "unmapped and free'd %i 0x%p 0x%x\n", i, desc->tx_hndl[i].psk_buff->data, le32_to_cpu( desc->ptx_ring[i].pkt_ptr)); pci_unmap_single(priv->pdev, le32_to_cpu( desc->ptx_ring[i].pkt_ptr), desc->tx_hndl[i].psk_buff->len, PCI_DMA_TODEVICE); dev_kfree_skb_any(desc->tx_hndl[i].psk_buff); desc->ptx_ring[i].status = cpu_to_le32(EAGLE_TXD_STATUS_IDLE); desc->ptx_ring[i].pkt_ptr = 0; desc->ptx_ring[i].pkt_len = 0; desc->tx_hndl[i].psk_buff = NULL; cleaned_tx_desc++; } } } wiphy_info(priv->hw->wiphy, "cleaned %i TX descr\n", cleaned_tx_desc); }
static ssize_t ieee80211_if_parse_tsf( struct ieee80211_sub_if_data *sdata, const char *buf, int buflen) { struct ieee80211_local *local = sdata->local; unsigned long long tsf; int ret; int tsf_is_delta = 0; if (strncmp(buf, "reset", 5) == 0) { if (local->ops->reset_tsf) { drv_reset_tsf(local, sdata); wiphy_info(local->hw.wiphy, "debugfs reset TSF\n"); } } else { if (buflen > 10 && buf[1] == '=') { if (buf[0] == '+') tsf_is_delta = 1; else if (buf[0] == '-') tsf_is_delta = -1; else return -EINVAL; buf += 2; } ret = kstrtoull(buf, 10, &tsf); if (ret < 0) return ret; if (tsf_is_delta) tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf; if (local->ops->set_tsf) { drv_set_tsf(local, sdata, tsf); wiphy_info(local->hw.wiphy, "debugfs set TSF to %#018llx\n", tsf); } } ieee80211_recalc_dtim(local, sdata); return buflen; }
void ieee80211_restart_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); trace_api_restart_hw(local); wiphy_info(hw->wiphy, "Hardware restart was requested\n"); /* use this reason, ieee80211_reconfig will unblock it */ ieee80211_stop_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); schedule_work(&local->restart_work); }
int carl9170_echo_test(struct ar9170 *ar, const u32 v) { u32 echores; int err; err = carl9170_exec_cmd(ar, CARL9170_CMD_ECHO, 4, (u8 *)&v, 4, (u8 *)&echores); if (err) return err; if (v != echores) { wiphy_info(ar->hw->wiphy, "wrong echo %x != %x", v, echores); return -EINVAL; } return 0; }
int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) { struct p54_common *priv = dev->priv; struct eeprom_pda_wrap *wrap; struct pda_entry *entry; unsigned int data_len, entry_len; void *tmp; int err; u8 *end = (u8 *)eeprom + len; u16 synth = 0; u16 crc16 = ~0; wrap = (struct eeprom_pda_wrap *) eeprom; entry = (void *)wrap->data + le16_to_cpu(wrap->len); /* verify that at least the entry length/code fits */ while ((u8 *)entry <= end - sizeof(*entry)) { entry_len = le16_to_cpu(entry->len); data_len = ((entry_len - 1) << 1); /* abort if entry exceeds whole structure */ if ((u8 *)entry + sizeof(*entry) + data_len > end) break; switch (le16_to_cpu(entry->code)) { case PDR_MAC_ADDRESS: if (data_len != ETH_ALEN) break; SET_IEEE80211_PERM_ADDR(dev, entry->data); break; case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS: if (priv->output_limit) break; err = p54_convert_output_limits(dev, entry->data, data_len); if (err) goto err; break; case PDR_PRISM_PA_CAL_CURVE_DATA: { struct pda_pa_curve_data *curve_data = (struct pda_pa_curve_data *)entry->data; if (data_len < sizeof(*curve_data)) { err = -EINVAL; goto err; } switch (curve_data->cal_method_rev) { case 0: err = p54_convert_rev0(dev, curve_data); break; case 1: err = p54_convert_rev1(dev, curve_data); break; default: wiphy_err(dev->wiphy, "unknown curve data revision %d\n", curve_data->cal_method_rev); err = -ENODEV; break; } if (err) goto err; } break; case PDR_PRISM_ZIF_TX_IQ_CALIBRATION: priv->iq_autocal = kmemdup(entry->data, data_len, GFP_KERNEL); if (!priv->iq_autocal) { err = -ENOMEM; goto err; } priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry); break; case PDR_DEFAULT_COUNTRY: p54_parse_default_country(dev, entry->data, data_len); break; case PDR_INTERFACE_LIST: tmp = entry->data; while ((u8 *)tmp < entry->data + data_len) { struct exp_if *exp_if = tmp; if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000)) synth = le16_to_cpu(exp_if->variant); tmp += sizeof(*exp_if); } break; case PDR_HARDWARE_PLATFORM_COMPONENT_ID: if (data_len < 2) break; priv->version = *(u8 *)(entry->data + 1); break; case PDR_RSSI_LINEAR_APPROXIMATION: case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND: case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED: err = p54_parse_rssical(dev, entry->data, data_len, le16_to_cpu(entry->code)); if (err) goto err; break; case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOMV2: { struct pda_custom_wrapper *pda = (void *) entry->data; __le16 *src; u16 *dst; int i; if (priv->rssi_db || data_len < sizeof(*pda)) break; priv->rssi_db = p54_convert_db(pda, data_len); if (!priv->rssi_db) break; src = (void *) priv->rssi_db->data; dst = (void *) priv->rssi_db->data; for (i = 0; i < priv->rssi_db->entries; i++) *(dst++) = (s16) le16_to_cpu(*(src++)); } break; case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: { struct pda_custom_wrapper *pda = (void *) entry->data; if (priv->output_limit || data_len < sizeof(*pda)) break; priv->output_limit = p54_convert_db(pda, data_len); } break; case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: { struct pda_custom_wrapper *pda = (void *) entry->data; if (priv->curve_data || data_len < sizeof(*pda)) break; priv->curve_data = p54_convert_db(pda, data_len); } break; case PDR_END: crc16 = ~crc_ccitt(crc16, (u8 *) entry, sizeof(*entry)); if (crc16 != le16_to_cpup((__le16 *)entry->data)) { wiphy_err(dev->wiphy, "eeprom failed checksum " "test!\n"); err = -ENOMSG; goto err; } else { goto good_eeprom; } break; default: break; } crc16 = crc_ccitt(crc16, (u8 *)entry, (entry_len + 1) * 2); entry = (void *)entry + (entry_len + 1) * 2; } wiphy_err(dev->wiphy, "unexpected end of eeprom data.\n"); err = -ENODATA; goto err; good_eeprom: if (!synth || !priv->iq_autocal || !priv->output_limit || !priv->curve_data) { wiphy_err(dev->wiphy, "not all required entries found in eeprom!\n"); err = -EINVAL; goto err; } err = p54_generate_channel_lists(dev); if (err) goto err; priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK; if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW) p54_init_xbow_synth(priv); if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) dev->wiphy->bands[IEEE80211_BAND_2GHZ] = priv->band_table[IEEE80211_BAND_2GHZ]; if (!(synth & PDR_SYNTH_5_GHZ_DISABLED)) dev->wiphy->bands[IEEE80211_BAND_5GHZ] = priv->band_table[IEEE80211_BAND_5GHZ]; if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED) priv->rx_diversity_mask = 3; if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED) priv->tx_diversity_mask = 3; if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { u8 perm_addr[ETH_ALEN]; wiphy_warn(dev->wiphy, "Invalid hwaddr! Using randomly generated MAC addr\n"); random_ether_addr(perm_addr); SET_IEEE80211_PERM_ADDR(dev, perm_addr); } priv->cur_rssi = &p54_rssi_default; wiphy_info(dev->wiphy, "hwaddr %pM, MAC:isl38%02x RF:%s\n", dev->wiphy->perm_addr, priv->version, p54_rf_chips[priv->rxhw]); return 0; err: kfree(priv->iq_autocal); kfree(priv->output_limit); kfree(priv->curve_data); kfree(priv->rssi_db); priv->iq_autocal = NULL; priv->output_limit = NULL; priv->curve_data = NULL; priv->rssi_db = NULL; wiphy_err(dev->wiphy, "eeprom parse failed!\n"); return err; }
static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { void __iomem *mem; struct ath_softc *sc; struct ieee80211_hw *hw; u8 csz; u32 val; int ret = 0; char hw_name[64]; if (pci_enable_device(pdev)) return -EIO; ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (ret) { printk(KERN_ERR "ath9k: 32-bit DMA not available\n"); goto err_dma; } ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); if (ret) { printk(KERN_ERR "ath9k: 32-bit DMA consistent " "DMA enable failed\n"); goto err_dma; } /* * Cache line size is used to size and align various * structures used to communicate with the hardware. */ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz); if (csz == 0) { /* * Linux 2.4.18 (at least) writes the cache line size * register as a 16-bit wide register which is wrong. * We must have this setup properly for rx buffer * DMA to work so force a reasonable value here if it * comes up zero. */ csz = L1_CACHE_BYTES / sizeof(u32); pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz); } /* * The default setting of latency timer yields poor results, * set it to the value used by other systems. It may be worth * tweaking this setting more. */ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8); pci_set_master(pdev); /* * Disable the RETRY_TIMEOUT register (0x41) to keep * PCI Tx retries from interfering with C3 CPU state. */ pci_read_config_dword(pdev, 0x40, &val); if ((val & 0x0000ff00) != 0) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); ret = pci_request_region(pdev, 0, "ath9k"); if (ret) { dev_err(&pdev->dev, "PCI memory region reserve error\n"); ret = -ENODEV; goto err_region; } mem = pci_iomap(pdev, 0, 0); if (!mem) { printk(KERN_ERR "PCI memory map error\n") ; ret = -EIO; goto err_iomap; } hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); if (!hw) { dev_err(&pdev->dev, "No memory for ieee80211_hw\n"); ret = -ENOMEM; goto err_alloc_hw; } SET_IEEE80211_DEV(hw, &pdev->dev); pci_set_drvdata(pdev, hw); sc = hw->priv; sc->hw = hw; sc->dev = &pdev->dev; sc->mem = mem; /* Will be cleared in ath9k_start() */ sc->sc_flags |= SC_OP_INVALID; ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc); if (ret) { dev_err(&pdev->dev, "request_irq failed\n"); goto err_irq; } sc->irq = pdev->irq; ret = ath9k_init_device(id->device, sc, &ath_pci_bus_ops); if (ret) { dev_err(&pdev->dev, "Failed to initialize device\n"); goto err_init; } ath9k_hw_name(sc->sc_ah, hw_name, sizeof(hw_name)); wiphy_info(hw->wiphy, "%s mem=0x%lx, irq=%d\n", hw_name, (unsigned long)mem, pdev->irq); return 0; err_init: free_irq(sc->irq, sc); err_irq: ieee80211_free_hw(hw); err_alloc_hw: pci_iounmap(pdev, mem); err_iomap: pci_release_region(pdev, 0); err_region: /* Nothing */ err_dma: pci_disable_device(pdev); return ret; }
void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len) { struct carl9170_rsp *cmd = (void *) buf; struct ieee80211_vif *vif; if (carl9170_check_sequence(ar, cmd->hdr.seq)) return; if ((cmd->hdr.cmd & CARL9170_RSP_FLAG) != CARL9170_RSP_FLAG) { if (!(cmd->hdr.cmd & CARL9170_CMD_ASYNC_FLAG)) carl9170_cmd_callback(ar, len, buf); return; } if (unlikely(cmd->hdr.len != (len - 4))) { if (net_ratelimit()) { wiphy_err(ar->hw->wiphy, "FW: received over-/under" "sized event %x (%d, but should be %d).\n", cmd->hdr.cmd, cmd->hdr.len, len - 4); print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); } return; } /* hardware event handlers */ switch (cmd->hdr.cmd) { case CARL9170_RSP_PRETBTT: /* pre-TBTT event */ rcu_read_lock(); vif = carl9170_get_main_vif(ar); if (!vif) { rcu_read_unlock(); break; } switch (vif->type) { case NL80211_IFTYPE_STATION: carl9170_handle_ps(ar, cmd); break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: carl9170_update_beacon(ar, true); break; default: break; } rcu_read_unlock(); break; case CARL9170_RSP_TXCOMP: /* TX status notification */ carl9170_tx_process_status(ar, cmd); break; case CARL9170_RSP_BEACON_CONFIG: /* * (IBSS) beacon send notification * bytes: 04 c2 XX YY B4 B3 B2 B1 * * XX always 80 * YY always 00 * B1-B4 "should" be the number of send out beacons. */ break; case CARL9170_RSP_ATIM: /* End of Atim Window */ break; case CARL9170_RSP_WATCHDOG: /* Watchdog Interrupt */ carl9170_restart(ar, CARL9170_RR_WATCHDOG); break; case CARL9170_RSP_TEXT: /* firmware debug */ carl9170_dbg_message(ar, (char *)buf + 4, len - 4); break; case CARL9170_RSP_HEXDUMP: wiphy_dbg(ar->hw->wiphy, "FW: HD %d\n", len - 4); print_hex_dump_bytes("FW:", DUMP_PREFIX_NONE, (char *)buf + 4, len - 4); break; case CARL9170_RSP_RADAR: if (!net_ratelimit()) break; wiphy_info(ar->hw->wiphy, "FW: RADAR! Please report this " "incident to [email protected] !\n"); break; case CARL9170_RSP_GPIO: #ifdef CONFIG_CARL9170_WPC if (ar->wps.pbc) { bool state = !!(cmd->gpio.gpio & cpu_to_le32( AR9170_GPIO_PORT_WPS_BUTTON_PRESSED)); if (state != ar->wps.pbc_state) { ar->wps.pbc_state = state; input_report_key(ar->wps.pbc, KEY_WPS_BUTTON, state); input_sync(ar->wps.pbc); } } #endif /* CONFIG_CARL9170_WPC */ break; case CARL9170_RSP_BOOT: complete(&ar->fw_boot_wait); break; default: wiphy_err(ar->hw->wiphy, "FW: received unhandled event %x\n", cmd->hdr.cmd); print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len); break; } }
int mwl_fwdl_download_firmware(struct ieee80211_hw *hw) { struct mwl_priv *priv = hw->priv; const struct firmware *fw; u32 curr_iteration = 0; u32 size_fw_downloaded = 0; u32 int_code = 0; u32 len = 0; fw = priv->fw_ucode; mwl_fwcmd_reset(hw); /* FW before jumping to boot rom, it will enable PCIe transaction retry, * wait for boot code to stop it. */ mdelay(FW_CHECK_MSECS); writel(MACREG_A2HRIC_BIT_MASK, priv->iobase1 + MACREG_REG_A2H_INTERRUPT_CLEAR_SEL); writel(0x00, priv->iobase1 + MACREG_REG_A2H_INTERRUPT_CAUSE); writel(0x00, priv->iobase1 + MACREG_REG_A2H_INTERRUPT_MASK); writel(MACREG_A2HRIC_BIT_MASK, priv->iobase1 + MACREG_REG_A2H_INTERRUPT_STATUS_MASK); /* this routine interacts with SC2 bootrom to download firmware binary * to the device. After DMA'd to SC2, the firmware could be deflated to * reside on its respective blocks such as ITCM, DTCM, SQRAM, * (or even DDR, AFTER DDR is init'd before fw download */ wiphy_info(hw->wiphy, "fw download start 88\n"); /* Disable PFU before FWDL */ writel(0x100, priv->iobase1 + 0xE0E4); /* make sure SCRATCH2 C40 is clear, in case we are too quick */ while (readl(priv->iobase1 + 0xc40) == 0) ; while (size_fw_downloaded < fw->size) { len = readl(priv->iobase1 + 0xc40); if (!len) break; /* this copies the next chunk of fw binary to be delivered */ memcpy((char *)&priv->pcmd_buf[0], (fw->data + size_fw_downloaded), len); /* this function writes pdata to c10, then write 2 to c18 */ mwl_fwdl_trig_pcicmd_bootcode(priv); /* this is arbitrary per your platform; we use 0xffff */ curr_iteration = FW_MAX_NUM_CHECKS; /* NOTE: the following back to back checks on C1C is time * sensitive, hence may need to be tweaked dependent on host * processor. Time for SC2 to go from the write of event 2 to * C1C == 2 is ~1300 nSec. Hence the checkings on host has to * consider how efficient your code can be to meet this timing, * or you can alternatively tweak this routines to fit your * platform */ do { int_code = readl(priv->iobase1 + 0xc1c); if (int_code != 0) break; curr_iteration--; } while (curr_iteration); do { int_code = readl(priv->iobase1 + 0xc1c); if ((int_code & MACREG_H2ARIC_BIT_DOOR_BELL) != MACREG_H2ARIC_BIT_DOOR_BELL) break; curr_iteration--; } while (curr_iteration); if (curr_iteration == 0) { /* This limited loop check allows you to exit gracefully * without locking up your entire system just because fw * download failed */ wiphy_err(hw->wiphy, "Exhausted curr_iteration for fw download\n"); goto err_download; } size_fw_downloaded += len; } wiphy_info(hw->wiphy, "FwSize = %d downloaded Size = %d curr_iteration %d\n", (int)fw->size, size_fw_downloaded, curr_iteration); /* Now firware is downloaded successfully, so this part is to check * whether fw can properly execute to an extent that write back * signature to indicate its readiness to the host. NOTE: if your * downloaded fw crashes, this signature checking will fail. This * part is similar as SC1 */ *((u32 *)&priv->pcmd_buf[1]) = 0; mwl_fwdl_trig_pcicmd(priv); curr_iteration = FW_MAX_NUM_CHECKS; do { curr_iteration--; writel(HOSTCMD_SOFTAP_MODE, priv->iobase1 + MACREG_REG_GEN_PTR); mdelay(FW_CHECK_MSECS); int_code = readl(priv->iobase1 + MACREG_REG_INT_CODE); if (!(curr_iteration % 0xff)) wiphy_err(hw->wiphy, "%x;", int_code); } while ((curr_iteration) && (int_code != HOSTCMD_SOFTAP_FWRDY_SIGNATURE)); if (curr_iteration == 0) { wiphy_err(hw->wiphy, "Exhausted curr_iteration for fw signature\n"); goto err_download; } wiphy_info(hw->wiphy, "complete\n"); writel(0x00, priv->iobase1 + MACREG_REG_INT_CODE); return 0; err_download: mwl_fwcmd_reset(hw); return -EIO; }