/* Bus ops */ static int wil_if_pcie_enable(struct wil6210_priv *wil) { struct pci_dev *pdev = wil->pdev; int rc; pci_set_master(pdev); /* * how many MSI interrupts to request? */ switch (use_msi) { case 3: case 1: case 0: break; default: wil_err(wil, "Invalid use_msi=%d, default to 1\n", use_msi); use_msi = 1; } wil->n_msi = use_msi; if (wil->n_msi) { wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); rc = pci_enable_msi_block(pdev, wil->n_msi); if (rc && (wil->n_msi == 3)) { wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); wil->n_msi = 1; rc = pci_enable_msi_block(pdev, wil->n_msi); } if (rc) { wil_err(wil, "pci_enable_msi failed, use INTx\n"); wil->n_msi = 0; } } else { wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); } rc = wil6210_init_irq(wil, pdev->irq); if (rc) goto stop_master; /* need reset here to obtain MAC */ rc = wil_reset(wil); if (debug_fw) rc = 0; if (rc) goto release_irq; return 0; release_irq: wil6210_fini_irq(wil, pdev->irq); /* safe to call if no MSI */ pci_disable_msi(pdev); stop_master: pci_clear_master(pdev); return rc; }
static int __wil_up(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); struct wireless_dev *wdev = wil->wdev; int rc; WARN_ON(!mutex_is_locked(&wil->mutex)); rc = wil_reset(wil); if (rc) return rc; /* Rx VRING. After MAC and beacon */ rc = wil_rx_init(wil); if (rc) return rc; switch (wdev->iftype) { case NL80211_IFTYPE_STATION: wil_dbg_misc(wil, "type: STATION\n"); ndev->type = ARPHRD_ETHER; break; case NL80211_IFTYPE_AP: wil_dbg_misc(wil, "type: AP\n"); ndev->type = ARPHRD_ETHER; break; case NL80211_IFTYPE_P2P_CLIENT: wil_dbg_misc(wil, "type: P2P_CLIENT\n"); ndev->type = ARPHRD_ETHER; break; case NL80211_IFTYPE_P2P_GO: wil_dbg_misc(wil, "type: P2P_GO\n"); ndev->type = ARPHRD_ETHER; break; case NL80211_IFTYPE_MONITOR: wil_dbg_misc(wil, "type: Monitor\n"); ndev->type = ARPHRD_IEEE80211_RADIOTAP; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */ break; default: return -EOPNOTSUPP; } /* MAC address - pre-requisite for other commands */ wmi_set_mac_address(wil, ndev->dev_addr); napi_enable(&wil->napi_rx); napi_enable(&wil->napi_tx); set_bit(wil_status_napi_en, &wil->status); return 0; }
/* Bus ops */ static int wil_if_pcie_enable(struct wil6210_priv *wil) { struct pci_dev *pdev = wil->pdev; int rc; /* on platforms with buggy ACPI, pdev->msi_enabled may be set to * allow pci_enable_device to work. This indicates INTx was not routed * and only MSI should be used */ int msi_only = pdev->msi_enabled; bool _use_msi = use_msi; wil_dbg_misc(wil, "%s()\n", __func__); pdev->msi_enabled = 0; pci_set_master(pdev); wil_dbg_misc(wil, "Setup %s interrupt\n", use_msi ? "MSI" : "INTx"); if (use_msi && pci_enable_msi(pdev)) { wil_err(wil, "pci_enable_msi failed, use INTx\n"); _use_msi = false; } if (!_use_msi && msi_only) { wil_err(wil, "Interrupt pin not routed, unable to use INTx\n"); rc = -ENODEV; goto stop_master; } rc = wil6210_init_irq(wil, pdev->irq, _use_msi); if (rc) goto stop_master; /* need reset here to obtain MAC */ mutex_lock(&wil->mutex); rc = wil_reset(wil, false); mutex_unlock(&wil->mutex); if (rc) goto release_irq; return 0; release_irq: wil6210_fini_irq(wil, pdev->irq); /* safe to call if no MSI */ pci_disable_msi(pdev); stop_master: pci_clear_master(pdev); return rc; }
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); }
/*---reset---*/ static ssize_t wil_write_file_reset(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; struct net_device *ndev = wil->main_ndev; /** * BUG: * this code does NOT sync device state with the rest of system * use with care, debug only!!! */ rtnl_lock(); dev_close(ndev); ndev->flags &= ~IFF_UP; rtnl_unlock(); wil_reset(wil, true); return len; }
/* * 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 int __wil_up(struct wil6210_priv *wil) { struct net_device *ndev = wil_to_ndev(wil); struct wireless_dev *wdev = wil->wdev; struct ieee80211_channel *channel = wdev->preset_chandef.chan; int rc; int bi; u16 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); rc = wil_reset(wil); if (rc) return rc; /* FIXME Firmware works now in PBSS mode(ToDS=0, FromDS=0) */ wmi_nettype = wil_iftype_nl2wmi(NL80211_IFTYPE_ADHOC); switch (wdev->iftype) { case NL80211_IFTYPE_STATION: wil_dbg_misc(wil, "type: STATION\n"); bi = 0; ndev->type = ARPHRD_ETHER; break; case NL80211_IFTYPE_AP: wil_dbg_misc(wil, "type: AP\n"); bi = 100; ndev->type = ARPHRD_ETHER; break; case NL80211_IFTYPE_P2P_CLIENT: wil_dbg_misc(wil, "type: P2P_CLIENT\n"); bi = 0; ndev->type = ARPHRD_ETHER; break; case NL80211_IFTYPE_P2P_GO: wil_dbg_misc(wil, "type: P2P_GO\n"); bi = 100; ndev->type = ARPHRD_ETHER; break; case NL80211_IFTYPE_MONITOR: wil_dbg_misc(wil, "type: Monitor\n"); bi = 0; ndev->type = ARPHRD_IEEE80211_RADIOTAP; /* ARPHRD_IEEE80211 or ARPHRD_IEEE80211_RADIOTAP ? */ break; default: return -EOPNOTSUPP; } /* Apply profile in the following order: */ /* SSID and channel for the AP */ switch (wdev->iftype) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: if (wdev->ssid_len == 0) { wil_err(wil, "SSID not set\n"); return -EINVAL; } rc = wmi_set_ssid(wil, wdev->ssid_len, wdev->ssid); if (rc) return rc; break; default: break; } /* MAC address - pre-requisite for other commands */ wmi_set_mac_address(wil, ndev->dev_addr); /* Set up beaconing if required. */ if (bi > 0) { rc = wmi_pcp_start(wil, bi, wmi_nettype, (channel ? channel->hw_value : 0)); if (rc) return rc; } /* Rx VRING. After MAC and beacon */ wil_rx_init(wil); return 0; }
static int wil_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ap_settings *info) { int rc = 0; struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct wireless_dev *wdev = ndev->ieee80211_ptr; struct ieee80211_channel *channel = info->chandef.chan; struct cfg80211_beacon_data *bcon = &info->beacon; u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); if (!channel) { wil_err(wil, "AP: No channel???\n"); return -EINVAL; } wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value, channel->center_freq, info->privacy ? "secure" : "open"); print_hex_dump_bytes("SSID ", DUMP_PREFIX_OFFSET, info->ssid, info->ssid_len); if (wil_fix_bcon(wil, bcon)) wil_dbg_misc(wil, "Fixed bcon\n"); mutex_lock(&wil->mutex); rc = wil_reset(wil); if (rc) goto out; /* Rx VRING. */ rc = wil_rx_init(wil); if (rc) goto out; rc = wmi_set_ssid(wil, info->ssid_len, info->ssid); if (rc) goto out; /* MAC address - pre-requisite for other commands */ wmi_set_mac_address(wil, ndev->dev_addr); /* IE's */ /* bcon 'head IE's are not relevant for 60g band */ /* * FW do not form regular beacon, so bcon IE's are not set * For the DMG bcon, when it will be supported, bcon IE's will * be reused; add something like: * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, * bcon->beacon_ies); */ wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len, bcon->proberesp_ies); wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, bcon->assocresp_ies); wil->secure_pcp = info->privacy; rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, channel->hw_value); if (rc) goto out; netif_carrier_on(ndev); out: mutex_unlock(&wil->mutex); return rc; }
/* Bus ops */ static int wil_if_pcie_enable(struct wil6210_priv *wil) { struct pci_dev *pdev = wil->pdev; int rc; /* on platforms with buggy ACPI, pdev->msi_enabled may be set to * allow pci_enable_device to work. This indicates INTx was not routed * and only MSI should be used */ int msi_only = pdev->msi_enabled; wil_dbg_misc(wil, "%s()\n", __func__); pdev->msi_enabled = 0; pci_set_master(pdev); /* * how many MSI interrupts to request? */ switch (use_msi) { case 3: case 1: wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); break; case 0: wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); break; default: wil_err(wil, "Invalid use_msi=%d, default to 1\n", use_msi); use_msi = 1; } if (use_msi == 3 && pci_enable_msi_range(pdev, 3, 3) < 0) { wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); use_msi = 1; } if (use_msi == 1 && pci_enable_msi(pdev)) { wil_err(wil, "pci_enable_msi failed, use INTx\n"); use_msi = 0; } wil->n_msi = use_msi; if ((wil->n_msi == 0) && msi_only) { wil_err(wil, "Interrupt pin not routed, unable to use INTx\n"); rc = -ENODEV; goto stop_master; } rc = wil6210_init_irq(wil, pdev->irq); if (rc) goto stop_master; /* need reset here to obtain MAC */ mutex_lock(&wil->mutex); rc = wil_reset(wil); mutex_unlock(&wil->mutex); if (debug_fw) rc = 0; if (rc) goto release_irq; return 0; release_irq: wil6210_fini_irq(wil, pdev->irq); /* safe to call if no MSI */ pci_disable_msi(pdev); stop_master: pci_clear_master(pdev); return rc; }