示例#1
0
static int wil_cfg80211_scan(struct wiphy *wiphy,
                             struct cfg80211_scan_request *request)
{
    struct wil6210_priv *wil = wiphy_to_wil(wiphy);
    struct wireless_dev *wdev = wil->wdev;
    struct {
        struct wmi_start_scan_cmd cmd;
        u16 chnl[4];
    } __packed cmd;
    uint i, n;
    int rc;

    if (wil->scan_request) {
        wil_err(wil, "Already scanning\n");
        return -EAGAIN;
    }

    /* check we are client side */
    switch (wdev->iftype) {
    case NL80211_IFTYPE_STATION:
    case NL80211_IFTYPE_P2P_CLIENT:
        break;
    default:
        return -EOPNOTSUPP;
    }

    /* FW don't support scan after connection attempt */
    if (test_bit(wil_status_dontscan, &wil->status)) {
        wil_err(wil, "Can't scan now\n");
        return -EBUSY;
    }

    wil->scan_request = request;
    mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO);

    memset(&cmd, 0, sizeof(cmd));
    cmd.cmd.num_channels = 0;
    n = min(request->n_channels, 4U);
    for (i = 0; i < n; i++) {
        int ch = request->channels[i]->hw_value;
        if (ch == 0) {
            wil_err(wil,
                    "Scan requested for unknown frequency %dMhz\n",
                    request->channels[i]->center_freq);
            continue;
        }
        /* 0-based channel indexes */
        cmd.cmd.channel_list[cmd.cmd.num_channels++].channel = ch - 1;
        wil_dbg_misc(wil, "Scan for ch %d  : %d MHz\n", ch,
                     request->channels[i]->center_freq);
    }

    rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
                  cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));

    if (rc)
        wil->scan_request = NULL;

    return rc;
}
示例#2
0
文件: debugfs.c 项目: lumag/linux
/* 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;
}
示例#3
0
文件: debugfs.c 项目: 3null/linux
/* 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;
}
示例#4
0
static int wil_cfg80211_disconnect(struct wiphy *wiphy,
                                   struct net_device *ndev,
                                   u16 reason_code)
{
    int rc;
    struct wil6210_priv *wil = wiphy_to_wil(wiphy);

    rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);

    return rc;
}
示例#5
0
static int wil_cfg80211_connect(struct wiphy *wiphy,
                                struct net_device *ndev,
                                struct cfg80211_connect_params *sme)
{
    struct wil6210_priv *wil = wiphy_to_wil(wiphy);
    struct cfg80211_bss *bss;
    struct wmi_connect_cmd conn;
    const u8 *ssid_eid;
    const u8 *rsn_eid;
    int ch;
    int rc = 0;

    if (test_bit(wil_status_fwconnecting, &wil->status) ||
            test_bit(wil_status_fwconnected, &wil->status))
        return -EALREADY;

    bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
                           sme->ssid, sme->ssid_len,
                           WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
    if (!bss) {
        wil_err(wil, "Unable to find BSS\n");
        return -ENOENT;
    }

    ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID);
    if (!ssid_eid) {
        wil_err(wil, "No SSID\n");
        rc = -ENOENT;
        goto out;
    }

    rsn_eid = sme->ie ?
              cfg80211_find_ie(WLAN_EID_RSN, sme->ie, sme->ie_len) :
              NULL;
    if (rsn_eid) {
        if (sme->ie_len > WMI_MAX_IE_LEN) {
            rc = -ERANGE;
            wil_err(wil, "IE too large (%td bytes)\n",
                    sme->ie_len);
            goto out;
        }
        /*
         * For secure assoc, send:
         * (1) WMI_DELETE_CIPHER_KEY_CMD
         * (2) WMI_SET_APPIE_CMD
         */
        rc = wmi_del_cipher_key(wil, 0, bss->bssid);
        if (rc) {
            wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD failed\n");
            goto out;
        }
        /* WMI_SET_APPIE_CMD */
        rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie);
        if (rc) {
            wil_err(wil, "WMI_SET_APPIE_CMD failed\n");
            goto out;
        }
    }

    /* WMI_CONNECT_CMD */
    memset(&conn, 0, sizeof(conn));
    switch (bss->capability & WLAN_CAPABILITY_DMG_TYPE_MASK) {
    case WLAN_CAPABILITY_DMG_TYPE_AP:
        conn.network_type = WMI_NETTYPE_INFRA;
        break;
    case WLAN_CAPABILITY_DMG_TYPE_PBSS:
        conn.network_type = WMI_NETTYPE_P2P;
        break;
    default:
        wil_err(wil, "Unsupported BSS type, capability= 0x%04x\n",
                bss->capability);
        goto out;
    }
    if (rsn_eid) {
        conn.dot11_auth_mode = WMI_AUTH11_SHARED;
        conn.auth_mode = WMI_AUTH_WPA2_PSK;
        conn.pairwise_crypto_type = WMI_CRYPT_AES_GCMP;
        conn.pairwise_crypto_len = 16;
    } else {
        conn.dot11_auth_mode = WMI_AUTH11_OPEN;
        conn.auth_mode = WMI_AUTH_NONE;
    }

    conn.ssid_len = min_t(u8, ssid_eid[1], 32);
    memcpy(conn.ssid, ssid_eid+2, conn.ssid_len);

    ch = bss->channel->hw_value;
    if (ch == 0) {
        wil_err(wil, "BSS at unknown frequency %dMhz\n",
                bss->channel->center_freq);
        rc = -EOPNOTSUPP;
        goto out;
    }
    conn.channel = ch - 1;

    memcpy(conn.bssid, bss->bssid, ETH_ALEN);
    memcpy(conn.dst_mac, bss->bssid, ETH_ALEN);

    set_bit(wil_status_fwconnecting, &wil->status);

    rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn));
    if (rc == 0) {
        /* Connect can take lots of time */
        mod_timer(&wil->connect_timer,
                  jiffies + msecs_to_jiffies(2000));
    } else {
        clear_bit(wil_status_fwconnecting, &wil->status);
    }

