Exemplo n.º 1
0
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");
}
Exemplo n.º 2
0
/* 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;
}
Exemplo n.º 3
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->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, &params, NULL);

	kfree(frame);
	wil_info(wil, "-> %d\n", rc);

	return len;
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
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, &params, NULL);

	kfree(frame);
	wil_info(wil, "%s() -> %d\n", __func__, rc);

	return len;
}
Exemplo n.º 6
0
/* 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;
}
Exemplo n.º 7
0
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;
}
Exemplo n.º 8
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;
}
Exemplo n.º 9
0
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;
}
Exemplo n.º 10
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);
}
Exemplo n.º 11
0
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;
}
Exemplo n.º 12
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;
#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;
}
Exemplo n.º 13
0
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);
}
Exemplo n.º 14
0
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;
}