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; }
/* 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 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_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; }
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; }
/** * 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 = ⅆ 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); }
/** * 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); }