static void wil_print_connect_params(struct wil6210_priv *wil, struct cfg80211_connect_params *sme) { wil_info(wil, "Connecting to:\n"); if (sme->channel) { wil_info(wil, " Channel: %d freq %d\n", sme->channel->hw_value, sme->channel->center_freq); } if (sme->bssid) wil_info(wil, " BSSID: %pM\n", sme->bssid); if (sme->ssid) print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET, 16, 1, sme->ssid, sme->ssid_len, true); wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open"); }
/* Write WMI command (w/o mbox header) to this file to send it * WMI starts from wil6210_mbox_hdr_wmi header */ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); struct wmi_cmd_hdr *wmi; void *cmd; int cmdlen = len - sizeof(struct wmi_cmd_hdr); u16 cmdid; int rc, rc1; if (cmdlen < 0) return -EINVAL; wmi = kmalloc(len, GFP_KERNEL); if (!wmi) return -ENOMEM; rc = simple_write_to_buffer(wmi, len, ppos, buf, len); if (rc < 0) { kfree(wmi); return rc; } cmd = (cmdlen > 0) ? &wmi[1] : NULL; cmdid = le16_to_cpu(wmi->command_id); rc1 = wmi_send(wil, cmdid, vif->mid, cmd, cmdlen); kfree(wmi); wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1); return rc; }
/* Write mgmt frame to this file to send it */ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; struct wiphy *wiphy = wil_to_wiphy(wil); struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr; struct cfg80211_mgmt_tx_params params; int rc; void *frame; if (!len) return -EINVAL; frame = memdup_user(buf, len); if (IS_ERR(frame)) return PTR_ERR(frame); params.buf = frame; params.len = len; rc = wil_cfg80211_mgmt_tx(wiphy, wdev, ¶ms, NULL); kfree(frame); wil_info(wil, "-> %d\n", rc); return len; }
int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie) { struct wil_p2p_info *p2p = &wil->p2p; u8 started; mutex_lock(&wil->mutex); if (cookie != p2p->cookie) { wil_info(wil, "Cookie mismatch: 0x%016llx vs. 0x%016llx\n", p2p->cookie, cookie); mutex_unlock(&wil->mutex); return -ENOENT; } started = wil_p2p_stop_discovery(wil); mutex_unlock(&wil->mutex); if (!started) { wil_err(wil, "listen not started\n"); return -ENOENT; } mutex_lock(&wil->p2p_wdev_mutex); cfg80211_remain_on_channel_expired(wil->radio_wdev, p2p->cookie, &p2p->listen_chan, GFP_KERNEL); wil->radio_wdev = wil->wdev; mutex_unlock(&wil->p2p_wdev_mutex); return 0; }
/* Write mgmt frame to this file to send it */ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; struct wiphy *wiphy = wil_to_wiphy(wil); struct wireless_dev *wdev = wil_to_wdev(wil); struct cfg80211_mgmt_tx_params params; int rc; void *frame = kmalloc(len, GFP_KERNEL); if (!frame) return -ENOMEM; if (copy_from_user(frame, buf, len)) { kfree(frame); return -EIO; } params.buf = frame; params.len = len; params.chan = wdev->preset_chandef.chan; rc = wil_cfg80211_mgmt_tx(wiphy, wdev, ¶ms, NULL); kfree(frame); wil_info(wil, "%s() -> %d\n", __func__, rc); return len; }
/* Write WMI command (w/o mbox header) to this file to send it * WMI starts from wil6210_mbox_hdr_wmi header */ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; struct wil6210_mbox_hdr_wmi *wmi; void *cmd; int cmdlen = len - sizeof(struct wil6210_mbox_hdr_wmi); u16 cmdid; int rc, rc1; if (cmdlen <= 0) return -EINVAL; wmi = kmalloc(len, GFP_KERNEL); if (!wmi) return -ENOMEM; rc = simple_write_to_buffer(wmi, len, ppos, buf, len); if (rc < 0) return rc; cmd = &wmi[1]; cmdid = le16_to_cpu(wmi->id); rc1 = wmi_send(wil, cmdid, cmd, cmdlen); kfree(wmi); wil_info(wil, "%s(0x%04x[%d]) -> %d\n", __func__, cmdid, cmdlen, rc1); return rc; }
static int wil_wait_for_fw_ready(struct wil6210_priv *wil) { ulong to = msecs_to_jiffies(1000); ulong left = wait_for_completion_timeout(&wil->wmi_ready, to); if (0 == left) { wil_err(wil, "Firmware not ready\n"); return -ETIME; } else { wil_info(wil, "FW ready after %d ms. HW version 0x%08x\n", jiffies_to_msecs(to-left), wil->hw_version); } return 0; }
static int wil_cancel_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, u64 cookie) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; wil_info(wil, "%s()\n", __func__); rc = wmi_rxon(wil, false); return rc; }
static int wil_set_features(struct net_device *netdev, netdev_features_t features) { struct wil6210_priv *wil = ndev_to_wil(netdev); netdev_features_t changed = features ^ netdev->features; wil_info(wil, "wil_set_features: %x\n", (unsigned int)features); if (changed & NETIF_F_HW_CSUM) wil_dbg_txrx(wil, "Tx checksum offloading changed\n"); else if (changed & NETIF_F_RXCSUM) wil_dbg_txrx(wil, "Rx checksum offloading changed\n"); return 0; }
static void wil_fw_error_worker(struct work_struct *work) { struct wil6210_priv *wil = container_of(work, struct wil6210_priv, fw_error_worker); struct wireless_dev *wdev = wil->wdev; wil_dbg_misc(wil, "fw error worker\n"); if (no_fw_recovery) return; /* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO * passed since last recovery attempt */ if (time_is_after_jiffies(wil->last_fw_recovery + WIL6210_FW_RECOVERY_TO)) wil->recovery_count++; else wil->recovery_count = 1; /* fw was alive for a long time */ if (wil->recovery_count > WIL6210_FW_RECOVERY_RETRIES) { wil_err(wil, "too many recovery attempts (%d), giving up\n", wil->recovery_count); return; } wil->last_fw_recovery = jiffies; mutex_lock(&wil->mutex); switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_MONITOR: wil_info(wil, "fw error recovery started (try %d)...\n", wil->recovery_count); wil_reset(wil); /* need to re-allocate Rx ring after reset */ wil_rx_init(wil); break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: /* recovery in these modes is done by upper layers */ break; default: break; } mutex_unlock(&wil->mutex); }
static int wil_remain_on_channel(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, unsigned int duration, u64 *cookie) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; /* TODO: handle duration */ wil_info(wil, "%s(%d, %d ms)\n", __func__, chan->center_freq, duration); rc = wmi_set_channel(wil, chan->hw_value); if (rc) return rc; rc = wmi_rxon(wil, true); return rc; }
/* * Write mgmt frame to this file to send it */ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; #if 0 struct net_device *ndev = wil_to_ndev(wil); #endif struct wiphy *wiphy = wil_to_wiphy(wil); struct wireless_dev *wdev = wil_to_wdev(wil); int rc; void *frame = kmalloc(len, GFP_KERNEL); if (!frame) return -ENOMEM; if (copy_from_user(frame, buf, len)) return -EIO; #if 0 rc = wmi_set_channel(wil, 1); if (rc) return rc; rc = wmi_call(wil, WMI_RX_ON_CMDID, NULL, 0, WMI_RX_ON_DONE_EVENTID, NULL, 0, 20); if (rc) return rc; #endif rc = wil_cfg80211_mgmt_tx(wiphy, wdev, wdev->preset_chandef.chan, true, 0, frame, len, true, false, NULL); kfree(frame); wil_info(wil, "%s() -> %d\n", __func__, rc); #if 0 msleep(300); rtnl_lock(); dev_close(ndev); ndev->flags &= ~IFF_UP; rtnl_unlock(); wil_reset(wil); #endif return len; }
static void wil_set_capabilities(struct wil6210_priv *wil) { u32 rev_id = wil_r(wil, RGF_USER_JTAG_DEV_ID); bitmap_zero(wil->hw_capabilities, hw_capability_last); bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX); switch (rev_id) { case JTAG_DEV_ID_SPARROW_B0: wil->hw_name = "Sparrow B0"; wil->hw_version = HW_VER_SPARROW_B0; break; default: wil_err(wil, "Unknown board hardware 0x%08x\n", rev_id); wil->hw_name = "Unknown"; wil->hw_version = HW_VER_UNKNOWN; } wil_info(wil, "Board hardware is %s\n", wil->hw_name); /* extract FW capabilities from file without loading the FW */ wil_request_firmware(wil, WIL_FW_NAME, false); }
static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct wil6210_priv *wil; struct device *dev = &pdev->dev; int rc; const struct wil_platform_rops rops = { .ramdump = wil_platform_rop_ramdump, .fw_recovery = wil_platform_rop_fw_recovery, }; /* check HW */ dev_info(&pdev->dev, WIL_NAME " device found [%04x:%04x] (rev %x)\n", (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) { dev_err(&pdev->dev, "Not " WIL_NAME "? " "BAR0 size is %lu while expecting %lu\n", (ulong)pci_resource_len(pdev, 0), WIL6210_MEM_SIZE); return -ENODEV; } wil = wil_if_alloc(dev); if (IS_ERR(wil)) { rc = (int)PTR_ERR(wil); dev_err(dev, "wil_if_alloc failed: %d\n", rc); return rc; } wil->pdev = pdev; pci_set_drvdata(pdev, wil); /* rollback to if_free */ wil->platform_handle = wil_platform_init(&pdev->dev, &wil->platform_ops, &rops, wil); if (!wil->platform_handle) { rc = -ENODEV; wil_err(wil, "wil_platform_init failed\n"); goto if_free; } /* rollback to err_plat */ rc = pci_enable_device(pdev); if (rc) { wil_err(wil, "pci_enable_device failed, retry with MSI only\n"); /* Work around for platforms that can't allocate IRQ: * retry with MSI only */ pdev->msi_enabled = 1; rc = pci_enable_device(pdev); } if (rc) { wil_err(wil, "pci_enable_device failed, even with MSI only\n"); goto err_plat; } /* rollback to err_disable_pdev */ rc = pci_request_region(pdev, 0, WIL_NAME); if (rc) { wil_err(wil, "pci_request_region failed\n"); goto err_disable_pdev; } /* rollback to err_release_reg */ wil->csr = pci_ioremap_bar(pdev, 0); if (!wil->csr) { wil_err(wil, "pci_ioremap_bar failed\n"); rc = -ENODEV; goto err_release_reg; } /* rollback to err_iounmap */ wil_info(wil, "CSR at %pR -> 0x%p\n", &pdev->resource[0], wil->csr); wil_set_capabilities(wil); wil6210_clear_irq(wil); /* FW should raise IRQ when ready */ rc = wil_if_pcie_enable(wil); if (rc) { wil_err(wil, "Enable device failed\n"); goto err_iounmap; } /* rollback to bus_disable */ rc = wil_if_add(wil); if (rc) { wil_err(wil, "wil_if_add failed: %d\n", rc); goto bus_disable; } #ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP wil->pm_notify.notifier_call = wil6210_pm_notify; rc = register_pm_notifier(&wil->pm_notify); if (rc) /* Do not fail the driver initialization, as suspend can * be prevented in a later phase if needed */ wil_err(wil, "register_pm_notifier failed: %d\n", rc); #endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM */ wil6210_debugfs_init(wil); return 0; bus_disable: wil_if_pcie_disable(wil); err_iounmap: pci_iounmap(pdev, wil->csr); err_release_reg: pci_release_region(pdev, 0); err_disable_pdev: pci_disable_device(pdev); err_plat: if (wil->platform_ops.uninit) wil->platform_ops.uninit(wil->platform_handle); if_free: wil_if_free(wil); return rc; }