out:
    cfg80211_put_bss(wiphy, bss);

    return rc;
}
示例#6
0
文件: pmc.c 项目: DenisLug/mptcp
/**
 * Allocate the physical ring (p-ring) and the required
 * number of descriptors of required size.
 * Initialize the descriptors as required by pmc dma.
 * The descriptors' buffers dwords are initialized to hold
 * dword's serial number in the lsw and reserved value
 * PCM_DATA_INVALID_DW_VAL in the msw.
 */
void wil_pmc_alloc(struct wil6210_priv *wil,
		   int num_descriptors,
		   int descriptor_size)
{
	u32 i;
	struct pmc_ctx *pmc = &wil->pmc;
	struct device *dev = wil_to_dev(wil);
	struct wmi_pmc_cmd pmc_cmd = {0};

	mutex_lock(&pmc->lock);

	if (wil_is_pmc_allocated(pmc)) {
		/* sanity check */
		wil_err(wil, "%s: ERROR pmc is already allocated\n", __func__);
		goto no_release_err;
	}

	pmc->num_descriptors = num_descriptors;
	pmc->descriptor_size = descriptor_size;

	wil_dbg_misc(wil, "%s: %d descriptors x %d bytes each\n",
		     __func__, num_descriptors, descriptor_size);

	/* allocate descriptors info list in pmc context*/
	pmc->descriptors = kcalloc(num_descriptors,
				  sizeof(struct desc_alloc_info),
				  GFP_KERNEL);
	if (!pmc->descriptors) {
		wil_err(wil, "%s: ERROR allocating pmc skb list\n", __func__);
		goto no_release_err;
	}

	wil_dbg_misc(wil,
		     "%s: allocated descriptors info list %p\n",
		     __func__, pmc->descriptors);

	/* Allocate pring buffer and descriptors.
	 * vring->va should be aligned on its size rounded up to power of 2
	 * This is granted by the dma_alloc_coherent
	 */
	pmc->pring_va = dma_alloc_coherent(dev,
			sizeof(struct vring_tx_desc) * num_descriptors,
			&pmc->pring_pa,
			GFP_KERNEL);

	wil_dbg_misc(wil,
		     "%s: allocated pring %p => %pad. %zd x %d = total %zd bytes\n",
		     __func__,
		     pmc->pring_va, &pmc->pring_pa,
		     sizeof(struct vring_tx_desc),
		     num_descriptors,
		     sizeof(struct vring_tx_desc) * num_descriptors);

	if (!pmc->pring_va) {
		wil_err(wil, "%s: ERROR allocating pmc pring\n", __func__);
		goto release_pmc_skb_list;
	}

	/* initially, all descriptors are SW owned
	 * For Tx, Rx, and PMC, ownership bit is at the same location, thus
	 * we can use any
	 */
	for (i = 0; i < num_descriptors; i++) {
		struct vring_tx_desc *_d = &pmc->pring_va[i];
		struct vring_tx_desc dd, *d = &dd;
		int j = 0;

		pmc->descriptors[i].va = dma_alloc_coherent(dev,
			descriptor_size,
			&pmc->descriptors[i].pa,
			GFP_KERNEL);

		if (unlikely(!pmc->descriptors[i].va)) {
			wil_err(wil,
				"%s: ERROR allocating pmc descriptor %d",
				__func__, i);
			goto release_pmc_skbs;
		}

		for (j = 0; j < descriptor_size / sizeof(u32); j++) {
			u32 *p = (u32 *)pmc->descriptors[i].va + j;
			*p = PCM_DATA_INVALID_DW_VAL | j;
		}

		/* configure dma descriptor */
		d->dma.addr.addr_low =
			cpu_to_le32(lower_32_bits(pmc->descriptors[i].pa));
		d->dma.addr.addr_high =
			cpu_to_le16((u16)upper_32_bits(pmc->descriptors[i].pa));
		d->dma.status = 0; /* 0 = HW_OWNED */
		d->dma.length = cpu_to_le16(descriptor_size);
		d->dma.d0 = BIT(9) | RX_DMA_D0_CMD_DMA_IT;
		*_d = *d;
	}

	wil_dbg_misc(wil, "%s: allocated successfully\n", __func__);

	pmc_cmd.op = WMI_PMC_ALLOCATE;
	pmc_cmd.ring_size = cpu_to_le16(pmc->num_descriptors);
	pmc_cmd.mem_base = cpu_to_le64(pmc->pring_pa);

	wil_dbg_misc(wil, "%s: send WMI_PMC_CMD with ALLOCATE op\n", __func__);
	pmc->last_cmd_status = wmi_send(wil,
					WMI_PMC_CMDID,
					&pmc_cmd,
					sizeof(pmc_cmd));
	if (pmc->last_cmd_status) {
		wil_err(wil,
			"%s: WMI_PMC_CMD with ALLOCATE op failed with status %d",
			__func__, pmc->last_cmd_status);
		goto release_pmc_skbs;
	}

	mutex_unlock(&pmc->lock);

	return;

release_pmc_skbs:
	wil_err(wil, "%s: exit on error: Releasing skbs...\n", __func__);
	for (i = 0; pmc->descriptors[i].va && i < num_descriptors; i++) {
		dma_free_coherent(dev,
				  descriptor_size,
				  pmc->descriptors[i].va,
				  pmc->descriptors[i].pa);

		pmc->descriptors[i].va = NULL;
	}
	wil_err(wil, "%s: exit on error: Releasing pring...\n", __func__);

	dma_free_coherent(dev,
			  sizeof(struct vring_tx_desc) * num_descriptors,
			  pmc->pring_va,
			  pmc->pring_pa);

	pmc->pring_va = NULL;

release_pmc_skb_list:
	wil_err(wil, "%s: exit on error: Releasing descriptors info list...\n",
		__func__);
	kfree(pmc->descriptors);
	pmc->descriptors = NULL;

no_release_err:
	pmc->last_cmd_status = -ENOMEM;
	mutex_unlock(&pmc->lock);
}
示例#7
0
文件: pmc.c 项目: DenisLug/mptcp
/**
 * Traverse the p-ring and release all buffers.
 * At the end release the p-ring memory
 */
void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd)
{
	struct pmc_ctx *pmc = &wil->pmc;
	struct device *dev = wil_to_dev(wil);
	struct wmi_pmc_cmd pmc_cmd = {0};

	mutex_lock(&pmc->lock);

	pmc->last_cmd_status = 0;

	if (!wil_is_pmc_allocated(pmc)) {
		wil_dbg_misc(wil, "%s: Error, can't free - not allocated\n",
			     __func__);
		pmc->last_cmd_status = -EPERM;
		mutex_unlock(&pmc->lock);
		return;
	}

	if (send_pmc_cmd) {
		wil_dbg_misc(wil, "%s: send WMI_PMC_CMD with RELEASE op\n",
			     __func__);
		pmc_cmd.op = WMI_PMC_RELEASE;
		pmc->last_cmd_status =
				wmi_send(wil, WMI_PMC_CMDID, &pmc_cmd,
					 sizeof(pmc_cmd));
		if (pmc->last_cmd_status) {
			wil_err(wil,
				"%s WMI_PMC_CMD with RELEASE op failed, status %d",
				__func__, pmc->last_cmd_status);
			/* There's nothing we can do with this error.
			 * Normally, it should never occur.
			 * Continue to freeing all memory allocated for pmc.
			 */
		}
	}

	if (pmc->pring_va) {
		size_t buf_size = sizeof(struct vring_tx_desc) *
				  pmc->num_descriptors;

		wil_dbg_misc(wil, "%s: free pring va %p\n",
			     __func__, pmc->pring_va);
		dma_free_coherent(dev, buf_size, pmc->pring_va, pmc->pring_pa);

		pmc->pring_va = NULL;
	} else {
		pmc->last_cmd_status = -ENOENT;
	}

	if (pmc->descriptors) {
		int i;

		for (i = 0;
		     pmc->descriptors[i].va && i < pmc->num_descriptors; i++) {
			dma_free_coherent(dev,
					  pmc->descriptor_size,
					  pmc->descriptors[i].va,
					  pmc->descriptors[i].pa);
			pmc->descriptors[i].va = NULL;
		}
		wil_dbg_misc(wil, "%s: free descriptor info %d/%d\n",
			     __func__, i, pmc->num_descriptors);
		wil_dbg_misc(wil,
			     "%s: free pmc descriptors info list %p\n",
			     __func__, pmc->descriptors);
		kfree(pmc->descriptors);
		pmc->descriptors = NULL;
	} else {
		pmc->last_cmd_status = -ENOENT;
	}

	mutex_unlock(&pmc->lock);
}