diff options
Diffstat (limited to 'drivers/net/wireless/quantenna')
22 files changed, 2144 insertions, 2576 deletions
| diff --git a/drivers/net/wireless/quantenna/Kconfig b/drivers/net/wireless/quantenna/Kconfig index de84ce125c26..7628d9c1ea6a 100644 --- a/drivers/net/wireless/quantenna/Kconfig +++ b/drivers/net/wireless/quantenna/Kconfig @@ -1,7 +1,7 @@  config WLAN_VENDOR_QUANTENNA  	bool "Quantenna wireless cards support"  	default y -	---help--- +	help  	  If you have a wireless card belonging to this class, say Y.  	  Note that the answer to this question doesn't directly affect the diff --git a/drivers/net/wireless/quantenna/qtnfmac/Kconfig b/drivers/net/wireless/quantenna/qtnfmac/Kconfig index 8d1492a90bd1..b8c12a5f16b4 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/Kconfig +++ b/drivers/net/wireless/quantenna/qtnfmac/Kconfig @@ -11,7 +11,7 @@ config QTNFMAC_PEARL_PCIE  	select QTNFMAC  	select FW_LOADER  	select CRC32 -	---help--- +	help  	  This option adds support for wireless adapters based on Quantenna  	  802.11ac QSR10g (aka Pearl) FullMAC chipset running over PCIe. diff --git a/drivers/net/wireless/quantenna/qtnfmac/Makefile b/drivers/net/wireless/quantenna/qtnfmac/Makefile index 97f760a3d599..17cd7adb4109 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/Makefile +++ b/drivers/net/wireless/quantenna/qtnfmac/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_QTNFMAC_PEARL_PCIE) += qtnfmac_pearl_pcie.o  qtnfmac_pearl_pcie-objs += \  	shm_ipc.o \ -	pearl/pcie.o +	pcie/pcie.o \ +	pcie/pearl_pcie.o  qtnfmac_pearl_pcie-$(CONFIG_DEBUG_FS) += debug.o diff --git a/drivers/net/wireless/quantenna/qtnfmac/bus.h b/drivers/net/wireless/quantenna/qtnfmac/bus.h index 323e47cea1e2..528ca7f5e070 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/bus.h +++ b/drivers/net/wireless/quantenna/qtnfmac/bus.h @@ -20,6 +20,9 @@  #include <linux/netdevice.h>  #include <linux/workqueue.h> +#include "trans.h" +#include "core.h" +  #define QTNF_MAX_MAC		3  enum qtnf_fw_state { @@ -57,10 +60,8 @@ struct qtnf_bus {  	struct qtnf_wmac *mac[QTNF_MAX_MAC];  	struct qtnf_qlink_transport trans;  	struct qtnf_hw_info hw_info; -	char fwname[32];  	struct napi_struct mux_napi;  	struct net_device mux_dev; -	struct completion firmware_init_complete;  	struct workqueue_struct *workqueue;  	struct work_struct fw_work;  	struct work_struct event_work; diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 4aa332f4646b..51b33ec78fac 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -141,8 +141,8 @@ qtnf_change_virtual_intf(struct wiphy *wiphy,  	ret = qtnf_cmd_send_change_intf_type(vif, type, mac_addr);  	if (ret) { -		pr_err("VIF%u.%u: failed to change VIF type: %d\n", -		       vif->mac->macid, vif->vifid, ret); +		pr_err("VIF%u.%u: failed to change type to %d\n", +		       vif->mac->macid, vif->vifid, type);  		return ret;  	} @@ -216,7 +216,6 @@ static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy,  		eth_zero_addr(vif->mac_addr);  		eth_zero_addr(vif->bssid);  		vif->bss_priority = QTNF_DEF_BSS_PRIORITY; -		vif->sta_state = QTNF_STA_DISCONNECTED;  		memset(&vif->wdev, 0, sizeof(vif->wdev));  		vif->wdev.wiphy = wiphy;  		vif->wdev.iftype = type; @@ -229,18 +228,22 @@ static struct wireless_dev *qtnf_add_virtual_intf(struct wiphy *wiphy,  	if (params)  		mac_addr = params->macaddr; -	if (qtnf_cmd_send_add_intf(vif, type, mac_addr)) { -		pr_err("VIF%u.%u: failed to add VIF\n", mac->macid, vif->vifid); +	ret = qtnf_cmd_send_add_intf(vif, type, mac_addr); +	if (ret) { +		pr_err("VIF%u.%u: failed to add VIF %pM\n", +		       mac->macid, vif->vifid, mac_addr);  		goto err_cmd;  	}  	if (!is_valid_ether_addr(vif->mac_addr)) {  		pr_err("VIF%u.%u: FW reported bad MAC: %pM\n",  		       mac->macid, vif->vifid, vif->mac_addr); +		ret = -EINVAL;  		goto err_mac;  	} -	if (qtnf_core_net_attach(mac, vif, name, name_assign_t)) { +	ret = qtnf_core_net_attach(mac, vif, name, name_assign_t); +	if (ret) {  		pr_err("VIF%u.%u: failed to attach netdev\n", mac->macid,  		       vif->vifid);  		goto err_net; @@ -256,7 +259,7 @@ err_mac:  err_cmd:  	vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; -	return ERR_PTR(-EFAULT); +	return ERR_PTR(ret);  }  static int qtnf_mgmt_set_appie(struct qtnf_vif *vif, @@ -335,12 +338,11 @@ static int qtnf_stop_ap(struct wiphy *wiphy, struct net_device *dev)  	qtnf_scan_done(vif->mac, true);  	ret = qtnf_cmd_send_stop_ap(vif); -	if (ret) { +	if (ret)  		pr_err("VIF%u.%u: failed to stop AP operation in FW\n",  		       vif->mac->macid, vif->vifid); -		netif_carrier_off(vif->netdev); -	} +	netif_carrier_off(vif->netdev);  	return ret;  } @@ -478,19 +480,31 @@ qtnf_dump_station(struct wiphy *wiphy, struct net_device *dev,  	const struct qtnf_sta_node *sta_node;  	int ret; -	sta_node = qtnf_sta_list_lookup_index(&vif->sta_list, idx); +	switch (vif->wdev.iftype) { +	case NL80211_IFTYPE_STATION: +		if (idx != 0 || !vif->wdev.current_bss) +			return -ENOENT; -	if (unlikely(!sta_node)) -		return -ENOENT; +		ether_addr_copy(mac, vif->bssid); +		break; +	case NL80211_IFTYPE_AP: +		sta_node = qtnf_sta_list_lookup_index(&vif->sta_list, idx); +		if (unlikely(!sta_node)) +			return -ENOENT; -	ether_addr_copy(mac, sta_node->mac_addr); +		ether_addr_copy(mac, sta_node->mac_addr); +		break; +	default: +		return -ENOTSUPP; +	} -	ret = qtnf_cmd_get_sta_info(vif, sta_node->mac_addr, sinfo); +	ret = qtnf_cmd_get_sta_info(vif, mac, sinfo); -	if (unlikely(ret == -ENOENT)) { -		qtnf_sta_list_del(vif, mac); -		cfg80211_del_sta(vif->netdev, mac, GFP_KERNEL); -		sinfo->filled = 0; +	if (vif->wdev.iftype == NL80211_IFTYPE_AP) { +		if (ret == -ENOENT) { +			cfg80211_del_sta(vif->netdev, mac, GFP_KERNEL); +			sinfo->filled = 0; +		}  	}  	sinfo->generation = vif->generation; @@ -521,9 +535,16 @@ static int qtnf_del_key(struct wiphy *wiphy, struct net_device *dev,  	int ret;  	ret = qtnf_cmd_send_del_key(vif, key_index, pairwise, mac_addr); -	if (ret) -		pr_err("VIF%u.%u: failed to delete key: idx=%u pw=%u\n", -		       vif->mac->macid, vif->vifid, key_index, pairwise); +	if (ret) { +		if (ret == -ENOENT) { +			pr_debug("VIF%u.%u: key index %d out of bounds\n", +				 vif->mac->macid, vif->vifid, key_index); +		} else { +			pr_err("VIF%u.%u: failed to delete key: idx=%u pw=%u\n", +			       vif->mac->macid, vif->vifid, +			       key_index, pairwise); +		} +	}  	return ret;  } @@ -590,6 +611,7 @@ qtnf_del_station(struct wiphy *wiphy, struct net_device *dev,  	if (ret)  		pr_err("VIF%u.%u: failed to delete STA %pM\n",  		       vif->mac->macid, vif->vifid, params->mac); +  	return ret;  } @@ -597,21 +619,25 @@ static int  qtnf_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)  {  	struct qtnf_wmac *mac = wiphy_priv(wiphy); +	int ret;  	cancel_delayed_work_sync(&mac->scan_timeout);  	mac->scan_req = request; -	if (qtnf_cmd_send_scan(mac)) { +	ret = qtnf_cmd_send_scan(mac); +	if (ret) {  		pr_err("MAC%u: failed to start scan\n", mac->macid);  		mac->scan_req = NULL; -		return -EFAULT; +		goto out;  	} +	pr_debug("MAC%u: scan started\n", mac->macid);  	queue_delayed_work(mac->bus->workqueue, &mac->scan_timeout,  			   QTNF_SCAN_TIMEOUT_SEC * HZ); -	return 0; +out: +	return ret;  }  static int @@ -624,9 +650,6 @@ qtnf_connect(struct wiphy *wiphy, struct net_device *dev,  	if (vif->wdev.iftype != NL80211_IFTYPE_STATION)  		return -EOPNOTSUPP; -	if (vif->sta_state != QTNF_STA_DISCONNECTED) -		return -EBUSY; -  	if (sme->bssid)  		ether_addr_copy(vif->bssid, sme->bssid);  	else @@ -634,13 +657,13 @@ qtnf_connect(struct wiphy *wiphy, struct net_device *dev,  	ret = qtnf_cmd_send_connect(vif, sme);  	if (ret) { -		pr_err("VIF%u.%u: failed to connect\n", vif->mac->macid, -		       vif->vifid); -		return ret; +		pr_err("VIF%u.%u: failed to connect\n", +		       vif->mac->macid, vif->vifid); +		goto out;  	} -	vif->sta_state = QTNF_STA_CONNECTING; -	return 0; +out: +	return ret;  }  static int @@ -662,22 +685,18 @@ qtnf_disconnect(struct wiphy *wiphy, struct net_device *dev,  		goto out;  	} -	qtnf_scan_done(mac, true); - -	if (vif->sta_state == QTNF_STA_DISCONNECTED) -		goto out; -  	ret = qtnf_cmd_send_disconnect(vif, reason_code); -	if (ret) { -		pr_err("VIF%u.%u: failed to disconnect\n", mac->macid, -		       vif->vifid); -		goto out; +	if (ret) +		pr_err("VIF%u.%u: failed to disconnect\n", +		       mac->macid, vif->vifid); + +	if (vif->wdev.current_bss) { +		netif_carrier_off(vif->netdev); +		cfg80211_disconnected(vif->netdev, reason_code, +				      NULL, 0, true, GFP_KERNEL);  	}  out: -	if (vif->sta_state == QTNF_STA_CONNECTING) -		vif->sta_state = QTNF_STA_DISCONNECTED; -  	return ret;  } @@ -691,11 +710,8 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev,  	const struct cfg80211_chan_def *chandef = &wdev->chandef;  	struct ieee80211_channel *chan;  	struct qtnf_chan_stats stats; -	struct qtnf_vif *vif;  	int ret; -	vif = qtnf_netdev_get_priv(dev); -  	sband = wiphy->bands[NL80211_BAND_2GHZ];  	if (sband && idx >= sband->n_channels) {  		idx -= sband->n_channels; @@ -750,7 +766,6 @@ qtnf_dump_survey(struct wiphy *wiphy, struct net_device *dev,  	default:  		pr_debug("failed to get chan(%d) stats from card\n",  			 chan->hw_value); -		ret = -EINVAL;  		break;  	} @@ -773,6 +788,7 @@ qtnf_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,  	ret = qtnf_cmd_get_channel(vif, chandef);  	if (ret) {  		pr_err("%s: failed to get channel: %d\n", ndev->name, ret); +		ret = -ENODATA;  		goto out;  	} @@ -782,6 +798,7 @@ qtnf_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,  		       chandef->center_freq1, chandef->center_freq2,  		       chandef->width);  		ret = -ENODATA; +		goto out;  	}  out: @@ -851,10 +868,8 @@ static int qtnf_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,  	ret = qtnf_cmd_send_pm_set(vif, enabled ? QLINK_PM_AUTO_STANDBY :  				   QLINK_PM_OFF, timeout); -	if (ret) { +	if (ret)  		pr_err("%s: failed to set PM mode ret=%d\n", dev->name, ret); -		return ret; -	}  	return ret;  } @@ -974,9 +989,16 @@ static void qtnf_cfg80211_reg_notifier(struct wiphy *wiphy_in,  	ret = qtnf_cmd_reg_notify(bus, req);  	if (ret) { -		if (ret != -EOPNOTSUPP && ret != -EALREADY) +		if (ret == -EOPNOTSUPP) { +			pr_warn("reg update not supported\n"); +		} else if (ret == -EALREADY) { +			pr_info("regulatory domain is already set to %c%c", +				req->alpha2[0], req->alpha2[1]); +		} else {  			pr_err("failed to update reg domain to %c%c\n",  			       req->alpha2[0], req->alpha2[1]); +		} +  		return;  	} @@ -1091,6 +1113,10 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)  	if (hw_info->hw_capab & QLINK_HW_CAPAB_DFS_OFFLOAD)  		wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD); +	if (hw_info->hw_capab & QLINK_HW_CAPAB_SCAN_DWELL) +		wiphy_ext_feature_set(wiphy, +				      NL80211_EXT_FEATURE_SET_SCAN_DWELL); +  	wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |  				    NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2; @@ -1109,6 +1135,9 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)  	if (hw_info->hw_capab & QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR)  		wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; +	if (!(hw_info->hw_capab & QLINK_HW_CAPAB_OBSS_SCAN)) +		wiphy->features |= NL80211_FEATURE_NEED_OBSS_SCAN; +  #ifdef CONFIG_PM  	if (macinfo->wowlan)  		wiphy->wowlan = macinfo->wowlan; @@ -1123,6 +1152,15 @@ int qtnf_wiphy_register(struct qtnf_hw_info *hw_info, struct qtnf_wmac *mac)  		wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;  	} +	if (mac->macinfo.extended_capabilities_len) { +		wiphy->extended_capabilities = +			mac->macinfo.extended_capabilities; +		wiphy->extended_capabilities_mask = +			mac->macinfo.extended_capabilities_mask; +		wiphy->extended_capabilities_len = +			mac->macinfo.extended_capabilities_len; +	} +  	strlcpy(wiphy->fw_version, hw_info->fw_version,  		sizeof(wiphy->fw_version));  	wiphy->hw_version = hw_info->hw_version; @@ -1146,7 +1184,8 @@ void qtnf_netdev_updown(struct net_device *ndev, bool up)  	struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);  	if (qtnf_cmd_send_updown_intf(vif, up)) -		pr_err("failed to send up/down command to FW\n"); +		pr_err("failed to send %s command to VIF%u.%u\n", +		       up ? "UP" : "DOWN", vif->mac->macid, vif->vifid);  }  void qtnf_virtual_intf_cleanup(struct net_device *ndev) @@ -1154,57 +1193,20 @@ void qtnf_virtual_intf_cleanup(struct net_device *ndev)  	struct qtnf_vif *vif = qtnf_netdev_get_priv(ndev);  	struct qtnf_wmac *mac = wiphy_priv(vif->wdev.wiphy); -	if (vif->wdev.iftype == NL80211_IFTYPE_STATION) { -		switch (vif->sta_state) { -		case QTNF_STA_DISCONNECTED: -			break; -		case QTNF_STA_CONNECTING: -			cfg80211_connect_result(vif->netdev, -						vif->bssid, NULL, 0, -						NULL, 0, -						WLAN_STATUS_UNSPECIFIED_FAILURE, -						GFP_KERNEL); -			qtnf_disconnect(vif->wdev.wiphy, ndev, -					WLAN_REASON_DEAUTH_LEAVING); -			break; -		case QTNF_STA_CONNECTED: -			cfg80211_disconnected(vif->netdev, -					      WLAN_REASON_DEAUTH_LEAVING, -					      NULL, 0, 1, GFP_KERNEL); -			qtnf_disconnect(vif->wdev.wiphy, ndev, -					WLAN_REASON_DEAUTH_LEAVING); -			break; -		} - -		vif->sta_state = QTNF_STA_DISCONNECTED; -	} +	if (vif->wdev.iftype == NL80211_IFTYPE_STATION) +		qtnf_disconnect(vif->wdev.wiphy, ndev, +				WLAN_REASON_DEAUTH_LEAVING);  	qtnf_scan_done(mac, true);  }  void qtnf_cfg80211_vif_reset(struct qtnf_vif *vif)  { -	if (vif->wdev.iftype == NL80211_IFTYPE_STATION) { -		switch (vif->sta_state) { -		case QTNF_STA_CONNECTING: -			cfg80211_connect_result(vif->netdev, -						vif->bssid, NULL, 0, -						NULL, 0, -						WLAN_STATUS_UNSPECIFIED_FAILURE, -						GFP_KERNEL); -			break; -		case QTNF_STA_CONNECTED: -			cfg80211_disconnected(vif->netdev, -					      WLAN_REASON_DEAUTH_LEAVING, -					      NULL, 0, 1, GFP_KERNEL); -			break; -		case QTNF_STA_DISCONNECTED: -			break; -		} -	} +	if (vif->wdev.iftype == NL80211_IFTYPE_STATION) +		cfg80211_disconnected(vif->netdev, WLAN_REASON_DEAUTH_LEAVING, +				      NULL, 0, 1, GFP_KERNEL);  	cfg80211_shutdown_all_interfaces(vif->wdev.wiphy); -	vif->sta_state = QTNF_STA_DISCONNECTED;  }  void qtnf_band_init_rates(struct ieee80211_supported_band *band) diff --git a/drivers/net/wireless/quantenna/qtnfmac/commands.c b/drivers/net/wireless/quantenna/qtnfmac/commands.c index ae9e77300533..bfdc1ad30c13 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/commands.c +++ b/drivers/net/wireless/quantenna/qtnfmac/commands.c @@ -80,7 +80,6 @@ static int qtnf_cmd_resp_result_decode(enum qlink_cmd_result qcode)  static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus,  				    struct sk_buff *cmd_skb,  				    struct sk_buff **response_skb, -				    u16 *result_code,  				    size_t const_resp_size,  				    size_t *var_resp_size)  { @@ -88,7 +87,8 @@ static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus,  	const struct qlink_resp *resp;  	struct sk_buff *resp_skb = NULL;  	u16 cmd_id; -	u8 mac_id, vif_id; +	u8 mac_id; +	u8 vif_id;  	int ret;  	cmd = (struct qlink_cmd *)cmd_skb->data; @@ -97,8 +97,11 @@ static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus,  	vif_id = cmd->vifid;  	cmd->mhdr.len = cpu_to_le16(cmd_skb->len); -	if (unlikely(bus->fw_state != QTNF_FW_STATE_ACTIVE && -		     le16_to_cpu(cmd->cmd_id) != QLINK_CMD_FW_INIT)) { +	pr_debug("VIF%u.%u cmd=0x%.4X\n", mac_id, vif_id, +		 le16_to_cpu(cmd->cmd_id)); + +	if (bus->fw_state != QTNF_FW_STATE_ACTIVE && +	    le16_to_cpu(cmd->cmd_id) != QLINK_CMD_FW_INIT) {  		pr_warn("VIF%u.%u: drop cmd 0x%.4X in fw state %d\n",  			mac_id, vif_id, le16_to_cpu(cmd->cmd_id),  			bus->fw_state); @@ -106,24 +109,16 @@ static int qtnf_cmd_send_with_reply(struct qtnf_bus *bus,  		return -ENODEV;  	} -	pr_debug("VIF%u.%u cmd=0x%.4X\n", mac_id, vif_id, -		 le16_to_cpu(cmd->cmd_id)); -  	ret = qtnf_trans_send_cmd_with_resp(bus, cmd_skb, &resp_skb); - -	if (unlikely(ret)) +	if (ret)  		goto out;  	resp = (const struct qlink_resp *)resp_skb->data;  	ret = qtnf_cmd_check_reply_header(resp, cmd_id, mac_id, vif_id,  					  const_resp_size); - -	if (unlikely(ret)) +	if (ret)  		goto out; -	if (likely(result_code)) -		*result_code = le16_to_cpu(resp->result); -  	/* Return length of variable part of response */  	if (response_skb && var_resp_size)  		*var_resp_size = le16_to_cpu(resp->mhdr.len) - const_resp_size; @@ -134,14 +129,18 @@ out:  	else  		consume_skb(resp_skb); +	if (!ret && resp) +		return qtnf_cmd_resp_result_decode(le16_to_cpu(resp->result)); + +	pr_warn("VIF%u.%u: cmd 0x%.4X failed: %d\n", +		mac_id, vif_id, le16_to_cpu(cmd->cmd_id), ret); +  	return ret;  } -static inline int qtnf_cmd_send(struct qtnf_bus *bus, -				struct sk_buff *cmd_skb, -				u16 *result_code) +static inline int qtnf_cmd_send(struct qtnf_bus *bus, struct sk_buff *cmd_skb)  { -	return qtnf_cmd_send_with_reply(bus, cmd_skb, NULL, result_code, +	return qtnf_cmd_send_with_reply(bus, cmd_skb, NULL,  					sizeof(struct qlink_resp), NULL);  } @@ -228,7 +227,6 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,  	struct sk_buff *cmd_skb;  	struct qlink_cmd_start_ap *cmd;  	struct qlink_auth_encr *aen; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret;  	int i; @@ -329,30 +327,21 @@ int qtnf_cmd_send_start_ap(struct qtnf_vif *vif,  	}  	qtnf_bus_lock(vif->mac->bus); - -	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - -	if (unlikely(ret)) -		goto out; - -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, -		       vif->vifid, res_code); -		ret = -EFAULT; +	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); +	if (ret)  		goto out; -	}  	netif_carrier_on(vif->netdev);  out:  	qtnf_bus_unlock(vif->mac->bus); +  	return ret;  }  int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif)  {  	struct sk_buff *cmd_skb; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -362,23 +351,13 @@ int qtnf_cmd_send_stop_ap(struct qtnf_vif *vif)  		return -ENOMEM;  	qtnf_bus_lock(vif->mac->bus); - -	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - -	if (unlikely(ret)) -		goto out; - -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, -		       vif->vifid, res_code); -		ret = -EFAULT; +	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); +	if (ret)  		goto out; -	} - -	netif_carrier_off(vif->netdev);  out:  	qtnf_bus_unlock(vif->mac->bus); +  	return ret;  } @@ -386,7 +365,6 @@ int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg)  {  	struct sk_buff *cmd_skb;  	struct qlink_cmd_mgmt_frame_register *cmd; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -401,20 +379,13 @@ int qtnf_cmd_send_register_mgmt(struct qtnf_vif *vif, u16 frame_type, bool reg)  	cmd->frame_type = cpu_to_le16(frame_type);  	cmd->do_register = reg; -	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - -	if (unlikely(ret)) -		goto out; - -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, -		       vif->vifid, res_code); -		ret = -EFAULT; +	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); +	if (ret)  		goto out; -	}  out:  	qtnf_bus_unlock(vif->mac->bus); +  	return ret;  } @@ -423,7 +394,6 @@ int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags,  {  	struct sk_buff *cmd_skb;  	struct qlink_cmd_mgmt_frame_tx *cmd; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret;  	if (sizeof(*cmd) + len > QTNF_MAX_CMD_BUF_SIZE) { @@ -448,20 +418,13 @@ int qtnf_cmd_send_mgmt_frame(struct qtnf_vif *vif, u32 cookie, u16 flags,  	if (len && buf)  		qtnf_cmd_skb_put_buffer(cmd_skb, buf, len); -	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - -	if (unlikely(ret)) +	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); +	if (ret)  		goto out; -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, -		       vif->vifid, res_code); -		ret = -EFAULT; -		goto out; -	} -  out:  	qtnf_bus_unlock(vif->mac->bus); +  	return ret;  } @@ -469,7 +432,6 @@ int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type,  				 const u8 *buf, size_t len)  {  	struct sk_buff *cmd_skb; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret;  	if (len > QTNF_MAX_CMD_BUF_SIZE) { @@ -487,21 +449,13 @@ int qtnf_cmd_send_mgmt_set_appie(struct qtnf_vif *vif, u8 frame_type,  	qtnf_cmd_tlv_ie_set_add(cmd_skb, frame_type, buf, len);  	qtnf_bus_lock(vif->mac->bus); - -	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - -	if (unlikely(ret)) -		goto out; - -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("VIF%u.%u frame %u: CMD failed: %u\n", vif->mac->macid, -		       vif->vifid, frame_type, res_code); -		ret = -EFAULT; +	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); +	if (ret)  		goto out; -	}  out:  	qtnf_bus_unlock(vif->mac->bus); +  	return ret;  } @@ -544,6 +498,9 @@ qtnf_sta_info_parse_rate(struct rate_info *rate_dst,  		rate_dst->flags |= RATE_INFO_FLAGS_MCS;  	else if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_VHT_MCS)  		rate_dst->flags |= RATE_INFO_FLAGS_VHT_MCS; + +	if (rate_src->flags & QLINK_STA_INFO_RATE_FLAG_SHORT_GI) +		rate_dst->flags |= RATE_INFO_FLAGS_SHORT_GI;  }  static void @@ -730,7 +687,6 @@ int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac,  	struct qlink_cmd_get_sta_info *cmd;  	const struct qlink_resp_get_sta_info *resp;  	size_t var_resp_len; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret = 0;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -745,31 +701,13 @@ int qtnf_cmd_get_sta_info(struct qtnf_vif *vif, const u8 *sta_mac,  	ether_addr_copy(cmd->sta_addr, sta_mac);  	ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb, -				       &res_code, sizeof(*resp), -				       &var_resp_len); - -	if (unlikely(ret)) -		goto out; - -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		switch (res_code) { -		case QLINK_CMD_RESULT_ENOTFOUND: -			pr_warn("VIF%u.%u: %pM STA not found\n", -				vif->mac->macid, vif->vifid, sta_mac); -			ret = -ENOENT; -			break; -		default: -			pr_err("VIF%u.%u: can't get info for %pM: %u\n", -			       vif->mac->macid, vif->vifid, sta_mac, res_code); -			ret = -EFAULT; -			break; -		} +				       sizeof(*resp), &var_resp_len); +	if (ret)  		goto out; -	}  	resp = (const struct qlink_resp_get_sta_info *)resp_skb->data; -	if (unlikely(!ether_addr_equal(sta_mac, resp->sta_addr))) { +	if (!ether_addr_equal(sta_mac, resp->sta_addr)) {  		pr_err("VIF%u.%u: wrong mac in reply: %pM != %pM\n",  		       vif->mac->macid, vif->vifid, resp->sta_addr, sta_mac);  		ret = -EINVAL; @@ -795,7 +733,6 @@ static int qtnf_cmd_send_add_change_intf(struct qtnf_vif *vif,  	struct sk_buff *cmd_skb, *resp_skb = NULL;  	struct qlink_cmd_manage_intf *cmd;  	const struct qlink_resp_manage_intf *resp; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret = 0;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -828,17 +765,9 @@ static int qtnf_cmd_send_add_change_intf(struct qtnf_vif *vif,  		eth_zero_addr(cmd->intf_info.mac_addr);  	ret = qtnf_cmd_send_with_reply(vif->mac->bus, cmd_skb, &resp_skb, -				       &res_code, sizeof(*resp), NULL); - -	if (unlikely(ret)) -		goto out; - -	ret = qtnf_cmd_resp_result_decode(res_code); -	if (ret) { -		pr_err("VIF%u.%u: CMD %d failed: %u\n", vif->mac->macid, -		       vif->vifid, cmd_type, res_code); +				       sizeof(*resp), NULL); +	if (ret)  		goto out; -	}  	resp = (const struct qlink_resp_manage_intf *)resp_skb->data;  	ether_addr_copy(vif->mac_addr, resp->intf_info.mac_addr); @@ -868,7 +797,6 @@ int qtnf_cmd_send_del_intf(struct qtnf_vif *vif)  {  	struct sk_buff *cmd_skb;  	struct qlink_cmd_manage_intf *cmd; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret = 0;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -897,17 +825,9 @@ int qtnf_cmd_send_del_intf(struct qtnf_vif *vif)  	eth_zero_addr(cmd->intf_info.mac_addr); -	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - -	if (unlikely(ret)) -		goto out; - -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, -		       vif->vifid, res_code); -		ret = -EFAULT; +	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); +	if (ret)  		goto out; -	}  out:  	qtnf_bus_unlock(vif->mac->bus); @@ -1353,8 +1273,7 @@ static int qtnf_parse_variable_mac_info(struct qtnf_wmac *mac,  		ext_capa_mask = NULL;  	} -	kfree(mac->macinfo.extended_capabilities); -	kfree(mac->macinfo.extended_capabilities_mask); +	qtnf_mac_ext_caps_free(mac);  	mac->macinfo.extended_capabilities = ext_capa;  	mac->macinfo.extended_capabilities_mask = ext_capa_mask;  	mac->macinfo.extended_capabilities_len = ext_capa_len; @@ -1732,7 +1651,6 @@ int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac)  	struct sk_buff *cmd_skb, *resp_skb = NULL;  	const struct qlink_resp_get_mac_info *resp;  	size_t var_data_len; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret = 0;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, @@ -1742,18 +1660,11 @@ int qtnf_cmd_get_mac_info(struct qtnf_wmac *mac)  		return -ENOMEM;  	qtnf_bus_lock(mac->bus); - -	ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, +	ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb,  				       sizeof(*resp), &var_data_len); -	if (unlikely(ret)) +	if (ret)  		goto out; -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); -		ret = -EFAULT; -		goto out; -	} -  	resp = (const struct qlink_resp_get_mac_info *)resp_skb->data;  	qtnf_cmd_resp_proc_mac_info(mac, resp);  	ret = qtnf_parse_variable_mac_info(mac, resp->var_info, var_data_len); @@ -1769,7 +1680,6 @@ int qtnf_cmd_get_hw_info(struct qtnf_bus *bus)  {  	struct sk_buff *cmd_skb, *resp_skb = NULL;  	const struct qlink_resp_get_hw_info *resp; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret = 0;  	size_t info_len; @@ -1780,18 +1690,10 @@ int qtnf_cmd_get_hw_info(struct qtnf_bus *bus)  		return -ENOMEM;  	qtnf_bus_lock(bus); - -	ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, &res_code, +	ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb,  				       sizeof(*resp), &info_len); - -	if (unlikely(ret)) -		goto out; - -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("cmd exec failed: 0x%.4X\n", res_code); -		ret = -EFAULT; +	if (ret)  		goto out; -	}  	resp = (const struct qlink_resp_get_hw_info *)resp_skb->data;  	ret = qtnf_cmd_resp_proc_hw_info(bus, resp, info_len); @@ -1810,7 +1712,6 @@ int qtnf_cmd_band_info_get(struct qtnf_wmac *mac,  	size_t info_len;  	struct qlink_cmd_band_info_get *cmd;  	struct qlink_resp_band_info_get *resp; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret = 0;  	u8 qband; @@ -1838,18 +1739,10 @@ int qtnf_cmd_band_info_get(struct qtnf_wmac *mac,  	cmd->band = qband;  	qtnf_bus_lock(mac->bus); - -	ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, +	ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb,  				       sizeof(*resp), &info_len); - -	if (unlikely(ret)) -		goto out; - -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); -		ret = -EFAULT; +	if (ret)  		goto out; -	}  	resp = (struct qlink_resp_band_info_get *)resp_skb->data;  	if (resp->band != qband) { @@ -1873,7 +1766,6 @@ int qtnf_cmd_send_get_phy_params(struct qtnf_wmac *mac)  	struct sk_buff *cmd_skb, *resp_skb = NULL;  	size_t response_size;  	struct qlink_resp_phy_params *resp; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret = 0;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, @@ -1883,19 +1775,11 @@ int qtnf_cmd_send_get_phy_params(struct qtnf_wmac *mac)  		return -ENOMEM;  	qtnf_bus_lock(mac->bus); - -	ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, +	ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb,  				       sizeof(*resp), &response_size); - -	if (unlikely(ret)) +	if (ret)  		goto out; -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); -		ret = -EFAULT; -		goto out; -	} -  	resp = (struct qlink_resp_phy_params *)resp_skb->data;  	ret = qtnf_cmd_resp_proc_phy_params(mac, resp->info, response_size); @@ -1910,7 +1794,6 @@ int qtnf_cmd_send_update_phy_params(struct qtnf_wmac *mac, u32 changed)  {  	struct wiphy *wiphy = priv_to_wiphy(mac);  	struct sk_buff *cmd_skb; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret = 0;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, 0, @@ -1931,26 +1814,19 @@ int qtnf_cmd_send_update_phy_params(struct qtnf_wmac *mac, u32 changed)  		qtnf_cmd_skb_put_tlv_u8(cmd_skb, QTN_TLV_ID_COVERAGE_CLASS,  					wiphy->coverage_class); -	ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); - -	if (unlikely(ret)) -		goto out; - -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); -		ret = -EFAULT; +	ret = qtnf_cmd_send(mac->bus, cmd_skb); +	if (ret)  		goto out; -	}  out:  	qtnf_bus_unlock(mac->bus); +  	return ret;  }  int qtnf_cmd_send_init_fw(struct qtnf_bus *bus)  {  	struct sk_buff *cmd_skb; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret = 0;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, @@ -1960,20 +1836,13 @@ int qtnf_cmd_send_init_fw(struct qtnf_bus *bus)  		return -ENOMEM;  	qtnf_bus_lock(bus); - -	ret = qtnf_cmd_send(bus, cmd_skb, &res_code); - -	if (unlikely(ret)) +	ret = qtnf_cmd_send(bus, cmd_skb); +	if (ret)  		goto out; -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("cmd exec failed: 0x%.4X\n", res_code); -		ret = -EFAULT; -		goto out; -	} -  out:  	qtnf_bus_unlock(bus); +  	return ret;  } @@ -1988,9 +1857,7 @@ void qtnf_cmd_send_deinit_fw(struct qtnf_bus *bus)  		return;  	qtnf_bus_lock(bus); - -	qtnf_cmd_send(bus, cmd_skb, NULL); - +	qtnf_cmd_send(bus, cmd_skb);  	qtnf_bus_unlock(bus);  } @@ -1999,7 +1866,6 @@ int qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,  {  	struct sk_buff *cmd_skb;  	struct qlink_cmd_add_key *cmd; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret = 0;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2031,19 +1897,13 @@ int qtnf_cmd_send_add_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,  					 params->seq,  					 params->seq_len); -	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); -	if (unlikely(ret)) +	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); +	if (ret)  		goto out; -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("VIF%u.%u: CMD failed: %u\n", -		       vif->mac->macid, vif->vifid, res_code); -		ret = -EFAULT; -		goto out; -	} -  out:  	qtnf_bus_unlock(vif->mac->bus); +  	return ret;  } @@ -2052,7 +1912,6 @@ int qtnf_cmd_send_del_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,  {  	struct sk_buff *cmd_skb;  	struct qlink_cmd_del_key *cmd; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret = 0;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2072,19 +1931,14 @@ int qtnf_cmd_send_del_key(struct qtnf_vif *vif, u8 key_index, bool pairwise,  	cmd->key_index = key_index;  	cmd->pairwise = pairwise; -	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); -	if (unlikely(ret)) -		goto out; -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("VIF%u.%u: CMD failed: %u\n", -		       vif->mac->macid, vif->vifid, res_code); -		ret = -EFAULT; +	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); +	if (ret)  		goto out; -	}  out:  	qtnf_bus_unlock(vif->mac->bus); +  	return ret;  } @@ -2093,7 +1947,6 @@ int qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index,  {  	struct sk_buff *cmd_skb;  	struct qlink_cmd_set_def_key *cmd; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret = 0;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2108,19 +1961,14 @@ int qtnf_cmd_send_set_default_key(struct qtnf_vif *vif, u8 key_index,  	cmd->key_index = key_index;  	cmd->unicast = unicast;  	cmd->multicast = multicast; -	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); -	if (unlikely(ret)) -		goto out; -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, -		       vif->vifid, res_code); -		ret = -EFAULT; +	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); +	if (ret)  		goto out; -	}  out:  	qtnf_bus_unlock(vif->mac->bus); +  	return ret;  } @@ -2128,7 +1976,6 @@ int qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif *vif, u8 key_index)  {  	struct sk_buff *cmd_skb;  	struct qlink_cmd_set_def_mgmt_key *cmd; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret = 0;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2141,19 +1988,14 @@ int qtnf_cmd_send_set_default_mgmt_key(struct qtnf_vif *vif, u8 key_index)  	cmd = (struct qlink_cmd_set_def_mgmt_key *)cmd_skb->data;  	cmd->key_index = key_index; -	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); -	if (unlikely(ret)) -		goto out; -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, -		       vif->vifid, res_code); -		ret = -EFAULT; +	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); +	if (ret)  		goto out; -	}  out:  	qtnf_bus_unlock(vif->mac->bus); +  	return ret;  } @@ -2183,7 +2025,6 @@ int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac,  {  	struct sk_buff *cmd_skb;  	struct qlink_cmd_change_sta *cmd; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret = 0;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2214,19 +2055,13 @@ int qtnf_cmd_send_change_sta(struct qtnf_vif *vif, const u8 *mac,  		goto out;  	} -	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); -	if (unlikely(ret)) -		goto out; - -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, -		       vif->vifid, res_code); -		ret = -EFAULT; +	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); +	if (ret)  		goto out; -	}  out:  	qtnf_bus_unlock(vif->mac->bus); +  	return ret;  } @@ -2235,7 +2070,6 @@ int qtnf_cmd_send_del_sta(struct qtnf_vif *vif,  {  	struct sk_buff *cmd_skb;  	struct qlink_cmd_del_sta *cmd; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret = 0;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2256,19 +2090,13 @@ int qtnf_cmd_send_del_sta(struct qtnf_vif *vif,  	cmd->subtype = params->subtype;  	cmd->reason_code = cpu_to_le16(params->reason_code); -	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); -	if (unlikely(ret)) +	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); +	if (ret)  		goto out; -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, -		       vif->vifid, res_code); -		ret = -EFAULT; -		goto out; -	} -  out:  	qtnf_bus_unlock(vif->mac->bus); +  	return ret;  } @@ -2312,7 +2140,6 @@ static void qtnf_cmd_randmac_tlv_add(struct sk_buff *cmd_skb,  int qtnf_cmd_send_scan(struct qtnf_wmac *mac)  {  	struct sk_buff *cmd_skb; -	u16 res_code = QLINK_CMD_RESULT_OK;  	struct ieee80211_channel *sc;  	struct cfg80211_scan_request *scan_req = mac->scan_req;  	int n_channels; @@ -2370,20 +2197,28 @@ int qtnf_cmd_send_scan(struct qtnf_wmac *mac)  					 scan_req->mac_addr_mask);  	} -	ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); +	if (scan_req->flags & NL80211_SCAN_FLAG_FLUSH) { +		pr_debug("MAC%u: flush cache before scan\n", mac->macid); -	if (unlikely(ret)) -		goto out; +		qtnf_cmd_skb_put_tlv_tag(cmd_skb, QTN_TLV_ID_SCAN_FLUSH); +	} -	pr_debug("MAC%u: scan started\n", mac->macid); +	if (scan_req->duration) { +		pr_debug("MAC%u: %s scan duration %u\n", mac->macid, +			 scan_req->duration_mandatory ? "mandatory" : "max", +			 scan_req->duration); -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("MAC%u: CMD failed: %u\n", mac->macid, res_code); -		ret = -EFAULT; -		goto out; +		qtnf_cmd_skb_put_tlv_u16(cmd_skb, QTN_TLV_ID_SCAN_DWELL, +					 scan_req->duration);  	} + +	ret = qtnf_cmd_send(mac->bus, cmd_skb); +	if (ret) +		goto out; +  out:  	qtnf_bus_unlock(mac->bus); +  	return ret;  } @@ -2393,7 +2228,6 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif,  	struct sk_buff *cmd_skb;  	struct qlink_cmd_connect *cmd;  	struct qlink_auth_encr *aen; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret;  	int i;  	u32 connect_flags = 0; @@ -2474,20 +2308,13 @@ int qtnf_cmd_send_connect(struct qtnf_vif *vif,  		qtnf_cmd_channel_tlv_add(cmd_skb, sme->channel);  	qtnf_bus_lock(vif->mac->bus); - -	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - -	if (unlikely(ret)) +	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); +	if (ret)  		goto out; -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, -		       vif->vifid, res_code); -		ret = -EFAULT; -		goto out; -	}  out:  	qtnf_bus_unlock(vif->mac->bus); +  	return ret;  } @@ -2495,7 +2322,6 @@ int qtnf_cmd_send_disconnect(struct qtnf_vif *vif, u16 reason_code)  {  	struct sk_buff *cmd_skb;  	struct qlink_cmd_disconnect *cmd; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2509,19 +2335,13 @@ int qtnf_cmd_send_disconnect(struct qtnf_vif *vif, u16 reason_code)  	cmd = (struct qlink_cmd_disconnect *)cmd_skb->data;  	cmd->reason = cpu_to_le16(reason_code); -	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - -	if (unlikely(ret)) +	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); +	if (ret)  		goto out; -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, -		       vif->vifid, res_code); -		ret = -EFAULT; -		goto out; -	}  out:  	qtnf_bus_unlock(vif->mac->bus); +  	return ret;  } @@ -2529,7 +2349,6 @@ int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, bool up)  {  	struct sk_buff *cmd_skb;  	struct qlink_cmd_updown *cmd; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2542,20 +2361,13 @@ int qtnf_cmd_send_updown_intf(struct qtnf_vif *vif, bool up)  	cmd->if_up = !!up;  	qtnf_bus_lock(vif->mac->bus); - -	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb, &res_code); - -	if (unlikely(ret)) +	ret = qtnf_cmd_send(vif->mac->bus, cmd_skb); +	if (ret)  		goto out; -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("VIF%u.%u: CMD failed: %u\n", vif->mac->macid, -		       vif->vifid, res_code); -		ret = -EFAULT; -		goto out; -	}  out:  	qtnf_bus_unlock(vif->mac->bus); +  	return ret;  } @@ -2563,7 +2375,6 @@ int qtnf_cmd_reg_notify(struct qtnf_bus *bus, struct regulatory_request *req)  {  	struct sk_buff *cmd_skb;  	int ret; -	u16 res_code;  	struct qlink_cmd_reg_notify *cmd;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(QLINK_MACID_RSVD, QLINK_VIFID_RSVD, @@ -2604,29 +2415,10 @@ int qtnf_cmd_reg_notify(struct qtnf_bus *bus, struct regulatory_request *req)  	}  	qtnf_bus_lock(bus); - -	ret = qtnf_cmd_send(bus, cmd_skb, &res_code); +	ret = qtnf_cmd_send(bus, cmd_skb);  	if (ret)  		goto out; -	switch (res_code) { -	case QLINK_CMD_RESULT_ENOTSUPP: -		pr_warn("reg update not supported\n"); -		ret = -EOPNOTSUPP; -		break; -	case QLINK_CMD_RESULT_EALREADY: -		pr_info("regulatory domain is already set to %c%c", -			req->alpha2[0], req->alpha2[1]); -		ret = -EALREADY; -		break; -	case QLINK_CMD_RESULT_OK: -		ret = 0; -		break; -	default: -		ret = -EFAULT; -		break; -	} -  out:  	qtnf_bus_unlock(bus); @@ -2640,7 +2432,6 @@ int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u16 channel,  	struct qlink_cmd_get_chan_stats *cmd;  	struct qlink_resp_get_chan_stats *resp;  	size_t var_data_len; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret = 0;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, QLINK_VIFID_RSVD, @@ -2654,25 +2445,10 @@ int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u16 channel,  	cmd = (struct qlink_cmd_get_chan_stats *)cmd_skb->data;  	cmd->channel = cpu_to_le16(channel); -	ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb, &res_code, +	ret = qtnf_cmd_send_with_reply(mac->bus, cmd_skb, &resp_skb,  				       sizeof(*resp), &var_data_len); -	if (unlikely(ret)) { -		qtnf_bus_unlock(mac->bus); -		return ret; -	} - -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		switch (res_code) { -		case QLINK_CMD_RESULT_ENOTFOUND: -			ret = -ENOENT; -			break; -		default: -			pr_err("cmd exec failed: 0x%.4X\n", res_code); -			ret = -EFAULT; -			break; -		} +	if (ret)  		goto out; -	}  	resp = (struct qlink_resp_get_chan_stats *)resp_skb->data;  	ret = qtnf_cmd_resp_proc_chan_stat_info(stats, resp->info, @@ -2681,6 +2457,7 @@ int qtnf_cmd_get_chan_stats(struct qtnf_wmac *mac, u16 channel,  out:  	qtnf_bus_unlock(mac->bus);  	consume_skb(resp_skb); +  	return ret;  } @@ -2690,7 +2467,6 @@ int qtnf_cmd_send_chan_switch(struct qtnf_vif *vif,  	struct qtnf_wmac *mac = vif->mac;  	struct qlink_cmd_chan_switch *cmd;  	struct sk_buff *cmd_skb; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(mac->macid, vif->vifid, @@ -2707,32 +2483,13 @@ int qtnf_cmd_send_chan_switch(struct qtnf_vif *vif,  	cmd->block_tx = params->block_tx;  	cmd->beacon_count = params->count; -	ret = qtnf_cmd_send(mac->bus, cmd_skb, &res_code); - -	if (unlikely(ret)) +	ret = qtnf_cmd_send(mac->bus, cmd_skb); +	if (ret)  		goto out; -	switch (res_code) { -	case QLINK_CMD_RESULT_OK: -		ret = 0; -		break; -	case QLINK_CMD_RESULT_ENOTFOUND: -		ret = -ENOENT; -		break; -	case QLINK_CMD_RESULT_ENOTSUPP: -		ret = -EOPNOTSUPP; -		break; -	case QLINK_CMD_RESULT_EALREADY: -		ret = -EALREADY; -		break; -	case QLINK_CMD_RESULT_INVALID: -	default: -		ret = -EFAULT; -		break; -	} -  out:  	qtnf_bus_unlock(mac->bus); +  	return ret;  } @@ -2742,7 +2499,6 @@ int qtnf_cmd_get_channel(struct qtnf_vif *vif, struct cfg80211_chan_def *chdef)  	const struct qlink_resp_channel_get *resp;  	struct sk_buff *cmd_skb;  	struct sk_buff *resp_skb = NULL; -	u16 res_code = QLINK_CMD_RESULT_OK;  	int ret;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2752,25 +2508,18 @@ int qtnf_cmd_get_channel(struct qtnf_vif *vif, struct cfg80211_chan_def *chdef)  		return -ENOMEM;  	qtnf_bus_lock(bus); - -	ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb, &res_code, +	ret = qtnf_cmd_send_with_reply(bus, cmd_skb, &resp_skb,  				       sizeof(*resp), NULL); - -	qtnf_bus_unlock(bus); - -	if (unlikely(ret)) +	if (ret)  		goto out; -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		ret = -ENODATA; -		goto out; -	} -  	resp = (const struct qlink_resp_channel_get *)resp_skb->data;  	qlink_chandef_q2cfg(priv_to_wiphy(vif->mac), &resp->chan, chdef);  out: +	qtnf_bus_unlock(bus);  	consume_skb(resp_skb); +  	return ret;  } @@ -2782,7 +2531,6 @@ int qtnf_cmd_start_cac(const struct qtnf_vif *vif,  	struct sk_buff *cmd_skb;  	struct qlink_cmd_start_cac *cmd;  	int ret; -	u16 res_code;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid,  					    QLINK_CMD_START_CAC, @@ -2795,19 +2543,12 @@ int qtnf_cmd_start_cac(const struct qtnf_vif *vif,  	qlink_chandef_cfg2q(chdef, &cmd->chan);  	qtnf_bus_lock(bus); -	ret = qtnf_cmd_send(bus, cmd_skb, &res_code); -	qtnf_bus_unlock(bus); - +	ret = qtnf_cmd_send(bus, cmd_skb);  	if (ret) -		return ret; +		goto out; -	switch (res_code) { -	case QLINK_CMD_RESULT_OK: -		break; -	default: -		ret = -EOPNOTSUPP; -		break; -	} +out: +	qtnf_bus_unlock(bus);  	return ret;  } @@ -2819,7 +2560,6 @@ int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif,  	struct sk_buff *cmd_skb;  	struct qlink_tlv_hdr *tlv;  	size_t acl_size = qtnf_cmd_acl_data_size(params); -	u16 res_code;  	int ret;  	cmd_skb = qtnf_cmd_alloc_new_cmdskb(vif->mac->macid, vif->vifid, @@ -2834,22 +2574,12 @@ int qtnf_cmd_set_mac_acl(const struct qtnf_vif *vif,  	qlink_acl_data_cfg2q(params, (struct qlink_acl_data *)tlv->val);  	qtnf_bus_lock(bus); -	ret = qtnf_cmd_send(bus, cmd_skb, &res_code); -	qtnf_bus_unlock(bus); - -	if (unlikely(ret)) -		return ret; +	ret = qtnf_cmd_send(bus, cmd_skb); +	if (ret) +		goto out; -	switch (res_code) { -	case QLINK_CMD_RESULT_OK: -		break; -	case QLINK_CMD_RESULT_INVALID: -		ret = -EINVAL; -		break; -	default: -		ret = -EOPNOTSUPP; -		break; -	} +out: +	qtnf_bus_unlock(bus);  	return ret;  } @@ -2858,7 +2588,6 @@ int qtnf_cmd_send_pm_set(const struct qtnf_vif *vif, u8 pm_mode, int timeout)  {  	struct qtnf_bus *bus = vif->mac->bus;  	struct sk_buff *cmd_skb; -	u16 res_code = QLINK_CMD_RESULT_OK;  	struct qlink_cmd_pm_set *cmd;  	int ret = 0; @@ -2873,18 +2602,13 @@ int qtnf_cmd_send_pm_set(const struct qtnf_vif *vif, u8 pm_mode, int timeout)  	qtnf_bus_lock(bus); -	ret = qtnf_cmd_send(bus, cmd_skb, &res_code); - -	if (unlikely(ret)) +	ret = qtnf_cmd_send(bus, cmd_skb); +	if (ret)  		goto out; -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("cmd exec failed: 0x%.4X\n", res_code); -		ret = -EFAULT; -	} -  out:  	qtnf_bus_unlock(bus); +  	return ret;  } @@ -2893,7 +2617,6 @@ int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif,  {  	struct qtnf_bus *bus = vif->mac->bus;  	struct sk_buff *cmd_skb; -	u16 res_code = QLINK_CMD_RESULT_OK;  	struct qlink_cmd_wowlan_set *cmd;  	u32 triggers = 0;  	int count = 0; @@ -2929,16 +2652,10 @@ int qtnf_cmd_send_wowlan_set(const struct qtnf_vif *vif,  	cmd->triggers = cpu_to_le32(triggers); -	ret = qtnf_cmd_send(bus, cmd_skb, &res_code); - -	if (unlikely(ret)) +	ret = qtnf_cmd_send(bus, cmd_skb); +	if (ret)  		goto out; -	if (unlikely(res_code != QLINK_CMD_RESULT_OK)) { -		pr_err("cmd exec failed: 0x%.4X\n", res_code); -		ret = -EFAULT; -	} -  out:  	qtnf_bus_unlock(bus);  	return ret; diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.c b/drivers/net/wireless/quantenna/qtnfmac/core.c index 19abbc4e23e0..5d18a4a917c9 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.c +++ b/drivers/net/wireless/quantenna/qtnfmac/core.c @@ -304,6 +304,19 @@ void qtnf_mac_iface_comb_free(struct qtnf_wmac *mac)  	}  } +void qtnf_mac_ext_caps_free(struct qtnf_wmac *mac) +{ +	if (mac->macinfo.extended_capabilities_len) { +		kfree(mac->macinfo.extended_capabilities); +		mac->macinfo.extended_capabilities = NULL; + +		kfree(mac->macinfo.extended_capabilities_mask); +		mac->macinfo.extended_capabilities_mask = NULL; + +		mac->macinfo.extended_capabilities_len = 0; +	} +} +  static void qtnf_vif_reset_handler(struct work_struct *work)  {  	struct qtnf_vif *vif = container_of(work, struct qtnf_vif, reset_work); @@ -370,6 +383,7 @@ static void qtnf_mac_scan_timeout(struct work_struct *work)  static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,  					     unsigned int macid)  { +	struct qtnf_vif *vif;  	struct wiphy *wiphy;  	struct qtnf_wmac *mac;  	unsigned int i; @@ -382,18 +396,20 @@ static struct qtnf_wmac *qtnf_core_mac_alloc(struct qtnf_bus *bus,  	mac->macid = macid;  	mac->bus = bus; +	mutex_init(&mac->mac_lock); +	INIT_DELAYED_WORK(&mac->scan_timeout, qtnf_mac_scan_timeout);  	for (i = 0; i < QTNF_MAX_INTF; i++) { -		memset(&mac->iflist[i], 0, sizeof(struct qtnf_vif)); -		mac->iflist[i].wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; -		mac->iflist[i].mac = mac; -		mac->iflist[i].vifid = i; -		qtnf_sta_list_init(&mac->iflist[i].sta_list); -		mutex_init(&mac->mac_lock); -		INIT_DELAYED_WORK(&mac->scan_timeout, qtnf_mac_scan_timeout); -		mac->iflist[i].stats64 = -			netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); -		if (!mac->iflist[i].stats64) +		vif = &mac->iflist[i]; + +		memset(vif, 0, sizeof(*vif)); +		vif->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED; +		vif->mac = mac; +		vif->vifid = i; +		qtnf_sta_list_init(&vif->sta_list); + +		vif->stats64 = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); +		if (!vif->stats64)  			pr_warn("VIF%u.%u: per cpu stats allocation failed\n",  				macid, i);  	} @@ -493,8 +509,7 @@ static void qtnf_core_mac_detach(struct qtnf_bus *bus, unsigned int macid)  	}  	qtnf_mac_iface_comb_free(mac); -	kfree(mac->macinfo.extended_capabilities); -	kfree(mac->macinfo.extended_capabilities_mask); +	qtnf_mac_ext_caps_free(mac);  	kfree(mac->macinfo.wowlan);  	wiphy_free(wiphy);  	bus->mac[macid] = NULL; diff --git a/drivers/net/wireless/quantenna/qtnfmac/core.h b/drivers/net/wireless/quantenna/qtnfmac/core.h index a1e338a1f055..293055049caa 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/core.h +++ b/drivers/net/wireless/quantenna/qtnfmac/core.h @@ -64,12 +64,6 @@ struct qtnf_sta_list {  	atomic_t size;  }; -enum qtnf_sta_state { -	QTNF_STA_DISCONNECTED, -	QTNF_STA_CONNECTING, -	QTNF_STA_CONNECTED -}; -  struct qtnf_vif {  	struct wireless_dev wdev;  	u8 bssid[ETH_ALEN]; @@ -77,7 +71,6 @@ struct qtnf_vif {  	u8 vifid;  	u8 bss_priority;  	u8 bss_status; -	enum qtnf_sta_state sta_state;  	u16 mgmt_frames_bitmask;  	struct net_device *netdev;  	struct qtnf_wmac *mac; @@ -151,6 +144,7 @@ struct qtnf_hw_info {  struct qtnf_vif *qtnf_mac_get_free_vif(struct qtnf_wmac *mac);  struct qtnf_vif *qtnf_mac_get_base_vif(struct qtnf_wmac *mac);  void qtnf_mac_iface_comb_free(struct qtnf_wmac *mac); +void qtnf_mac_ext_caps_free(struct qtnf_wmac *mac);  struct wiphy *qtnf_wiphy_allocate(struct qtnf_bus *bus);  int qtnf_core_net_attach(struct qtnf_wmac *mac, struct qtnf_vif *priv,  			 const char *name, unsigned char name_assign_type); diff --git a/drivers/net/wireless/quantenna/qtnfmac/event.c b/drivers/net/wireless/quantenna/qtnfmac/event.c index 68da81bec4e9..8b542b431b75 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/event.c +++ b/drivers/net/wireless/quantenna/qtnfmac/event.c @@ -171,24 +171,14 @@ qtnf_event_handle_bss_join(struct qtnf_vif *vif,  		return -EPROTO;  	} -	if (vif->sta_state != QTNF_STA_CONNECTING) { -		pr_err("VIF%u.%u: BSS_JOIN event when STA is not connecting\n", -		       vif->mac->macid, vif->vifid); -		return -EPROTO; -	} -  	pr_debug("VIF%u.%u: BSSID:%pM\n", vif->mac->macid, vif->vifid,  		 join_info->bssid);  	cfg80211_connect_result(vif->netdev, join_info->bssid, NULL, 0, NULL,  				0, le16_to_cpu(join_info->status), GFP_KERNEL); -	if (le16_to_cpu(join_info->status) == WLAN_STATUS_SUCCESS) { -		vif->sta_state = QTNF_STA_CONNECTED; +	if (le16_to_cpu(join_info->status) == WLAN_STATUS_SUCCESS)  		netif_carrier_on(vif->netdev); -	} else { -		vif->sta_state = QTNF_STA_DISCONNECTED; -	}  	return 0;  } @@ -211,16 +201,10 @@ qtnf_event_handle_bss_leave(struct qtnf_vif *vif,  		return -EPROTO;  	} -	if (vif->sta_state != QTNF_STA_CONNECTED) -		pr_warn("VIF%u.%u: BSS_LEAVE event when STA is not connected\n", -			vif->mac->macid, vif->vifid); -  	pr_debug("VIF%u.%u: disconnected\n", vif->mac->macid, vif->vifid);  	cfg80211_disconnected(vif->netdev, le16_to_cpu(leave_info->reason),  			      NULL, 0, 0, GFP_KERNEL); - -	vif->sta_state = QTNF_STA_DISCONNECTED;  	netif_carrier_off(vif->netdev);  	return 0; diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c new file mode 100644 index 000000000000..16795dbe475b --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie.c @@ -0,0 +1,392 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2018 Quantenna Communications, Inc. All rights reserved. */ + +#include <linux/printk.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/mutex.h> +#include <linux/netdevice.h> +#include <linux/seq_file.h> +#include <linux/workqueue.h> +#include <linux/completion.h> + +#include "pcie_priv.h" +#include "bus.h" +#include "shm_ipc.h" +#include "core.h" +#include "debug.h" + +#undef pr_fmt +#define pr_fmt(fmt)	"qtnf_pcie: %s: " fmt, __func__ + +#define QTN_SYSCTL_BAR	0 +#define QTN_SHMEM_BAR	2 +#define QTN_DMA_BAR	3 + +int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb) +{ +	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); +	int ret; + +	ret = qtnf_shm_ipc_send(&priv->shm_ipc_ep_in, skb->data, skb->len); + +	if (ret == -ETIMEDOUT) { +		pr_err("EP firmware is dead\n"); +		bus->fw_state = QTNF_FW_STATE_EP_DEAD; +	} + +	return ret; +} + +int qtnf_pcie_alloc_skb_array(struct qtnf_pcie_bus_priv *priv) +{ +	struct sk_buff **vaddr; +	int len; + +	len = priv->tx_bd_num * sizeof(*priv->tx_skb) + +		priv->rx_bd_num * sizeof(*priv->rx_skb); +	vaddr = devm_kzalloc(&priv->pdev->dev, len, GFP_KERNEL); + +	if (!vaddr) +		return -ENOMEM; + +	priv->tx_skb = vaddr; + +	vaddr += priv->tx_bd_num; +	priv->rx_skb = vaddr; + +	return 0; +} + +void qtnf_pcie_bringup_fw_async(struct qtnf_bus *bus) +{ +	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); +	struct pci_dev *pdev = priv->pdev; + +	get_device(&pdev->dev); +	schedule_work(&bus->fw_work); +} + +static int qtnf_dbg_mps_show(struct seq_file *s, void *data) +{ +	struct qtnf_bus *bus = dev_get_drvdata(s->private); +	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + +	seq_printf(s, "%d\n", priv->mps); + +	return 0; +} + +static int qtnf_dbg_msi_show(struct seq_file *s, void *data) +{ +	struct qtnf_bus *bus = dev_get_drvdata(s->private); +	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + +	seq_printf(s, "%u\n", priv->msi_enabled); + +	return 0; +} + +static int qtnf_dbg_shm_stats(struct seq_file *s, void *data) +{ +	struct qtnf_bus *bus = dev_get_drvdata(s->private); +	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); + +	seq_printf(s, "shm_ipc_ep_in.tx_packet_count(%zu)\n", +		   priv->shm_ipc_ep_in.tx_packet_count); +	seq_printf(s, "shm_ipc_ep_in.rx_packet_count(%zu)\n", +		   priv->shm_ipc_ep_in.rx_packet_count); +	seq_printf(s, "shm_ipc_ep_out.tx_packet_count(%zu)\n", +		   priv->shm_ipc_ep_out.tx_timeout_count); +	seq_printf(s, "shm_ipc_ep_out.rx_packet_count(%zu)\n", +		   priv->shm_ipc_ep_out.rx_packet_count); + +	return 0; +} + +void qtnf_pcie_fw_boot_done(struct qtnf_bus *bus, bool boot_success, +			    const char *drv_name) +{ +	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); +	struct pci_dev *pdev = priv->pdev; +	int ret; + +	if (boot_success) { +		bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE; + +		ret = qtnf_core_attach(bus); +		if (ret) { +			pr_err("failed to attach core\n"); +			boot_success = false; +		} +	} + +	if (boot_success) { +		qtnf_debugfs_init(bus, drv_name); +		qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show); +		qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show); +		qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats); +	} else { +		bus->fw_state = QTNF_FW_STATE_DETACHED; +	} + +	put_device(&pdev->dev); +} + +static void qtnf_tune_pcie_mps(struct qtnf_pcie_bus_priv *priv) +{ +	struct pci_dev *pdev = priv->pdev; +	struct pci_dev *parent; +	int mps_p, mps_o, mps_m, mps; +	int ret; + +	/* current mps */ +	mps_o = pcie_get_mps(pdev); + +	/* maximum supported mps */ +	mps_m = 128 << pdev->pcie_mpss; + +	/* suggested new mps value */ +	mps = mps_m; + +	if (pdev->bus && pdev->bus->self) { +		/* parent (bus) mps */ +		parent = pdev->bus->self; + +		if (pci_is_pcie(parent)) { +			mps_p = pcie_get_mps(parent); +			mps = min(mps_m, mps_p); +		} +	} + +	ret = pcie_set_mps(pdev, mps); +	if (ret) { +		pr_err("failed to set mps to %d, keep using current %d\n", +		       mps, mps_o); +		priv->mps = mps_o; +		return; +	} + +	pr_debug("set mps to %d (was %d, max %d)\n", mps, mps_o, mps_m); +	priv->mps = mps; +} + +static void qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv, bool use_msi) +{ +	struct pci_dev *pdev = priv->pdev; + +	/* fall back to legacy INTx interrupts by default */ +	priv->msi_enabled = 0; + +	/* check if MSI capability is available */ +	if (use_msi) { +		if (!pci_enable_msi(pdev)) { +			pr_debug("enabled MSI interrupt\n"); +			priv->msi_enabled = 1; +		} else { +			pr_warn("failed to enable MSI interrupts"); +		} +	} + +	if (!priv->msi_enabled) { +		pr_warn("legacy PCIE interrupts enabled\n"); +		pci_intx(pdev, 1); +	} +} + +static void __iomem *qtnf_map_bar(struct qtnf_pcie_bus_priv *priv, u8 index) +{ +	void __iomem *vaddr; +	dma_addr_t busaddr; +	size_t len; +	int ret; + +	ret = pcim_iomap_regions(priv->pdev, 1 << index, "qtnfmac_pcie"); +	if (ret) +		return IOMEM_ERR_PTR(ret); + +	busaddr = pci_resource_start(priv->pdev, index); +	len = pci_resource_len(priv->pdev, index); +	vaddr = pcim_iomap_table(priv->pdev)[index]; +	if (!vaddr) +		return IOMEM_ERR_PTR(-ENOMEM); + +	pr_debug("BAR%u vaddr=0x%p busaddr=%pad len=%u\n", +		 index, vaddr, &busaddr, (int)len); + +	return vaddr; +} + +static int qtnf_pcie_init_memory(struct qtnf_pcie_bus_priv *priv) +{ +	int ret = -ENOMEM; + +	priv->sysctl_bar = qtnf_map_bar(priv, QTN_SYSCTL_BAR); +	if (IS_ERR(priv->sysctl_bar)) { +		pr_err("failed to map BAR%u\n", QTN_SYSCTL_BAR); +		return ret; +	} + +	priv->dmareg_bar = qtnf_map_bar(priv, QTN_DMA_BAR); +	if (IS_ERR(priv->dmareg_bar)) { +		pr_err("failed to map BAR%u\n", QTN_DMA_BAR); +		return ret; +	} + +	priv->epmem_bar = qtnf_map_bar(priv, QTN_SHMEM_BAR); +	if (IS_ERR(priv->epmem_bar)) { +		pr_err("failed to map BAR%u\n", QTN_SHMEM_BAR); +		return ret; +	} + +	return 0; +} + +static void qtnf_pcie_control_rx_callback(void *arg, const u8 __iomem *buf, +					  size_t len) +{ +	struct qtnf_pcie_bus_priv *priv = arg; +	struct qtnf_bus *bus = pci_get_drvdata(priv->pdev); +	struct sk_buff *skb; + +	if (unlikely(len == 0)) { +		pr_warn("zero length packet received\n"); +		return; +	} + +	skb = __dev_alloc_skb(len, GFP_KERNEL); + +	if (unlikely(!skb)) { +		pr_err("failed to allocate skb\n"); +		return; +	} + +	memcpy_fromio(skb_put(skb, len), buf, len); + +	qtnf_trans_handle_rx_ctl_packet(bus, skb); +} + +void qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv, +			    struct qtnf_shm_ipc_region __iomem *ipc_tx_reg, +			    struct qtnf_shm_ipc_region __iomem *ipc_rx_reg, +			    const struct qtnf_shm_ipc_int *ipc_int) +{ +	const struct qtnf_shm_ipc_rx_callback rx_callback = { +					qtnf_pcie_control_rx_callback, priv }; + +	qtnf_shm_ipc_init(&priv->shm_ipc_ep_in, QTNF_SHM_IPC_OUTBOUND, +			  ipc_tx_reg, priv->workqueue, +			  ipc_int, &rx_callback); +	qtnf_shm_ipc_init(&priv->shm_ipc_ep_out, QTNF_SHM_IPC_INBOUND, +			  ipc_rx_reg, priv->workqueue, +			  ipc_int, &rx_callback); +} + +int qtnf_pcie_probe(struct pci_dev *pdev, size_t priv_size, +		    const struct qtnf_bus_ops *bus_ops, u64 dma_mask, +		    bool use_msi) +{ +	struct qtnf_pcie_bus_priv *pcie_priv; +	struct qtnf_bus *bus; +	int ret; + +	bus = devm_kzalloc(&pdev->dev, +			   sizeof(*bus) + priv_size, GFP_KERNEL); +	if (!bus) +		return -ENOMEM; + +	pcie_priv = get_bus_priv(bus); + +	pci_set_drvdata(pdev, bus); +	bus->bus_ops = bus_ops; +	bus->dev = &pdev->dev; +	bus->fw_state = QTNF_FW_STATE_RESET; +	pcie_priv->pdev = pdev; +	pcie_priv->tx_stopped = 0; + +	mutex_init(&bus->bus_lock); +	spin_lock_init(&pcie_priv->tx_lock); +	spin_lock_init(&pcie_priv->tx_reclaim_lock); + +	pcie_priv->tx_full_count = 0; +	pcie_priv->tx_done_count = 0; +	pcie_priv->pcie_irq_count = 0; +	pcie_priv->tx_reclaim_done = 0; +	pcie_priv->tx_reclaim_req = 0; + +	pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PCIE"); +	if (!pcie_priv->workqueue) { +		pr_err("failed to alloc bus workqueue\n"); +		ret = -ENODEV; +		goto err_init; +	} + +	init_dummy_netdev(&bus->mux_dev); + +	if (!pci_is_pcie(pdev)) { +		pr_err("device %s is not PCI Express\n", pci_name(pdev)); +		ret = -EIO; +		goto err_base; +	} + +	qtnf_tune_pcie_mps(pcie_priv); + +	ret = pcim_enable_device(pdev); +	if (ret) { +		pr_err("failed to init PCI device %x\n", pdev->device); +		goto err_base; +	} else { +		pr_debug("successful init of PCI device %x\n", pdev->device); +	} + +	ret = dma_set_mask_and_coherent(&pdev->dev, dma_mask); +	if (ret) { +		pr_err("PCIE DMA coherent mask init failed\n"); +		goto err_base; +	} + +	pci_set_master(pdev); +	qtnf_pcie_init_irq(pcie_priv, use_msi); + +	ret = qtnf_pcie_init_memory(pcie_priv); +	if (ret < 0) { +		pr_err("PCIE memory init failed\n"); +		goto err_base; +	} + +	pci_save_state(pdev); + +	return 0; + +err_base: +	flush_workqueue(pcie_priv->workqueue); +	destroy_workqueue(pcie_priv->workqueue); +err_init: +	pci_set_drvdata(pdev, NULL); + +	return ret; +} + +static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_bus_priv *priv) +{ +	qtnf_shm_ipc_free(&priv->shm_ipc_ep_in); +	qtnf_shm_ipc_free(&priv->shm_ipc_ep_out); +} + +void qtnf_pcie_remove(struct qtnf_bus *bus, struct qtnf_pcie_bus_priv *priv) +{ +	cancel_work_sync(&bus->fw_work); + +	if (bus->fw_state == QTNF_FW_STATE_ACTIVE || +	    bus->fw_state == QTNF_FW_STATE_EP_DEAD) +		qtnf_core_detach(bus); + +	netif_napi_del(&bus->mux_napi); +	flush_workqueue(priv->workqueue); +	destroy_workqueue(priv->workqueue); +	tasklet_kill(&priv->reclaim_tq); + +	qtnf_pcie_free_shm_ipc(priv); +	qtnf_debugfs_remove(bus); +	pci_set_drvdata(priv->pdev, NULL); +} diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h new file mode 100644 index 000000000000..5c70fb4c0f92 --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pcie_priv.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2018 Quantenna Communications, Inc. All rights reserved. */ + +#ifndef _QTN_FMAC_PCIE_H_ +#define _QTN_FMAC_PCIE_H_ + +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/skbuff.h> +#include <linux/workqueue.h> +#include <linux/interrupt.h> + +#include "shm_ipc.h" +#include "bus.h" + +#define SKB_BUF_SIZE		2048 + +#define QTN_FW_DL_TIMEOUT_MS	3000 +#define QTN_FW_QLINK_TIMEOUT_MS	30000 +#define QTN_EP_RESET_WAIT_MS	1000 + +struct qtnf_pcie_bus_priv { +	struct pci_dev *pdev; + +	spinlock_t tx_reclaim_lock; +	spinlock_t tx_lock; +	int mps; + +	struct workqueue_struct *workqueue; +	struct tasklet_struct reclaim_tq; + +	void __iomem *sysctl_bar; +	void __iomem *epmem_bar; +	void __iomem *dmareg_bar; + +	struct qtnf_shm_ipc shm_ipc_ep_in; +	struct qtnf_shm_ipc shm_ipc_ep_out; + +	u16 tx_bd_num; +	u16 rx_bd_num; + +	struct sk_buff **tx_skb; +	struct sk_buff **rx_skb; + +	u32 rx_bd_w_index; +	u32 rx_bd_r_index; + +	u32 tx_bd_w_index; +	u32 tx_bd_r_index; + +	/* diagnostics stats */ +	u32 pcie_irq_count; +	u32 tx_full_count; +	u32 tx_done_count; +	u32 tx_reclaim_done; +	u32 tx_reclaim_req; + +	u8 msi_enabled; +	u8 tx_stopped; +}; + +int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb); +int qtnf_pcie_alloc_skb_array(struct qtnf_pcie_bus_priv *priv); +void qtnf_pcie_bringup_fw_async(struct qtnf_bus *bus); +void qtnf_pcie_fw_boot_done(struct qtnf_bus *bus, bool boot_success, +			    const char *drv_name); +void qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv, +			    struct qtnf_shm_ipc_region __iomem *ipc_tx_reg, +			    struct qtnf_shm_ipc_region __iomem *ipc_rx_reg, +			    const struct qtnf_shm_ipc_int *ipc_int); +int qtnf_pcie_probe(struct pci_dev *pdev, size_t priv_size, +		    const struct qtnf_bus_ops *bus_ops, u64 dma_mask, +		    bool use_msi); +void qtnf_pcie_remove(struct qtnf_bus *bus, struct qtnf_pcie_bus_priv *priv); + +static inline void qtnf_non_posted_write(u32 val, void __iomem *basereg) +{ +	writel(val, basereg); + +	/* flush posted write */ +	readl(basereg); +} + +#endif /* _QTN_FMAC_PCIE_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c new file mode 100644 index 000000000000..95c7b95c6f8a --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie.c @@ -0,0 +1,1249 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* Copyright (c) 2018 Quantenna Communications */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/firmware.h> +#include <linux/pci.h> +#include <linux/vmalloc.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/completion.h> +#include <linux/crc32.h> +#include <linux/spinlock.h> +#include <linux/circ_buf.h> +#include <linux/log2.h> + +#include "pcie_priv.h" +#include "pearl_pcie_regs.h" +#include "pearl_pcie_ipc.h" +#include "qtn_hw_ids.h" +#include "core.h" +#include "bus.h" +#include "shm_ipc.h" +#include "debug.h" + +static bool use_msi = true; +module_param(use_msi, bool, 0644); +MODULE_PARM_DESC(use_msi, "set 0 to use legacy interrupt"); + +static unsigned int tx_bd_size_param = 32; +module_param(tx_bd_size_param, uint, 0644); +MODULE_PARM_DESC(tx_bd_size_param, "Tx descriptors queue size, power of two"); + +static unsigned int rx_bd_size_param = 256; +module_param(rx_bd_size_param, uint, 0644); +MODULE_PARM_DESC(rx_bd_size_param, "Rx descriptors queue size, power of two"); + +static u8 flashboot = 1; +module_param(flashboot, byte, 0644); +MODULE_PARM_DESC(flashboot, "set to 0 to use FW binary file on FS"); + +#define DRV_NAME	"qtnfmac_pearl_pcie" + +struct qtnf_pearl_bda { +	__le16 bda_len; +	__le16 bda_version; +	__le32 bda_pci_endian; +	__le32 bda_ep_state; +	__le32 bda_rc_state; +	__le32 bda_dma_mask; +	__le32 bda_msi_addr; +	__le32 bda_flashsz; +	u8 bda_boardname[PCIE_BDA_NAMELEN]; +	__le32 bda_rc_msi_enabled; +	u8 bda_hhbm_list[PCIE_HHBM_MAX_SIZE]; +	__le32 bda_dsbw_start_index; +	__le32 bda_dsbw_end_index; +	__le32 bda_dsbw_total_bytes; +	__le32 bda_rc_tx_bd_base; +	__le32 bda_rc_tx_bd_num; +	u8 bda_pcie_mac[QTN_ENET_ADDR_LENGTH]; +	struct qtnf_shm_ipc_region bda_shm_reg1 __aligned(4096); /* host TX */ +	struct qtnf_shm_ipc_region bda_shm_reg2 __aligned(4096); /* host RX */ +} __packed; + +struct qtnf_pearl_tx_bd { +	__le32 addr; +	__le32 addr_h; +	__le32 info; +	__le32 info_h; +} __packed; + +struct qtnf_pearl_rx_bd { +	__le32 addr; +	__le32 addr_h; +	__le32 info; +	__le32 info_h; +	__le32 next_ptr; +	__le32 next_ptr_h; +} __packed; + +struct qtnf_pearl_fw_hdr { +	u8 boardflg[8]; +	__le32 fwsize; +	__le32 seqnum; +	__le32 type; +	__le32 pktlen; +	__le32 crc; +} __packed; + +struct qtnf_pcie_pearl_state { +	struct qtnf_pcie_bus_priv base; + +	/* lock for irq configuration changes */ +	spinlock_t irq_lock; + +	struct qtnf_pearl_bda __iomem *bda; +	void __iomem *pcie_reg_base; + +	struct qtnf_pearl_tx_bd *tx_bd_vbase; +	dma_addr_t tx_bd_pbase; + +	struct qtnf_pearl_rx_bd *rx_bd_vbase; +	dma_addr_t rx_bd_pbase; + +	dma_addr_t bd_table_paddr; +	void *bd_table_vaddr; +	u32 bd_table_len; +	u32 pcie_irq_mask; +	u32 pcie_irq_rx_count; +	u32 pcie_irq_tx_count; +	u32 pcie_irq_uf_count; +}; + +static inline void qtnf_init_hdp_irqs(struct qtnf_pcie_pearl_state *ps) +{ +	unsigned long flags; + +	spin_lock_irqsave(&ps->irq_lock, flags); +	ps->pcie_irq_mask = (PCIE_HDP_INT_RX_BITS | PCIE_HDP_INT_TX_BITS); +	spin_unlock_irqrestore(&ps->irq_lock, flags); +} + +static inline void qtnf_enable_hdp_irqs(struct qtnf_pcie_pearl_state *ps) +{ +	unsigned long flags; + +	spin_lock_irqsave(&ps->irq_lock, flags); +	writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base)); +	spin_unlock_irqrestore(&ps->irq_lock, flags); +} + +static inline void qtnf_disable_hdp_irqs(struct qtnf_pcie_pearl_state *ps) +{ +	unsigned long flags; + +	spin_lock_irqsave(&ps->irq_lock, flags); +	writel(0x0, PCIE_HDP_INT_EN(ps->pcie_reg_base)); +	spin_unlock_irqrestore(&ps->irq_lock, flags); +} + +static inline void qtnf_en_rxdone_irq(struct qtnf_pcie_pearl_state *ps) +{ +	unsigned long flags; + +	spin_lock_irqsave(&ps->irq_lock, flags); +	ps->pcie_irq_mask |= PCIE_HDP_INT_RX_BITS; +	writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base)); +	spin_unlock_irqrestore(&ps->irq_lock, flags); +} + +static inline void qtnf_dis_rxdone_irq(struct qtnf_pcie_pearl_state *ps) +{ +	unsigned long flags; + +	spin_lock_irqsave(&ps->irq_lock, flags); +	ps->pcie_irq_mask &= ~PCIE_HDP_INT_RX_BITS; +	writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base)); +	spin_unlock_irqrestore(&ps->irq_lock, flags); +} + +static inline void qtnf_en_txdone_irq(struct qtnf_pcie_pearl_state *ps) +{ +	unsigned long flags; + +	spin_lock_irqsave(&ps->irq_lock, flags); +	ps->pcie_irq_mask |= PCIE_HDP_INT_TX_BITS; +	writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base)); +	spin_unlock_irqrestore(&ps->irq_lock, flags); +} + +static inline void qtnf_dis_txdone_irq(struct qtnf_pcie_pearl_state *ps) +{ +	unsigned long flags; + +	spin_lock_irqsave(&ps->irq_lock, flags); +	ps->pcie_irq_mask &= ~PCIE_HDP_INT_TX_BITS; +	writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base)); +	spin_unlock_irqrestore(&ps->irq_lock, flags); +} + +static void qtnf_deassert_intx(struct qtnf_pcie_pearl_state *ps) +{ +	void __iomem *reg = ps->base.sysctl_bar + PEARL_PCIE_CFG0_OFFSET; +	u32 cfg; + +	cfg = readl(reg); +	cfg &= ~PEARL_ASSERT_INTX; +	qtnf_non_posted_write(cfg, reg); +} + +static void qtnf_pearl_reset_ep(struct qtnf_pcie_pearl_state *ps) +{ +	const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_EP_RESET); +	void __iomem *reg = ps->base.sysctl_bar + +			    QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET; + +	qtnf_non_posted_write(data, reg); +	msleep(QTN_EP_RESET_WAIT_MS); +	pci_restore_state(ps->base.pdev); +} + +static void qtnf_pcie_pearl_ipc_gen_ep_int(void *arg) +{ +	const struct qtnf_pcie_pearl_state *ps = arg; +	const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_IPC_IRQ); +	void __iomem *reg = ps->base.sysctl_bar + +			    QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET; + +	qtnf_non_posted_write(data, reg); +} + +static int qtnf_is_state(__le32 __iomem *reg, u32 state) +{ +	u32 s = readl(reg); + +	return s & state; +} + +static void qtnf_set_state(__le32 __iomem *reg, u32 state) +{ +	u32 s = readl(reg); + +	qtnf_non_posted_write(state | s, reg); +} + +static void qtnf_clear_state(__le32 __iomem *reg, u32 state) +{ +	u32 s = readl(reg); + +	qtnf_non_posted_write(s & ~state, reg); +} + +static int qtnf_poll_state(__le32 __iomem *reg, u32 state, u32 delay_in_ms) +{ +	u32 timeout = 0; + +	while ((qtnf_is_state(reg, state) == 0)) { +		usleep_range(1000, 1200); +		if (++timeout > delay_in_ms) +			return -1; +	} + +	return 0; +} + +static int pearl_alloc_bd_table(struct qtnf_pcie_pearl_state *ps) +{ +	struct qtnf_pcie_bus_priv *priv = &ps->base; +	dma_addr_t paddr; +	void *vaddr; +	int len; + +	len = priv->tx_bd_num * sizeof(struct qtnf_pearl_tx_bd) + +		priv->rx_bd_num * sizeof(struct qtnf_pearl_rx_bd); + +	vaddr = dmam_alloc_coherent(&priv->pdev->dev, len, &paddr, GFP_KERNEL); +	if (!vaddr) +		return -ENOMEM; + +	/* tx bd */ + +	memset(vaddr, 0, len); + +	ps->bd_table_vaddr = vaddr; +	ps->bd_table_paddr = paddr; +	ps->bd_table_len = len; + +	ps->tx_bd_vbase = vaddr; +	ps->tx_bd_pbase = paddr; + +	pr_debug("TX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr); + +	priv->tx_bd_r_index = 0; +	priv->tx_bd_w_index = 0; + +	/* rx bd */ + +	vaddr = ((struct qtnf_pearl_tx_bd *)vaddr) + priv->tx_bd_num; +	paddr += priv->tx_bd_num * sizeof(struct qtnf_pearl_tx_bd); + +	ps->rx_bd_vbase = vaddr; +	ps->rx_bd_pbase = paddr; + +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT +	writel(QTN_HOST_HI32(paddr), +	       PCIE_HDP_TX_HOST_Q_BASE_H(ps->pcie_reg_base)); +#endif +	writel(QTN_HOST_LO32(paddr), +	       PCIE_HDP_TX_HOST_Q_BASE_L(ps->pcie_reg_base)); +	writel(priv->rx_bd_num | (sizeof(struct qtnf_pearl_rx_bd)) << 16, +	       PCIE_HDP_TX_HOST_Q_SZ_CTRL(ps->pcie_reg_base)); + +	pr_debug("RX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr); + +	return 0; +} + +static int pearl_skb2rbd_attach(struct qtnf_pcie_pearl_state *ps, u16 index) +{ +	struct qtnf_pcie_bus_priv *priv = &ps->base; +	struct qtnf_pearl_rx_bd *rxbd; +	struct sk_buff *skb; +	dma_addr_t paddr; + +	skb = __netdev_alloc_skb_ip_align(NULL, SKB_BUF_SIZE, GFP_ATOMIC); +	if (!skb) { +		priv->rx_skb[index] = NULL; +		return -ENOMEM; +	} + +	priv->rx_skb[index] = skb; +	rxbd = &ps->rx_bd_vbase[index]; + +	paddr = pci_map_single(priv->pdev, skb->data, +			       SKB_BUF_SIZE, PCI_DMA_FROMDEVICE); +	if (pci_dma_mapping_error(priv->pdev, paddr)) { +		pr_err("skb DMA mapping error: %pad\n", &paddr); +		return -ENOMEM; +	} + +	/* keep rx skb paddrs in rx buffer descriptors for cleanup purposes */ +	rxbd->addr = cpu_to_le32(QTN_HOST_LO32(paddr)); +	rxbd->addr_h = cpu_to_le32(QTN_HOST_HI32(paddr)); +	rxbd->info = 0x0; + +	priv->rx_bd_w_index = index; + +	/* sync up all descriptor updates */ +	wmb(); + +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT +	writel(QTN_HOST_HI32(paddr), +	       PCIE_HDP_HHBM_BUF_PTR_H(ps->pcie_reg_base)); +#endif +	writel(QTN_HOST_LO32(paddr), +	       PCIE_HDP_HHBM_BUF_PTR(ps->pcie_reg_base)); + +	writel(index, PCIE_HDP_TX_HOST_Q_WR_PTR(ps->pcie_reg_base)); +	return 0; +} + +static int pearl_alloc_rx_buffers(struct qtnf_pcie_pearl_state *ps) +{ +	u16 i; +	int ret = 0; + +	memset(ps->rx_bd_vbase, 0x0, +	       ps->base.rx_bd_num * sizeof(struct qtnf_pearl_rx_bd)); + +	for (i = 0; i < ps->base.rx_bd_num; i++) { +		ret = pearl_skb2rbd_attach(ps, i); +		if (ret) +			break; +	} + +	return ret; +} + +/* all rx/tx activity should have ceased before calling this function */ +static void qtnf_pearl_free_xfer_buffers(struct qtnf_pcie_pearl_state *ps) +{ +	struct qtnf_pcie_bus_priv *priv = &ps->base; +	struct qtnf_pearl_tx_bd *txbd; +	struct qtnf_pearl_rx_bd *rxbd; +	struct sk_buff *skb; +	dma_addr_t paddr; +	int i; + +	/* free rx buffers */ +	for (i = 0; i < priv->rx_bd_num; i++) { +		if (priv->rx_skb && priv->rx_skb[i]) { +			rxbd = &ps->rx_bd_vbase[i]; +			skb = priv->rx_skb[i]; +			paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h), +					      le32_to_cpu(rxbd->addr)); +			pci_unmap_single(priv->pdev, paddr, SKB_BUF_SIZE, +					 PCI_DMA_FROMDEVICE); +			dev_kfree_skb_any(skb); +			priv->rx_skb[i] = NULL; +		} +	} + +	/* free tx buffers */ +	for (i = 0; i < priv->tx_bd_num; i++) { +		if (priv->tx_skb && priv->tx_skb[i]) { +			txbd = &ps->tx_bd_vbase[i]; +			skb = priv->tx_skb[i]; +			paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h), +					      le32_to_cpu(txbd->addr)); +			pci_unmap_single(priv->pdev, paddr, skb->len, +					 PCI_DMA_TODEVICE); +			dev_kfree_skb_any(skb); +			priv->tx_skb[i] = NULL; +		} +	} +} + +static int pearl_hhbm_init(struct qtnf_pcie_pearl_state *ps) +{ +	u32 val; + +	val = readl(PCIE_HHBM_CONFIG(ps->pcie_reg_base)); +	val |= HHBM_CONFIG_SOFT_RESET; +	writel(val, PCIE_HHBM_CONFIG(ps->pcie_reg_base)); +	usleep_range(50, 100); +	val &= ~HHBM_CONFIG_SOFT_RESET; +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT +	val |= HHBM_64BIT; +#endif +	writel(val, PCIE_HHBM_CONFIG(ps->pcie_reg_base)); +	writel(ps->base.rx_bd_num, PCIE_HHBM_Q_LIMIT_REG(ps->pcie_reg_base)); + +	return 0; +} + +static int qtnf_pcie_pearl_init_xfer(struct qtnf_pcie_pearl_state *ps) +{ +	struct qtnf_pcie_bus_priv *priv = &ps->base; +	int ret; +	u32 val; + +	priv->tx_bd_num = tx_bd_size_param; +	priv->rx_bd_num = rx_bd_size_param; +	priv->rx_bd_w_index = 0; +	priv->rx_bd_r_index = 0; + +	if (!priv->tx_bd_num || !is_power_of_2(priv->tx_bd_num)) { +		pr_err("tx_bd_size_param %u is not power of two\n", +		       priv->tx_bd_num); +		return -EINVAL; +	} + +	val = priv->tx_bd_num * sizeof(struct qtnf_pearl_tx_bd); +	if (val > PCIE_HHBM_MAX_SIZE) { +		pr_err("tx_bd_size_param %u is too large\n", +		       priv->tx_bd_num); +		return -EINVAL; +	} + +	if (!priv->rx_bd_num || !is_power_of_2(priv->rx_bd_num)) { +		pr_err("rx_bd_size_param %u is not power of two\n", +		       priv->rx_bd_num); +		return -EINVAL; +	} + +	val = priv->rx_bd_num * sizeof(dma_addr_t); +	if (val > PCIE_HHBM_MAX_SIZE) { +		pr_err("rx_bd_size_param %u is too large\n", +		       priv->rx_bd_num); +		return -EINVAL; +	} + +	ret = pearl_hhbm_init(ps); +	if (ret) { +		pr_err("failed to init h/w queues\n"); +		return ret; +	} + +	ret = qtnf_pcie_alloc_skb_array(priv); +	if (ret) { +		pr_err("failed to allocate skb array\n"); +		return ret; +	} + +	ret = pearl_alloc_bd_table(ps); +	if (ret) { +		pr_err("failed to allocate bd table\n"); +		return ret; +	} + +	ret = pearl_alloc_rx_buffers(ps); +	if (ret) { +		pr_err("failed to allocate rx buffers\n"); +		return ret; +	} + +	return ret; +} + +static void qtnf_pearl_data_tx_reclaim(struct qtnf_pcie_pearl_state *ps) +{ +	struct qtnf_pcie_bus_priv *priv = &ps->base; +	struct qtnf_pearl_tx_bd *txbd; +	struct sk_buff *skb; +	unsigned long flags; +	dma_addr_t paddr; +	u32 tx_done_index; +	int count = 0; +	int i; + +	spin_lock_irqsave(&priv->tx_reclaim_lock, flags); + +	tx_done_index = readl(PCIE_HDP_RX0DMA_CNT(ps->pcie_reg_base)) +			& (priv->tx_bd_num - 1); + +	i = priv->tx_bd_r_index; + +	while (CIRC_CNT(tx_done_index, i, priv->tx_bd_num)) { +		skb = priv->tx_skb[i]; +		if (likely(skb)) { +			txbd = &ps->tx_bd_vbase[i]; +			paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h), +					      le32_to_cpu(txbd->addr)); +			pci_unmap_single(priv->pdev, paddr, skb->len, +					 PCI_DMA_TODEVICE); + +			if (skb->dev) { +				qtnf_update_tx_stats(skb->dev, skb); +				if (unlikely(priv->tx_stopped)) { +					qtnf_wake_all_queues(skb->dev); +					priv->tx_stopped = 0; +				} +			} + +			dev_kfree_skb_any(skb); +		} + +		priv->tx_skb[i] = NULL; +		count++; + +		if (++i >= priv->tx_bd_num) +			i = 0; +	} + +	priv->tx_reclaim_done += count; +	priv->tx_reclaim_req++; +	priv->tx_bd_r_index = i; + +	spin_unlock_irqrestore(&priv->tx_reclaim_lock, flags); +} + +static int qtnf_tx_queue_ready(struct qtnf_pcie_pearl_state *ps) +{ +	struct qtnf_pcie_bus_priv *priv = &ps->base; + +	if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index, +			priv->tx_bd_num)) { +		qtnf_pearl_data_tx_reclaim(ps); + +		if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index, +				priv->tx_bd_num)) { +			pr_warn_ratelimited("reclaim full Tx queue\n"); +			priv->tx_full_count++; +			return 0; +		} +	} + +	return 1; +} + +static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) +{ +	struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); +	struct qtnf_pcie_bus_priv *priv = &ps->base; +	dma_addr_t txbd_paddr, skb_paddr; +	struct qtnf_pearl_tx_bd *txbd; +	unsigned long flags; +	int len, i; +	u32 info; +	int ret = 0; + +	spin_lock_irqsave(&priv->tx_lock, flags); + +	if (!qtnf_tx_queue_ready(ps)) { +		if (skb->dev) { +			netif_tx_stop_all_queues(skb->dev); +			priv->tx_stopped = 1; +		} + +		spin_unlock_irqrestore(&priv->tx_lock, flags); +		return NETDEV_TX_BUSY; +	} + +	i = priv->tx_bd_w_index; +	priv->tx_skb[i] = skb; +	len = skb->len; + +	skb_paddr = pci_map_single(priv->pdev, skb->data, +				   skb->len, PCI_DMA_TODEVICE); +	if (pci_dma_mapping_error(priv->pdev, skb_paddr)) { +		pr_err("skb DMA mapping error: %pad\n", &skb_paddr); +		ret = -ENOMEM; +		goto tx_done; +	} + +	txbd = &ps->tx_bd_vbase[i]; +	txbd->addr = cpu_to_le32(QTN_HOST_LO32(skb_paddr)); +	txbd->addr_h = cpu_to_le32(QTN_HOST_HI32(skb_paddr)); + +	info = (len & QTN_PCIE_TX_DESC_LEN_MASK) << QTN_PCIE_TX_DESC_LEN_SHIFT; +	txbd->info = cpu_to_le32(info); + +	/* sync up all descriptor updates before passing them to EP */ +	dma_wmb(); + +	/* write new TX descriptor to PCIE_RX_FIFO on EP */ +	txbd_paddr = ps->tx_bd_pbase + i * sizeof(struct qtnf_pearl_tx_bd); + +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT +	writel(QTN_HOST_HI32(txbd_paddr), +	       PCIE_HDP_HOST_WR_DESC0_H(ps->pcie_reg_base)); +#endif +	writel(QTN_HOST_LO32(txbd_paddr), +	       PCIE_HDP_HOST_WR_DESC0(ps->pcie_reg_base)); + +	if (++i >= priv->tx_bd_num) +		i = 0; + +	priv->tx_bd_w_index = i; + +tx_done: +	if (ret && skb) { +		pr_err_ratelimited("drop skb\n"); +		if (skb->dev) +			skb->dev->stats.tx_dropped++; +		dev_kfree_skb_any(skb); +	} + +	priv->tx_done_count++; +	spin_unlock_irqrestore(&priv->tx_lock, flags); + +	qtnf_pearl_data_tx_reclaim(ps); + +	return NETDEV_TX_OK; +} + +static irqreturn_t qtnf_pcie_pearl_interrupt(int irq, void *data) +{ +	struct qtnf_bus *bus = (struct qtnf_bus *)data; +	struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); +	struct qtnf_pcie_bus_priv *priv = &ps->base; +	u32 status; + +	priv->pcie_irq_count++; +	status = readl(PCIE_HDP_INT_STATUS(ps->pcie_reg_base)); + +	qtnf_shm_ipc_irq_handler(&priv->shm_ipc_ep_in); +	qtnf_shm_ipc_irq_handler(&priv->shm_ipc_ep_out); + +	if (!(status & ps->pcie_irq_mask)) +		goto irq_done; + +	if (status & PCIE_HDP_INT_RX_BITS) +		ps->pcie_irq_rx_count++; + +	if (status & PCIE_HDP_INT_TX_BITS) +		ps->pcie_irq_tx_count++; + +	if (status & PCIE_HDP_INT_HHBM_UF) +		ps->pcie_irq_uf_count++; + +	if (status & PCIE_HDP_INT_RX_BITS) { +		qtnf_dis_rxdone_irq(ps); +		napi_schedule(&bus->mux_napi); +	} + +	if (status & PCIE_HDP_INT_TX_BITS) { +		qtnf_dis_txdone_irq(ps); +		tasklet_hi_schedule(&priv->reclaim_tq); +	} + +irq_done: +	/* H/W workaround: clean all bits, not only enabled */ +	qtnf_non_posted_write(~0U, PCIE_HDP_INT_STATUS(ps->pcie_reg_base)); + +	if (!priv->msi_enabled) +		qtnf_deassert_intx(ps); + +	return IRQ_HANDLED; +} + +static int qtnf_rx_data_ready(struct qtnf_pcie_pearl_state *ps) +{ +	u16 index = ps->base.rx_bd_r_index; +	struct qtnf_pearl_rx_bd *rxbd; +	u32 descw; + +	rxbd = &ps->rx_bd_vbase[index]; +	descw = le32_to_cpu(rxbd->info); + +	if (descw & QTN_TXDONE_MASK) +		return 1; + +	return 0; +} + +static int qtnf_pcie_pearl_rx_poll(struct napi_struct *napi, int budget) +{ +	struct qtnf_bus *bus = container_of(napi, struct qtnf_bus, mux_napi); +	struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); +	struct qtnf_pcie_bus_priv *priv = &ps->base; +	struct net_device *ndev = NULL; +	struct sk_buff *skb = NULL; +	int processed = 0; +	struct qtnf_pearl_rx_bd *rxbd; +	dma_addr_t skb_paddr; +	int consume; +	u32 descw; +	u32 psize; +	u16 r_idx; +	u16 w_idx; +	int ret; + +	while (processed < budget) { +		if (!qtnf_rx_data_ready(ps)) +			goto rx_out; + +		r_idx = priv->rx_bd_r_index; +		rxbd = &ps->rx_bd_vbase[r_idx]; +		descw = le32_to_cpu(rxbd->info); + +		skb = priv->rx_skb[r_idx]; +		psize = QTN_GET_LEN(descw); +		consume = 1; + +		if (!(descw & QTN_TXDONE_MASK)) { +			pr_warn("skip invalid rxbd[%d]\n", r_idx); +			consume = 0; +		} + +		if (!skb) { +			pr_warn("skip missing rx_skb[%d]\n", r_idx); +			consume = 0; +		} + +		if (skb && (skb_tailroom(skb) <  psize)) { +			pr_err("skip packet with invalid length: %u > %u\n", +			       psize, skb_tailroom(skb)); +			consume = 0; +		} + +		if (skb) { +			skb_paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h), +						  le32_to_cpu(rxbd->addr)); +			pci_unmap_single(priv->pdev, skb_paddr, SKB_BUF_SIZE, +					 PCI_DMA_FROMDEVICE); +		} + +		if (consume) { +			skb_put(skb, psize); +			ndev = qtnf_classify_skb(bus, skb); +			if (likely(ndev)) { +				qtnf_update_rx_stats(ndev, skb); +				skb->protocol = eth_type_trans(skb, ndev); +				napi_gro_receive(napi, skb); +			} else { +				pr_debug("drop untagged skb\n"); +				bus->mux_dev.stats.rx_dropped++; +				dev_kfree_skb_any(skb); +			} +		} else { +			if (skb) { +				bus->mux_dev.stats.rx_dropped++; +				dev_kfree_skb_any(skb); +			} +		} + +		priv->rx_skb[r_idx] = NULL; +		if (++r_idx >= priv->rx_bd_num) +			r_idx = 0; + +		priv->rx_bd_r_index = r_idx; + +		/* repalce processed buffer by a new one */ +		w_idx = priv->rx_bd_w_index; +		while (CIRC_SPACE(priv->rx_bd_w_index, priv->rx_bd_r_index, +				  priv->rx_bd_num) > 0) { +			if (++w_idx >= priv->rx_bd_num) +				w_idx = 0; + +			ret = pearl_skb2rbd_attach(ps, w_idx); +			if (ret) { +				pr_err("failed to allocate new rx_skb[%d]\n", +				       w_idx); +				break; +			} +		} + +		processed++; +	} + +rx_out: +	if (processed < budget) { +		napi_complete(napi); +		qtnf_en_rxdone_irq(ps); +	} + +	return processed; +} + +static void +qtnf_pcie_data_tx_timeout(struct qtnf_bus *bus, struct net_device *ndev) +{ +	struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); + +	tasklet_hi_schedule(&ps->base.reclaim_tq); +} + +static void qtnf_pcie_data_rx_start(struct qtnf_bus *bus) +{ +	struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); + +	qtnf_enable_hdp_irqs(ps); +	napi_enable(&bus->mux_napi); +} + +static void qtnf_pcie_data_rx_stop(struct qtnf_bus *bus) +{ +	struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); + +	napi_disable(&bus->mux_napi); +	qtnf_disable_hdp_irqs(ps); +} + +static const struct qtnf_bus_ops qtnf_pcie_pearl_bus_ops = { +	/* control path methods */ +	.control_tx	= qtnf_pcie_control_tx, + +	/* data path methods */ +	.data_tx		= qtnf_pcie_data_tx, +	.data_tx_timeout	= qtnf_pcie_data_tx_timeout, +	.data_rx_start		= qtnf_pcie_data_rx_start, +	.data_rx_stop		= qtnf_pcie_data_rx_stop, +}; + +static int qtnf_dbg_irq_stats(struct seq_file *s, void *data) +{ +	struct qtnf_bus *bus = dev_get_drvdata(s->private); +	struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); +	u32 reg = readl(PCIE_HDP_INT_EN(ps->pcie_reg_base)); +	u32 status; + +	seq_printf(s, "pcie_irq_count(%u)\n", ps->base.pcie_irq_count); +	seq_printf(s, "pcie_irq_tx_count(%u)\n", ps->pcie_irq_tx_count); +	status = reg &  PCIE_HDP_INT_TX_BITS; +	seq_printf(s, "pcie_irq_tx_status(%s)\n", +		   (status == PCIE_HDP_INT_TX_BITS) ? "EN" : "DIS"); +	seq_printf(s, "pcie_irq_rx_count(%u)\n", ps->pcie_irq_rx_count); +	status = reg &  PCIE_HDP_INT_RX_BITS; +	seq_printf(s, "pcie_irq_rx_status(%s)\n", +		   (status == PCIE_HDP_INT_RX_BITS) ? "EN" : "DIS"); +	seq_printf(s, "pcie_irq_uf_count(%u)\n", ps->pcie_irq_uf_count); +	status = reg &  PCIE_HDP_INT_HHBM_UF; +	seq_printf(s, "pcie_irq_hhbm_uf_status(%s)\n", +		   (status == PCIE_HDP_INT_HHBM_UF) ? "EN" : "DIS"); + +	return 0; +} + +static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data) +{ +	struct qtnf_bus *bus = dev_get_drvdata(s->private); +	struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); +	struct qtnf_pcie_bus_priv *priv = &ps->base; + +	seq_printf(s, "tx_full_count(%u)\n", priv->tx_full_count); +	seq_printf(s, "tx_done_count(%u)\n", priv->tx_done_count); +	seq_printf(s, "tx_reclaim_done(%u)\n", priv->tx_reclaim_done); +	seq_printf(s, "tx_reclaim_req(%u)\n", priv->tx_reclaim_req); + +	seq_printf(s, "tx_bd_r_index(%u)\n", priv->tx_bd_r_index); +	seq_printf(s, "tx_bd_p_index(%u)\n", +		   readl(PCIE_HDP_RX0DMA_CNT(ps->pcie_reg_base)) +			& (priv->tx_bd_num - 1)); +	seq_printf(s, "tx_bd_w_index(%u)\n", priv->tx_bd_w_index); +	seq_printf(s, "tx queue len(%u)\n", +		   CIRC_CNT(priv->tx_bd_w_index, priv->tx_bd_r_index, +			    priv->tx_bd_num)); + +	seq_printf(s, "rx_bd_r_index(%u)\n", priv->rx_bd_r_index); +	seq_printf(s, "rx_bd_p_index(%u)\n", +		   readl(PCIE_HDP_TX0DMA_CNT(ps->pcie_reg_base)) +			& (priv->rx_bd_num - 1)); +	seq_printf(s, "rx_bd_w_index(%u)\n", priv->rx_bd_w_index); +	seq_printf(s, "rx alloc queue len(%u)\n", +		   CIRC_SPACE(priv->rx_bd_w_index, priv->rx_bd_r_index, +			      priv->rx_bd_num)); + +	return 0; +} + +static int qtnf_ep_fw_send(struct pci_dev *pdev, uint32_t size, +			   int blk, const u8 *pblk, const u8 *fw) +{ +	struct qtnf_bus *bus = pci_get_drvdata(pdev); + +	struct qtnf_pearl_fw_hdr *hdr; +	u8 *pdata; + +	int hds = sizeof(*hdr); +	struct sk_buff *skb = NULL; +	int len = 0; +	int ret; + +	skb = __dev_alloc_skb(QTN_PCIE_FW_BUFSZ, GFP_KERNEL); +	if (!skb) +		return -ENOMEM; + +	skb->len = QTN_PCIE_FW_BUFSZ; +	skb->dev = NULL; + +	hdr = (struct qtnf_pearl_fw_hdr *)skb->data; +	memcpy(hdr->boardflg, QTN_PCIE_BOARDFLG, strlen(QTN_PCIE_BOARDFLG)); +	hdr->fwsize = cpu_to_le32(size); +	hdr->seqnum = cpu_to_le32(blk); + +	if (blk) +		hdr->type = cpu_to_le32(QTN_FW_DSUB); +	else +		hdr->type = cpu_to_le32(QTN_FW_DBEGIN); + +	pdata = skb->data + hds; + +	len = QTN_PCIE_FW_BUFSZ - hds; +	if (pblk >= (fw + size - len)) { +		len = fw + size - pblk; +		hdr->type = cpu_to_le32(QTN_FW_DEND); +	} + +	hdr->pktlen = cpu_to_le32(len); +	memcpy(pdata, pblk, len); +	hdr->crc = cpu_to_le32(~crc32(0, pdata, len)); + +	ret = qtnf_pcie_data_tx(bus, skb); + +	return (ret == NETDEV_TX_OK) ? len : 0; +} + +static int +qtnf_ep_fw_load(struct qtnf_pcie_pearl_state *ps, const u8 *fw, u32 fw_size) +{ +	int blk_size = QTN_PCIE_FW_BUFSZ - sizeof(struct qtnf_pearl_fw_hdr); +	int blk_count = fw_size / blk_size + ((fw_size % blk_size) ? 1 : 0); +	const u8 *pblk = fw; +	int threshold = 0; +	int blk = 0; +	int len; + +	pr_debug("FW upload started: fw_addr=0x%p size=%d\n", fw, fw_size); + +	while (blk < blk_count) { +		if (++threshold > 10000) { +			pr_err("FW upload failed: too many retries\n"); +			return -ETIMEDOUT; +		} + +		len = qtnf_ep_fw_send(ps->base.pdev, fw_size, blk, pblk, fw); +		if (len <= 0) +			continue; + +		if (!((blk + 1) & QTN_PCIE_FW_DLMASK) || +		    (blk == (blk_count - 1))) { +			qtnf_set_state(&ps->bda->bda_rc_state, +				       QTN_RC_FW_SYNC); +			if (qtnf_poll_state(&ps->bda->bda_ep_state, +					    QTN_EP_FW_SYNC, +					    QTN_FW_DL_TIMEOUT_MS)) { +				pr_err("FW upload failed: SYNC timed out\n"); +				return -ETIMEDOUT; +			} + +			qtnf_clear_state(&ps->bda->bda_ep_state, +					 QTN_EP_FW_SYNC); + +			if (qtnf_is_state(&ps->bda->bda_ep_state, +					  QTN_EP_FW_RETRY)) { +				if (blk == (blk_count - 1)) { +					int last_round = +						blk_count & QTN_PCIE_FW_DLMASK; +					blk -= last_round; +					pblk -= ((last_round - 1) * +						blk_size + len); +				} else { +					blk -= QTN_PCIE_FW_DLMASK; +					pblk -= QTN_PCIE_FW_DLMASK * blk_size; +				} + +				qtnf_clear_state(&ps->bda->bda_ep_state, +						 QTN_EP_FW_RETRY); + +				pr_warn("FW upload retry: block #%d\n", blk); +				continue; +			} + +			qtnf_pearl_data_tx_reclaim(ps); +		} + +		pblk += len; +		blk++; +	} + +	pr_debug("FW upload completed: totally sent %d blocks\n", blk); +	return 0; +} + +static void qtnf_pearl_fw_work_handler(struct work_struct *work) +{ +	struct qtnf_bus *bus = container_of(work, struct qtnf_bus, fw_work); +	struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); +	struct pci_dev *pdev = ps->base.pdev; +	const struct firmware *fw; +	int ret; +	u32 state = QTN_RC_FW_LOADRDY | QTN_RC_FW_QLINK; +	const char *fwname = QTN_PCI_PEARL_FW_NAME; +	bool fw_boot_success = false; + +	if (flashboot) { +		state |= QTN_RC_FW_FLASHBOOT; +	} else { +		ret = request_firmware(&fw, fwname, &pdev->dev); +		if (ret < 0) { +			pr_err("failed to get firmware %s\n", fwname); +			goto fw_load_exit; +		} +	} + +	qtnf_set_state(&ps->bda->bda_rc_state, state); + +	if (qtnf_poll_state(&ps->bda->bda_ep_state, QTN_EP_FW_LOADRDY, +			    QTN_FW_DL_TIMEOUT_MS)) { +		pr_err("card is not ready\n"); + +		if (!flashboot) +			release_firmware(fw); + +		goto fw_load_exit; +	} + +	qtnf_clear_state(&ps->bda->bda_ep_state, QTN_EP_FW_LOADRDY); + +	if (flashboot) { +		pr_info("booting firmware from flash\n"); + +	} else { +		pr_info("starting firmware upload: %s\n", fwname); + +		ret = qtnf_ep_fw_load(ps, fw->data, fw->size); +		release_firmware(fw); +		if (ret) { +			pr_err("firmware upload error\n"); +			goto fw_load_exit; +		} +	} + +	if (qtnf_poll_state(&ps->bda->bda_ep_state, QTN_EP_FW_DONE, +			    QTN_FW_DL_TIMEOUT_MS)) { +		pr_err("firmware bringup timed out\n"); +		goto fw_load_exit; +	} + +	pr_info("firmware is up and running\n"); + +	if (qtnf_poll_state(&ps->bda->bda_ep_state, +			    QTN_EP_FW_QLINK_DONE, QTN_FW_QLINK_TIMEOUT_MS)) { +		pr_err("firmware runtime failure\n"); +		goto fw_load_exit; +	} + +	fw_boot_success = true; + +fw_load_exit: +	qtnf_pcie_fw_boot_done(bus, fw_boot_success, DRV_NAME); + +	if (fw_boot_success) { +		qtnf_debugfs_add_entry(bus, "hdp_stats", qtnf_dbg_hdp_stats); +		qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats); +	} +} + +static void qtnf_pearl_reclaim_tasklet_fn(unsigned long data) +{ +	struct qtnf_pcie_pearl_state *ps = (void *)data; + +	qtnf_pearl_data_tx_reclaim(ps); +	qtnf_en_txdone_irq(ps); +} + +static int qtnf_pearl_check_chip_id(struct qtnf_pcie_pearl_state *ps) +{ +	unsigned int chipid; + +	chipid = qtnf_chip_id_get(ps->base.sysctl_bar); + +	switch (chipid) { +	case QTN_CHIP_ID_PEARL: +	case QTN_CHIP_ID_PEARL_B: +	case QTN_CHIP_ID_PEARL_C: +		pr_info("chip ID is 0x%x\n", chipid); +		break; +	default: +		pr_err("incorrect chip ID 0x%x\n", chipid); +		return -ENODEV; +	} + +	return 0; +} + +static int qtnf_pcie_pearl_probe(struct pci_dev *pdev, +				 const struct pci_device_id *id) +{ +	struct qtnf_shm_ipc_int ipc_int; +	struct qtnf_pcie_pearl_state *ps; +	struct qtnf_bus *bus; +	int ret; +	u64 dma_mask; + +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT +	dma_mask = DMA_BIT_MASK(64); +#else +	dma_mask = DMA_BIT_MASK(32); +#endif + +	ret = qtnf_pcie_probe(pdev, sizeof(*ps), &qtnf_pcie_pearl_bus_ops, +			      dma_mask, use_msi); +	if (ret) +		return ret; + +	bus = pci_get_drvdata(pdev); +	ps = get_bus_priv(bus); + +	spin_lock_init(&ps->irq_lock); + +	tasklet_init(&ps->base.reclaim_tq, qtnf_pearl_reclaim_tasklet_fn, +		     (unsigned long)ps); +	netif_napi_add(&bus->mux_dev, &bus->mux_napi, +		       qtnf_pcie_pearl_rx_poll, 10); +	INIT_WORK(&bus->fw_work, qtnf_pearl_fw_work_handler); + +	ps->pcie_reg_base = ps->base.dmareg_bar; +	ps->bda = ps->base.epmem_bar; +	writel(ps->base.msi_enabled, &ps->bda->bda_rc_msi_enabled); + +	ipc_int.fn = qtnf_pcie_pearl_ipc_gen_ep_int; +	ipc_int.arg = ps; +	qtnf_pcie_init_shm_ipc(&ps->base, &ps->bda->bda_shm_reg1, +			       &ps->bda->bda_shm_reg2, &ipc_int); + +	ret = qtnf_pearl_check_chip_id(ps); +	if (ret) +		goto error; + +	ret = qtnf_pcie_pearl_init_xfer(ps); +	if (ret) { +		pr_err("PCIE xfer init failed\n"); +		goto error; +	} + +	/* init default irq settings */ +	qtnf_init_hdp_irqs(ps); + +	/* start with disabled irqs */ +	qtnf_disable_hdp_irqs(ps); + +	ret = devm_request_irq(&pdev->dev, pdev->irq, +			       &qtnf_pcie_pearl_interrupt, 0, +			       "qtnf_pcie_irq", (void *)bus); +	if (ret) { +		pr_err("failed to request pcie irq %d\n", pdev->irq); +		goto err_xfer; +	} + +	qtnf_pcie_bringup_fw_async(bus); + +	return 0; + +err_xfer: +	qtnf_pearl_free_xfer_buffers(ps); +error: +	qtnf_pcie_remove(bus, &ps->base); + +	return ret; +} + +static void qtnf_pcie_pearl_remove(struct pci_dev *pdev) +{ +	struct qtnf_pcie_pearl_state *ps; +	struct qtnf_bus *bus; + +	bus = pci_get_drvdata(pdev); +	if (!bus) +		return; + +	ps = get_bus_priv(bus); + +	qtnf_pcie_remove(bus, &ps->base); +	qtnf_pearl_reset_ep(ps); +	qtnf_pearl_free_xfer_buffers(ps); +} + +#ifdef CONFIG_PM_SLEEP +static int qtnf_pcie_pearl_suspend(struct device *dev) +{ +	return -EOPNOTSUPP; +} + +static int qtnf_pcie_pearl_resume(struct device *dev) +{ +	return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM_SLEEP +/* Power Management Hooks */ +static SIMPLE_DEV_PM_OPS(qtnf_pcie_pearl_pm_ops, qtnf_pcie_pearl_suspend, +			 qtnf_pcie_pearl_resume); +#endif + +static const struct pci_device_id qtnf_pcie_devid_table[] = { +	{ +		PCIE_VENDOR_ID_QUANTENNA, PCIE_DEVICE_ID_QTN_PEARL, +		PCI_ANY_ID, PCI_ANY_ID, 0, 0, +	}, +	{ }, +}; + +MODULE_DEVICE_TABLE(pci, qtnf_pcie_devid_table); + +static struct pci_driver qtnf_pcie_pearl_drv_data = { +	.name = DRV_NAME, +	.id_table = qtnf_pcie_devid_table, +	.probe = qtnf_pcie_pearl_probe, +	.remove = qtnf_pcie_pearl_remove, +#ifdef CONFIG_PM_SLEEP +	.driver = { +		.pm = &qtnf_pcie_pearl_pm_ops, +	}, +#endif +}; + +static int __init qtnf_pcie_pearl_register(void) +{ +	pr_info("register Quantenna QSR10g FullMAC PCIE driver\n"); +	return pci_register_driver(&qtnf_pcie_pearl_drv_data); +} + +static void __exit qtnf_pcie_pearl_exit(void) +{ +	pr_info("unregister Quantenna QSR10g FullMAC PCIE driver\n"); +	pci_unregister_driver(&qtnf_pcie_pearl_drv_data); +} + +module_init(qtnf_pcie_pearl_register); +module_exit(qtnf_pcie_pearl_exit); + +MODULE_AUTHOR("Quantenna Communications"); +MODULE_DESCRIPTION("Quantenna QSR10g PCIe bus driver for 802.11 wireless LAN."); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h index 00bb21a1c47a..634480fe6a64 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_ipc.h +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_ipc.h @@ -1,18 +1,5 @@ -/* - * Copyright (c) 2015-2016 Quantenna Communications, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - */ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2015-2016 Quantenna Communications */  #ifndef _QTN_FMAC_PCIE_IPC_H_  #define _QTN_FMAC_PCIE_IPC_H_ @@ -43,11 +30,6 @@  #define QTN_RC_FW_LOADRDY	BIT(8)  #define QTN_RC_FW_SYNC		BIT(9) -/* state transition timeouts */ -#define QTN_FW_DL_TIMEOUT_MS	3000 -#define QTN_FW_QLINK_TIMEOUT_MS	30000 -#define QTN_EP_RESET_WAIT_MS	1000 -  #define PCIE_HDP_INT_RX_BITS (0		\  	| PCIE_HDP_INT_EP_TXDMA		\  	| PCIE_HDP_INT_EP_TXEMPTY	\ @@ -68,17 +50,11 @@  #define QTN_HOST_ADDR(h, l)	((u32)l)  #endif -#define QTN_SYSCTL_BAR	0 -#define QTN_SHMEM_BAR	2 -#define QTN_DMA_BAR	3 -  #define QTN_PCIE_BDA_VERSION		0x1002  #define PCIE_BDA_NAMELEN		32  #define PCIE_HHBM_MAX_SIZE		2048 -#define SKB_BUF_SIZE		2048 -  #define QTN_PCIE_BOARDFLG	"PCIEQTN"  #define QTN_PCIE_FW_DLMASK	0xF  #define QTN_PCIE_FW_BUFSZ	2048 @@ -96,49 +72,6 @@  #define QTN_EP_LHOST_TQE_PORT	4 -enum qtnf_pcie_bda_ipc_flags { -	QTN_PCIE_IPC_FLAG_HBM_MAGIC	= BIT(0), -	QTN_PCIE_IPC_FLAG_SHM_PIO	= BIT(1), -}; - -struct qtnf_pcie_bda { -	__le16 bda_len; -	__le16 bda_version; -	__le32 bda_pci_endian; -	__le32 bda_ep_state; -	__le32 bda_rc_state; -	__le32 bda_dma_mask; -	__le32 bda_msi_addr; -	__le32 bda_flashsz; -	u8 bda_boardname[PCIE_BDA_NAMELEN]; -	__le32 bda_rc_msi_enabled; -	u8 bda_hhbm_list[PCIE_HHBM_MAX_SIZE]; -	__le32 bda_dsbw_start_index; -	__le32 bda_dsbw_end_index; -	__le32 bda_dsbw_total_bytes; -	__le32 bda_rc_tx_bd_base; -	__le32 bda_rc_tx_bd_num; -	u8 bda_pcie_mac[QTN_ENET_ADDR_LENGTH]; -	struct qtnf_shm_ipc_region bda_shm_reg1 __aligned(4096); /* host TX */ -	struct qtnf_shm_ipc_region bda_shm_reg2 __aligned(4096); /* host RX */ -} __packed; - -struct qtnf_tx_bd { -	__le32 addr; -	__le32 addr_h; -	__le32 info; -	__le32 info_h; -} __packed; - -struct qtnf_rx_bd { -	__le32 addr; -	__le32 addr_h; -	__le32 info; -	__le32 info_h; -	__le32 next_ptr; -	__le32 next_ptr_h; -} __packed; -  enum qtnf_fw_loadtype {  	QTN_FW_DBEGIN,  	QTN_FW_DSUB, @@ -146,13 +79,4 @@ enum qtnf_fw_loadtype {  	QTN_FW_CTRL  }; -struct qtnf_pcie_fw_hdr { -	u8 boardflg[8]; -	__le32 fwsize; -	__le32 seqnum; -	__le32 type; -	__le32 pktlen; -	__le32 crc; -} __packed; -  #endif /* _QTN_FMAC_PCIE_IPC_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h new file mode 100644 index 000000000000..6e9a5c61d46f --- /dev/null +++ b/drivers/net/wireless/quantenna/qtnfmac/pcie/pearl_pcie_regs.h @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* Copyright (c) 2015 Quantenna Communications */ + +#ifndef __PEARL_PCIE_H +#define __PEARL_PCIE_H + +/* Pearl PCIe HDP registers */ +#define PCIE_HDP_CTRL(base)			((base) + 0x2c00) +#define PCIE_HDP_AXI_CTRL(base)			((base) + 0x2c04) +#define PCIE_HDP_HOST_WR_DESC0(base)		((base) + 0x2c10) +#define PCIE_HDP_HOST_WR_DESC0_H(base)		((base) + 0x2c14) +#define PCIE_HDP_HOST_WR_DESC1(base)		((base) + 0x2c18) +#define PCIE_HDP_HOST_WR_DESC1_H(base)		((base) + 0x2c1c) +#define PCIE_HDP_HOST_WR_DESC2(base)		((base) + 0x2c20) +#define PCIE_HDP_HOST_WR_DESC2_H(base)		((base) + 0x2c24) +#define PCIE_HDP_HOST_WR_DESC3(base)		((base) + 0x2c28) +#define PCIE_HDP_HOST_WR_DESC4_H(base)		((base) + 0x2c2c) +#define PCIE_HDP_RX_INT_CTRL(base)		((base) + 0x2c30) +#define PCIE_HDP_TX_INT_CTRL(base)		((base) + 0x2c34) +#define PCIE_HDP_INT_STATUS(base)		((base) + 0x2c38) +#define PCIE_HDP_INT_EN(base)			((base) + 0x2c3c) +#define PCIE_HDP_RX_DESC0_PTR(base)		((base) + 0x2c40) +#define PCIE_HDP_RX_DESC0_NOE(base)		((base) + 0x2c44) +#define PCIE_HDP_RX_DESC1_PTR(base)		((base) + 0x2c48) +#define PCIE_HDP_RX_DESC1_NOE(base)		((base) + 0x2c4c) +#define PCIE_HDP_RX_DESC2_PTR(base)		((base) + 0x2c50) +#define PCIE_HDP_RX_DESC2_NOE(base)		((base) + 0x2c54) +#define PCIE_HDP_RX_DESC3_PTR(base)		((base) + 0x2c58) +#define PCIE_HDP_RX_DESC3_NOE(base)		((base) + 0x2c5c) + +#define PCIE_HDP_TX0_BASE_ADDR(base)		((base) + 0x2c60) +#define PCIE_HDP_TX1_BASE_ADDR(base)		((base) + 0x2c64) +#define PCIE_HDP_TX0_Q_CTRL(base)		((base) + 0x2c70) +#define PCIE_HDP_TX1_Q_CTRL(base)		((base) + 0x2c74) +#define PCIE_HDP_CFG0(base)			((base) + 0x2c80) +#define PCIE_HDP_CFG1(base)			((base) + 0x2c84) +#define PCIE_HDP_CFG2(base)			((base) + 0x2c88) +#define PCIE_HDP_CFG3(base)			((base) + 0x2c8c) +#define PCIE_HDP_CFG4(base)			((base) + 0x2c90) +#define PCIE_HDP_CFG5(base)			((base) + 0x2c94) +#define PCIE_HDP_CFG6(base)			((base) + 0x2c98) +#define PCIE_HDP_CFG7(base)			((base) + 0x2c9c) +#define PCIE_HDP_CFG8(base)			((base) + 0x2ca0) +#define PCIE_HDP_CFG9(base)			((base) + 0x2ca4) +#define PCIE_HDP_CFG10(base)			((base) + 0x2ca8) +#define PCIE_HDP_CFG11(base)			((base) + 0x2cac) +#define PCIE_INT(base)				((base) + 0x2cb0) +#define PCIE_INT_MASK(base)			((base) + 0x2cb4) +#define PCIE_MSI_MASK(base)			((base) + 0x2cb8) +#define PCIE_MSI_PNDG(base)			((base) + 0x2cbc) +#define PCIE_PRI_CFG(base)			((base) + 0x2cc0) +#define PCIE_PHY_CR(base)			((base) + 0x2cc4) +#define PCIE_HDP_CTAG_CTRL(base)		((base) + 0x2cf4) +#define PCIE_HDP_HHBM_BUF_PTR(base)		((base) + 0x2d00) +#define PCIE_HDP_HHBM_BUF_PTR_H(base)		((base) + 0x2d04) +#define PCIE_HDP_HHBM_BUF_FIFO_NOE(base)	((base) + 0x2d04) +#define PCIE_HDP_RX0DMA_CNT(base)		((base) + 0x2d10) +#define PCIE_HDP_RX1DMA_CNT(base)		((base) + 0x2d14) +#define PCIE_HDP_RX2DMA_CNT(base)		((base) + 0x2d18) +#define PCIE_HDP_RX3DMA_CNT(base)		((base) + 0x2d1c) +#define PCIE_HDP_TX0DMA_CNT(base)		((base) + 0x2d20) +#define PCIE_HDP_TX1DMA_CNT(base)		((base) + 0x2d24) +#define PCIE_HDP_RXDMA_CTRL(base)		((base) + 0x2d28) +#define PCIE_HDP_TX_HOST_Q_SZ_CTRL(base)	((base) + 0x2d2c) +#define PCIE_HDP_TX_HOST_Q_BASE_L(base)		((base) + 0x2d30) +#define PCIE_HDP_TX_HOST_Q_BASE_H(base)		((base) + 0x2d34) +#define PCIE_HDP_TX_HOST_Q_WR_PTR(base)		((base) + 0x2d38) +#define PCIE_HDP_TX_HOST_Q_RD_PTR(base)		((base) + 0x2d3c) +#define PCIE_HDP_TX_HOST_Q_STS(base)		((base) + 0x2d40) + +/* Pearl PCIe HBM pool registers */ +#define PCIE_HHBM_CSR_REG(base)			((base) + 0x2e00) +#define PCIE_HHBM_Q_BASE_REG(base)		((base) + 0x2e04) +#define PCIE_HHBM_Q_LIMIT_REG(base)		((base) + 0x2e08) +#define PCIE_HHBM_Q_WR_REG(base)		((base) + 0x2e0c) +#define PCIE_HHBM_Q_RD_REG(base)		((base) + 0x2e10) +#define PCIE_HHBM_POOL_DATA_0_H(base)		((base) + 0x2e90) +#define PCIE_HHBM_CONFIG(base)			((base) + 0x2f9c) +#define PCIE_HHBM_POOL_REQ_0(base)		((base) + 0x2f10) +#define PCIE_HHBM_POOL_DATA_0(base)		((base) + 0x2f40) +#define PCIE_HHBM_WATERMARK_MASKED_INT(base)	((base) + 0x2f68) +#define PCIE_HHBM_WATERMARK_INT(base)		((base) + 0x2f6c) +#define PCIE_HHBM_POOL_WATERMARK(base)		((base) + 0x2f70) +#define PCIE_HHBM_POOL_OVERFLOW_CNT(base)	((base) + 0x2f90) +#define PCIE_HHBM_POOL_UNDERFLOW_CNT(base)	((base) + 0x2f94) +#define HBM_INT_STATUS(base)			((base) + 0x2f9c) +#define PCIE_HHBM_POOL_CNFIG(base)		((base) + 0x2f9c) + +/* Pearl PCIe HBM bit field definitions */ +#define HHBM_CONFIG_SOFT_RESET			(BIT(8)) +#define HHBM_WR_REQ				(BIT(0)) +#define HHBM_RD_REQ				(BIT(1)) +#define HHBM_DONE				(BIT(31)) +#define HHBM_64BIT				(BIT(10)) + +/* PCIe HDP interrupt status definition */ +#define PCIE_HDP_INT_EP_RXDMA		(BIT(0)) +#define PCIE_HDP_INT_HBM_UF		(BIT(1)) +#define PCIE_HDP_INT_RX_LEN_ERR		(BIT(2)) +#define PCIE_HDP_INT_RX_HDR_LEN_ERR	(BIT(3)) +#define PCIE_HDP_INT_EP_TXDMA		(BIT(12)) +#define PCIE_HDP_INT_HHBM_UF		(BIT(13)) +#define PCIE_HDP_INT_EP_TXEMPTY		(BIT(15)) +#define PCIE_HDP_INT_IPC		(BIT(29)) + +/* PCIe interrupt status definition */ +#define PCIE_INT_MSI			(BIT(24)) +#define PCIE_INT_INTX			(BIT(23)) + +/* PCIe legacy INTx */ +#define PEARL_PCIE_CFG0_OFFSET		(0x6C) +#define PEARL_ASSERT_INTX		(BIT(9)) + +/* SYS CTL regs */ +#define QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET	(0x001C) + +#define QTN_PEARL_IPC_IRQ_WORD(irq)	(BIT(irq) | BIT(irq + 16)) +#define QTN_PEARL_LHOST_IPC_IRQ		(6) +#define QTN_PEARL_LHOST_EP_RESET	(7) + +#endif /* __PEARL_PCIE_H */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c deleted file mode 100644 index 3120d49df565..000000000000 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie.c +++ /dev/null @@ -1,1494 +0,0 @@ -/* - * Copyright (c) 2015-2016 Quantenna Communications, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/firmware.h> -#include <linux/pci.h> -#include <linux/vmalloc.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/sched.h> -#include <linux/completion.h> -#include <linux/crc32.h> -#include <linux/spinlock.h> -#include <linux/circ_buf.h> -#include <linux/log2.h> - -#include "qtn_hw_ids.h" -#include "pcie_bus_priv.h" -#include "core.h" -#include "bus.h" -#include "debug.h" - -static bool use_msi = true; -module_param(use_msi, bool, 0644); -MODULE_PARM_DESC(use_msi, "set 0 to use legacy interrupt"); - -static unsigned int tx_bd_size_param = 32; -module_param(tx_bd_size_param, uint, 0644); -MODULE_PARM_DESC(tx_bd_size_param, "Tx descriptors queue size, power of two"); - -static unsigned int rx_bd_size_param = 256; -module_param(rx_bd_size_param, uint, 0644); -MODULE_PARM_DESC(rx_bd_size_param, "Rx descriptors queue size, power of two"); - -static u8 flashboot = 1; -module_param(flashboot, byte, 0644); -MODULE_PARM_DESC(flashboot, "set to 0 to use FW binary file on FS"); - -#define DRV_NAME	"qtnfmac_pearl_pcie" - -static inline void qtnf_non_posted_write(u32 val, void __iomem *basereg) -{ -	writel(val, basereg); - -	/* flush posted write */ -	readl(basereg); -} - -static inline void qtnf_init_hdp_irqs(struct qtnf_pcie_bus_priv *priv) -{ -	unsigned long flags; - -	spin_lock_irqsave(&priv->irq_lock, flags); -	priv->pcie_irq_mask = (PCIE_HDP_INT_RX_BITS | PCIE_HDP_INT_TX_BITS); -	spin_unlock_irqrestore(&priv->irq_lock, flags); -} - -static inline void qtnf_enable_hdp_irqs(struct qtnf_pcie_bus_priv *priv) -{ -	unsigned long flags; - -	spin_lock_irqsave(&priv->irq_lock, flags); -	writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); -	spin_unlock_irqrestore(&priv->irq_lock, flags); -} - -static inline void qtnf_disable_hdp_irqs(struct qtnf_pcie_bus_priv *priv) -{ -	unsigned long flags; - -	spin_lock_irqsave(&priv->irq_lock, flags); -	writel(0x0, PCIE_HDP_INT_EN(priv->pcie_reg_base)); -	spin_unlock_irqrestore(&priv->irq_lock, flags); -} - -static inline void qtnf_en_rxdone_irq(struct qtnf_pcie_bus_priv *priv) -{ -	unsigned long flags; - -	spin_lock_irqsave(&priv->irq_lock, flags); -	priv->pcie_irq_mask |= PCIE_HDP_INT_RX_BITS; -	writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); -	spin_unlock_irqrestore(&priv->irq_lock, flags); -} - -static inline void qtnf_dis_rxdone_irq(struct qtnf_pcie_bus_priv *priv) -{ -	unsigned long flags; - -	spin_lock_irqsave(&priv->irq_lock, flags); -	priv->pcie_irq_mask &= ~PCIE_HDP_INT_RX_BITS; -	writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); -	spin_unlock_irqrestore(&priv->irq_lock, flags); -} - -static inline void qtnf_en_txdone_irq(struct qtnf_pcie_bus_priv *priv) -{ -	unsigned long flags; - -	spin_lock_irqsave(&priv->irq_lock, flags); -	priv->pcie_irq_mask |= PCIE_HDP_INT_TX_BITS; -	writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); -	spin_unlock_irqrestore(&priv->irq_lock, flags); -} - -static inline void qtnf_dis_txdone_irq(struct qtnf_pcie_bus_priv *priv) -{ -	unsigned long flags; - -	spin_lock_irqsave(&priv->irq_lock, flags); -	priv->pcie_irq_mask &= ~PCIE_HDP_INT_TX_BITS; -	writel(priv->pcie_irq_mask, PCIE_HDP_INT_EN(priv->pcie_reg_base)); -	spin_unlock_irqrestore(&priv->irq_lock, flags); -} - -static void qtnf_pcie_init_irq(struct qtnf_pcie_bus_priv *priv) -{ -	struct pci_dev *pdev = priv->pdev; - -	/* fall back to legacy INTx interrupts by default */ -	priv->msi_enabled = 0; - -	/* check if MSI capability is available */ -	if (use_msi) { -		if (!pci_enable_msi(pdev)) { -			pr_debug("MSI interrupt enabled\n"); -			priv->msi_enabled = 1; -		} else { -			pr_warn("failed to enable MSI interrupts"); -		} -	} - -	if (!priv->msi_enabled) { -		pr_warn("legacy PCIE interrupts enabled\n"); -		pci_intx(pdev, 1); -	} -} - -static void qtnf_deassert_intx(struct qtnf_pcie_bus_priv *priv) -{ -	void __iomem *reg = priv->sysctl_bar + PEARL_PCIE_CFG0_OFFSET; -	u32 cfg; - -	cfg = readl(reg); -	cfg &= ~PEARL_ASSERT_INTX; -	qtnf_non_posted_write(cfg, reg); -} - -static void qtnf_reset_card(struct qtnf_pcie_bus_priv *priv) -{ -	const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_EP_RESET); -	void __iomem *reg = priv->sysctl_bar + -			    QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET; - -	qtnf_non_posted_write(data, reg); -	msleep(QTN_EP_RESET_WAIT_MS); -	pci_restore_state(priv->pdev); -} - -static void qtnf_ipc_gen_ep_int(void *arg) -{ -	const struct qtnf_pcie_bus_priv *priv = arg; -	const u32 data = QTN_PEARL_IPC_IRQ_WORD(QTN_PEARL_LHOST_IPC_IRQ); -	void __iomem *reg = priv->sysctl_bar + -			    QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET; - -	qtnf_non_posted_write(data, reg); -} - -static void __iomem *qtnf_map_bar(struct qtnf_pcie_bus_priv *priv, u8 index) -{ -	void __iomem *vaddr; -	dma_addr_t busaddr; -	size_t len; -	int ret; - -	ret = pcim_iomap_regions(priv->pdev, 1 << index, DRV_NAME); -	if (ret) -		return IOMEM_ERR_PTR(ret); - -	busaddr = pci_resource_start(priv->pdev, index); -	len = pci_resource_len(priv->pdev, index); -	vaddr = pcim_iomap_table(priv->pdev)[index]; -	if (!vaddr) -		return IOMEM_ERR_PTR(-ENOMEM); - -	pr_debug("BAR%u vaddr=0x%p busaddr=%pad len=%u\n", -		 index, vaddr, &busaddr, (int)len); - -	return vaddr; -} - -static void qtnf_pcie_control_rx_callback(void *arg, const u8 *buf, size_t len) -{ -	struct qtnf_pcie_bus_priv *priv = arg; -	struct qtnf_bus *bus = pci_get_drvdata(priv->pdev); -	struct sk_buff *skb; - -	if (unlikely(len == 0)) { -		pr_warn("zero length packet received\n"); -		return; -	} - -	skb = __dev_alloc_skb(len, GFP_KERNEL); - -	if (unlikely(!skb)) { -		pr_err("failed to allocate skb\n"); -		return; -	} - -	skb_put_data(skb, buf, len); - -	qtnf_trans_handle_rx_ctl_packet(bus, skb); -} - -static int qtnf_pcie_init_shm_ipc(struct qtnf_pcie_bus_priv *priv) -{ -	struct qtnf_shm_ipc_region __iomem *ipc_tx_reg; -	struct qtnf_shm_ipc_region __iomem *ipc_rx_reg; -	const struct qtnf_shm_ipc_int ipc_int = { qtnf_ipc_gen_ep_int, priv }; -	const struct qtnf_shm_ipc_rx_callback rx_callback = { -					qtnf_pcie_control_rx_callback, priv }; - -	ipc_tx_reg = &priv->bda->bda_shm_reg1; -	ipc_rx_reg = &priv->bda->bda_shm_reg2; - -	qtnf_shm_ipc_init(&priv->shm_ipc_ep_in, QTNF_SHM_IPC_OUTBOUND, -			  ipc_tx_reg, priv->workqueue, -			  &ipc_int, &rx_callback); -	qtnf_shm_ipc_init(&priv->shm_ipc_ep_out, QTNF_SHM_IPC_INBOUND, -			  ipc_rx_reg, priv->workqueue, -			  &ipc_int, &rx_callback); - -	return 0; -} - -static void qtnf_pcie_free_shm_ipc(struct qtnf_pcie_bus_priv *priv) -{ -	qtnf_shm_ipc_free(&priv->shm_ipc_ep_in); -	qtnf_shm_ipc_free(&priv->shm_ipc_ep_out); -} - -static int qtnf_pcie_init_memory(struct qtnf_pcie_bus_priv *priv) -{ -	int ret = -ENOMEM; - -	priv->sysctl_bar = qtnf_map_bar(priv, QTN_SYSCTL_BAR); -	if (IS_ERR(priv->sysctl_bar)) { -		pr_err("failed to map BAR%u\n", QTN_SYSCTL_BAR); -		return ret; -	} - -	priv->dmareg_bar = qtnf_map_bar(priv, QTN_DMA_BAR); -	if (IS_ERR(priv->dmareg_bar)) { -		pr_err("failed to map BAR%u\n", QTN_DMA_BAR); -		return ret; -	} - -	priv->epmem_bar = qtnf_map_bar(priv, QTN_SHMEM_BAR); -	if (IS_ERR(priv->epmem_bar)) { -		pr_err("failed to map BAR%u\n", QTN_SHMEM_BAR); -		return ret; -	} - -	priv->pcie_reg_base = priv->dmareg_bar; -	priv->bda = priv->epmem_bar; -	writel(priv->msi_enabled, &priv->bda->bda_rc_msi_enabled); - -	return 0; -} - -static void qtnf_tune_pcie_mps(struct qtnf_pcie_bus_priv *priv) -{ -	struct pci_dev *pdev = priv->pdev; -	struct pci_dev *parent; -	int mps_p, mps_o, mps_m, mps; -	int ret; - -	/* current mps */ -	mps_o = pcie_get_mps(pdev); - -	/* maximum supported mps */ -	mps_m = 128 << pdev->pcie_mpss; - -	/* suggested new mps value */ -	mps = mps_m; - -	if (pdev->bus && pdev->bus->self) { -		/* parent (bus) mps */ -		parent = pdev->bus->self; - -		if (pci_is_pcie(parent)) { -			mps_p = pcie_get_mps(parent); -			mps = min(mps_m, mps_p); -		} -	} - -	ret = pcie_set_mps(pdev, mps); -	if (ret) { -		pr_err("failed to set mps to %d, keep using current %d\n", -		       mps, mps_o); -		priv->mps = mps_o; -		return; -	} - -	pr_debug("set mps to %d (was %d, max %d)\n", mps, mps_o, mps_m); -	priv->mps = mps; -} - -static int qtnf_is_state(__le32 __iomem *reg, u32 state) -{ -	u32 s = readl(reg); - -	return s & state; -} - -static void qtnf_set_state(__le32 __iomem *reg, u32 state) -{ -	u32 s = readl(reg); - -	qtnf_non_posted_write(state | s, reg); -} - -static void qtnf_clear_state(__le32 __iomem *reg, u32 state) -{ -	u32 s = readl(reg); - -	qtnf_non_posted_write(s & ~state, reg); -} - -static int qtnf_poll_state(__le32 __iomem *reg, u32 state, u32 delay_in_ms) -{ -	u32 timeout = 0; - -	while ((qtnf_is_state(reg, state) == 0)) { -		usleep_range(1000, 1200); -		if (++timeout > delay_in_ms) -			return -1; -	} - -	return 0; -} - -static int alloc_skb_array(struct qtnf_pcie_bus_priv *priv) -{ -	struct sk_buff **vaddr; -	int len; - -	len = priv->tx_bd_num * sizeof(*priv->tx_skb) + -		priv->rx_bd_num * sizeof(*priv->rx_skb); -	vaddr = devm_kzalloc(&priv->pdev->dev, len, GFP_KERNEL); - -	if (!vaddr) -		return -ENOMEM; - -	priv->tx_skb = vaddr; - -	vaddr += priv->tx_bd_num; -	priv->rx_skb = vaddr; - -	return 0; -} - -static int alloc_bd_table(struct qtnf_pcie_bus_priv *priv) -{ -	dma_addr_t paddr; -	void *vaddr; -	int len; - -	len = priv->tx_bd_num * sizeof(struct qtnf_tx_bd) + -		priv->rx_bd_num * sizeof(struct qtnf_rx_bd); - -	vaddr = dmam_alloc_coherent(&priv->pdev->dev, len, &paddr, GFP_KERNEL); -	if (!vaddr) -		return -ENOMEM; - -	/* tx bd */ - -	memset(vaddr, 0, len); - -	priv->bd_table_vaddr = vaddr; -	priv->bd_table_paddr = paddr; -	priv->bd_table_len = len; - -	priv->tx_bd_vbase = vaddr; -	priv->tx_bd_pbase = paddr; - -	pr_debug("TX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr); - -	priv->tx_bd_r_index = 0; -	priv->tx_bd_w_index = 0; - -	/* rx bd */ - -	vaddr = ((struct qtnf_tx_bd *)vaddr) + priv->tx_bd_num; -	paddr += priv->tx_bd_num * sizeof(struct qtnf_tx_bd); - -	priv->rx_bd_vbase = vaddr; -	priv->rx_bd_pbase = paddr; - -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -	writel(QTN_HOST_HI32(paddr), -	       PCIE_HDP_TX_HOST_Q_BASE_H(priv->pcie_reg_base)); -#endif -	writel(QTN_HOST_LO32(paddr), -	       PCIE_HDP_TX_HOST_Q_BASE_L(priv->pcie_reg_base)); -	writel(priv->rx_bd_num | (sizeof(struct qtnf_rx_bd)) << 16, -	       PCIE_HDP_TX_HOST_Q_SZ_CTRL(priv->pcie_reg_base)); - -	pr_debug("RX descriptor table: vaddr=0x%p paddr=%pad\n", vaddr, &paddr); - -	return 0; -} - -static int skb2rbd_attach(struct qtnf_pcie_bus_priv *priv, u16 index) -{ -	struct qtnf_rx_bd *rxbd; -	struct sk_buff *skb; -	dma_addr_t paddr; - -	skb = __netdev_alloc_skb_ip_align(NULL, SKB_BUF_SIZE, GFP_ATOMIC); -	if (!skb) { -		priv->rx_skb[index] = NULL; -		return -ENOMEM; -	} - -	priv->rx_skb[index] = skb; -	rxbd = &priv->rx_bd_vbase[index]; - -	paddr = pci_map_single(priv->pdev, skb->data, -			       SKB_BUF_SIZE, PCI_DMA_FROMDEVICE); -	if (pci_dma_mapping_error(priv->pdev, paddr)) { -		pr_err("skb DMA mapping error: %pad\n", &paddr); -		return -ENOMEM; -	} - -	/* keep rx skb paddrs in rx buffer descriptors for cleanup purposes */ -	rxbd->addr = cpu_to_le32(QTN_HOST_LO32(paddr)); -	rxbd->addr_h = cpu_to_le32(QTN_HOST_HI32(paddr)); -	rxbd->info = 0x0; - -	priv->rx_bd_w_index = index; - -	/* sync up all descriptor updates */ -	wmb(); - -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -	writel(QTN_HOST_HI32(paddr), -	       PCIE_HDP_HHBM_BUF_PTR_H(priv->pcie_reg_base)); -#endif -	writel(QTN_HOST_LO32(paddr), -	       PCIE_HDP_HHBM_BUF_PTR(priv->pcie_reg_base)); - -	writel(index, PCIE_HDP_TX_HOST_Q_WR_PTR(priv->pcie_reg_base)); -	return 0; -} - -static int alloc_rx_buffers(struct qtnf_pcie_bus_priv *priv) -{ -	u16 i; -	int ret = 0; - -	memset(priv->rx_bd_vbase, 0x0, -	       priv->rx_bd_num * sizeof(struct qtnf_rx_bd)); - -	for (i = 0; i < priv->rx_bd_num; i++) { -		ret = skb2rbd_attach(priv, i); -		if (ret) -			break; -	} - -	return ret; -} - -/* all rx/tx activity should have ceased before calling this function */ -static void qtnf_free_xfer_buffers(struct qtnf_pcie_bus_priv *priv) -{ -	struct qtnf_tx_bd *txbd; -	struct qtnf_rx_bd *rxbd; -	struct sk_buff *skb; -	dma_addr_t paddr; -	int i; - -	/* free rx buffers */ -	for (i = 0; i < priv->rx_bd_num; i++) { -		if (priv->rx_skb && priv->rx_skb[i]) { -			rxbd = &priv->rx_bd_vbase[i]; -			skb = priv->rx_skb[i]; -			paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h), -					      le32_to_cpu(rxbd->addr)); -			pci_unmap_single(priv->pdev, paddr, SKB_BUF_SIZE, -					 PCI_DMA_FROMDEVICE); -			dev_kfree_skb_any(skb); -			priv->rx_skb[i] = NULL; -		} -	} - -	/* free tx buffers */ -	for (i = 0; i < priv->tx_bd_num; i++) { -		if (priv->tx_skb && priv->tx_skb[i]) { -			txbd = &priv->tx_bd_vbase[i]; -			skb = priv->tx_skb[i]; -			paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h), -					      le32_to_cpu(txbd->addr)); -			pci_unmap_single(priv->pdev, paddr, skb->len, -					 PCI_DMA_TODEVICE); -			dev_kfree_skb_any(skb); -			priv->tx_skb[i] = NULL; -		} -	} -} - -static int qtnf_hhbm_init(struct qtnf_pcie_bus_priv *priv) -{ -	u32 val; - -	val = readl(PCIE_HHBM_CONFIG(priv->pcie_reg_base)); -	val |= HHBM_CONFIG_SOFT_RESET; -	writel(val, PCIE_HHBM_CONFIG(priv->pcie_reg_base)); -	usleep_range(50, 100); -	val &= ~HHBM_CONFIG_SOFT_RESET; -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -	val |= HHBM_64BIT; -#endif -	writel(val, PCIE_HHBM_CONFIG(priv->pcie_reg_base)); -	writel(priv->rx_bd_num, PCIE_HHBM_Q_LIMIT_REG(priv->pcie_reg_base)); - -	return 0; -} - -static int qtnf_pcie_init_xfer(struct qtnf_pcie_bus_priv *priv) -{ -	int ret; -	u32 val; - -	priv->tx_bd_num = tx_bd_size_param; -	priv->rx_bd_num = rx_bd_size_param; -	priv->rx_bd_w_index = 0; -	priv->rx_bd_r_index = 0; - -	if (!priv->tx_bd_num || !is_power_of_2(priv->tx_bd_num)) { -		pr_err("tx_bd_size_param %u is not power of two\n", -		       priv->tx_bd_num); -		return -EINVAL; -	} - -	val = priv->tx_bd_num * sizeof(struct qtnf_tx_bd); -	if (val > PCIE_HHBM_MAX_SIZE) { -		pr_err("tx_bd_size_param %u is too large\n", -		       priv->tx_bd_num); -		return -EINVAL; -	} - -	if (!priv->rx_bd_num || !is_power_of_2(priv->rx_bd_num)) { -		pr_err("rx_bd_size_param %u is not power of two\n", -		       priv->rx_bd_num); -		return -EINVAL; -	} - -	val = priv->rx_bd_num * sizeof(dma_addr_t); -	if (val > PCIE_HHBM_MAX_SIZE) { -		pr_err("rx_bd_size_param %u is too large\n", -		       priv->rx_bd_num); -		return -EINVAL; -	} - -	ret = qtnf_hhbm_init(priv); -	if (ret) { -		pr_err("failed to init h/w queues\n"); -		return ret; -	} - -	ret = alloc_skb_array(priv); -	if (ret) { -		pr_err("failed to allocate skb array\n"); -		return ret; -	} - -	ret = alloc_bd_table(priv); -	if (ret) { -		pr_err("failed to allocate bd table\n"); -		return ret; -	} - -	ret = alloc_rx_buffers(priv); -	if (ret) { -		pr_err("failed to allocate rx buffers\n"); -		return ret; -	} - -	return ret; -} - -static void qtnf_pcie_data_tx_reclaim(struct qtnf_pcie_bus_priv *priv) -{ -	struct qtnf_tx_bd *txbd; -	struct sk_buff *skb; -	unsigned long flags; -	dma_addr_t paddr; -	u32 tx_done_index; -	int count = 0; -	int i; - -	spin_lock_irqsave(&priv->tx_reclaim_lock, flags); - -	tx_done_index = readl(PCIE_HDP_RX0DMA_CNT(priv->pcie_reg_base)) -			& (priv->tx_bd_num - 1); - -	i = priv->tx_bd_r_index; - -	while (CIRC_CNT(tx_done_index, i, priv->tx_bd_num)) { -		skb = priv->tx_skb[i]; -		if (likely(skb)) { -			txbd = &priv->tx_bd_vbase[i]; -			paddr = QTN_HOST_ADDR(le32_to_cpu(txbd->addr_h), -					      le32_to_cpu(txbd->addr)); -			pci_unmap_single(priv->pdev, paddr, skb->len, -					 PCI_DMA_TODEVICE); - -			if (skb->dev) { -				qtnf_update_tx_stats(skb->dev, skb); -				if (unlikely(priv->tx_stopped)) { -					qtnf_wake_all_queues(skb->dev); -					priv->tx_stopped = 0; -				} -			} - -			dev_kfree_skb_any(skb); -		} - -		priv->tx_skb[i] = NULL; -		count++; - -		if (++i >= priv->tx_bd_num) -			i = 0; -	} - -	priv->tx_reclaim_done += count; -	priv->tx_reclaim_req++; -	priv->tx_bd_r_index = i; - -	spin_unlock_irqrestore(&priv->tx_reclaim_lock, flags); -} - -static int qtnf_tx_queue_ready(struct qtnf_pcie_bus_priv *priv) -{ -	if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index, -			priv->tx_bd_num)) { -		qtnf_pcie_data_tx_reclaim(priv); - -		if (!CIRC_SPACE(priv->tx_bd_w_index, priv->tx_bd_r_index, -				priv->tx_bd_num)) { -			pr_warn_ratelimited("reclaim full Tx queue\n"); -			priv->tx_full_count++; -			return 0; -		} -	} - -	return 1; -} - -static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) -{ -	struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); -	dma_addr_t txbd_paddr, skb_paddr; -	struct qtnf_tx_bd *txbd; -	unsigned long flags; -	int len, i; -	u32 info; -	int ret = 0; - -	spin_lock_irqsave(&priv->tx0_lock, flags); - -	if (!qtnf_tx_queue_ready(priv)) { -		if (skb->dev) { -			netif_tx_stop_all_queues(skb->dev); -			priv->tx_stopped = 1; -		} - -		spin_unlock_irqrestore(&priv->tx0_lock, flags); -		return NETDEV_TX_BUSY; -	} - -	i = priv->tx_bd_w_index; -	priv->tx_skb[i] = skb; -	len = skb->len; - -	skb_paddr = pci_map_single(priv->pdev, skb->data, -				   skb->len, PCI_DMA_TODEVICE); -	if (pci_dma_mapping_error(priv->pdev, skb_paddr)) { -		pr_err("skb DMA mapping error: %pad\n", &skb_paddr); -		ret = -ENOMEM; -		goto tx_done; -	} - -	txbd = &priv->tx_bd_vbase[i]; -	txbd->addr = cpu_to_le32(QTN_HOST_LO32(skb_paddr)); -	txbd->addr_h = cpu_to_le32(QTN_HOST_HI32(skb_paddr)); - -	info = (len & QTN_PCIE_TX_DESC_LEN_MASK) << QTN_PCIE_TX_DESC_LEN_SHIFT; -	txbd->info = cpu_to_le32(info); - -	/* sync up all descriptor updates before passing them to EP */ -	dma_wmb(); - -	/* write new TX descriptor to PCIE_RX_FIFO on EP */ -	txbd_paddr = priv->tx_bd_pbase + i * sizeof(struct qtnf_tx_bd); - -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -	writel(QTN_HOST_HI32(txbd_paddr), -	       PCIE_HDP_HOST_WR_DESC0_H(priv->pcie_reg_base)); -#endif -	writel(QTN_HOST_LO32(txbd_paddr), -	       PCIE_HDP_HOST_WR_DESC0(priv->pcie_reg_base)); - -	if (++i >= priv->tx_bd_num) -		i = 0; - -	priv->tx_bd_w_index = i; - -tx_done: -	if (ret && skb) { -		pr_err_ratelimited("drop skb\n"); -		if (skb->dev) -			skb->dev->stats.tx_dropped++; -		dev_kfree_skb_any(skb); -	} - -	priv->tx_done_count++; -	spin_unlock_irqrestore(&priv->tx0_lock, flags); - -	qtnf_pcie_data_tx_reclaim(priv); - -	return NETDEV_TX_OK; -} - -static int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb) -{ -	struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); -	int ret; - -	ret = qtnf_shm_ipc_send(&priv->shm_ipc_ep_in, skb->data, skb->len); - -	if (ret == -ETIMEDOUT) { -		pr_err("EP firmware is dead\n"); -		bus->fw_state = QTNF_FW_STATE_EP_DEAD; -	} - -	return ret; -} - -static irqreturn_t qtnf_interrupt(int irq, void *data) -{ -	struct qtnf_bus *bus = (struct qtnf_bus *)data; -	struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); -	u32 status; - -	priv->pcie_irq_count++; -	status = readl(PCIE_HDP_INT_STATUS(priv->pcie_reg_base)); - -	qtnf_shm_ipc_irq_handler(&priv->shm_ipc_ep_in); -	qtnf_shm_ipc_irq_handler(&priv->shm_ipc_ep_out); - -	if (!(status & priv->pcie_irq_mask)) -		goto irq_done; - -	if (status & PCIE_HDP_INT_RX_BITS) -		priv->pcie_irq_rx_count++; - -	if (status & PCIE_HDP_INT_TX_BITS) -		priv->pcie_irq_tx_count++; - -	if (status & PCIE_HDP_INT_HHBM_UF) -		priv->pcie_irq_uf_count++; - -	if (status & PCIE_HDP_INT_RX_BITS) { -		qtnf_dis_rxdone_irq(priv); -		napi_schedule(&bus->mux_napi); -	} - -	if (status & PCIE_HDP_INT_TX_BITS) { -		qtnf_dis_txdone_irq(priv); -		tasklet_hi_schedule(&priv->reclaim_tq); -	} - -irq_done: -	/* H/W workaround: clean all bits, not only enabled */ -	qtnf_non_posted_write(~0U, PCIE_HDP_INT_STATUS(priv->pcie_reg_base)); - -	if (!priv->msi_enabled) -		qtnf_deassert_intx(priv); - -	return IRQ_HANDLED; -} - -static int qtnf_rx_data_ready(struct qtnf_pcie_bus_priv *priv) -{ -	u16 index = priv->rx_bd_r_index; -	struct qtnf_rx_bd *rxbd; -	u32 descw; - -	rxbd = &priv->rx_bd_vbase[index]; -	descw = le32_to_cpu(rxbd->info); - -	if (descw & QTN_TXDONE_MASK) -		return 1; - -	return 0; -} - -static int qtnf_rx_poll(struct napi_struct *napi, int budget) -{ -	struct qtnf_bus *bus = container_of(napi, struct qtnf_bus, mux_napi); -	struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); -	struct net_device *ndev = NULL; -	struct sk_buff *skb = NULL; -	int processed = 0; -	struct qtnf_rx_bd *rxbd; -	dma_addr_t skb_paddr; -	int consume; -	u32 descw; -	u32 psize; -	u16 r_idx; -	u16 w_idx; -	int ret; - -	while (processed < budget) { - - -		if (!qtnf_rx_data_ready(priv)) -			goto rx_out; - -		r_idx = priv->rx_bd_r_index; -		rxbd = &priv->rx_bd_vbase[r_idx]; -		descw = le32_to_cpu(rxbd->info); - -		skb = priv->rx_skb[r_idx]; -		psize = QTN_GET_LEN(descw); -		consume = 1; - -		if (!(descw & QTN_TXDONE_MASK)) { -			pr_warn("skip invalid rxbd[%d]\n", r_idx); -			consume = 0; -		} - -		if (!skb) { -			pr_warn("skip missing rx_skb[%d]\n", r_idx); -			consume = 0; -		} - -		if (skb && (skb_tailroom(skb) <  psize)) { -			pr_err("skip packet with invalid length: %u > %u\n", -			       psize, skb_tailroom(skb)); -			consume = 0; -		} - -		if (skb) { -			skb_paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h), -						  le32_to_cpu(rxbd->addr)); -			pci_unmap_single(priv->pdev, skb_paddr, SKB_BUF_SIZE, -					 PCI_DMA_FROMDEVICE); -		} - -		if (consume) { -			skb_put(skb, psize); -			ndev = qtnf_classify_skb(bus, skb); -			if (likely(ndev)) { -				qtnf_update_rx_stats(ndev, skb); -				skb->protocol = eth_type_trans(skb, ndev); -				napi_gro_receive(napi, skb); -			} else { -				pr_debug("drop untagged skb\n"); -				bus->mux_dev.stats.rx_dropped++; -				dev_kfree_skb_any(skb); -			} -		} else { -			if (skb) { -				bus->mux_dev.stats.rx_dropped++; -				dev_kfree_skb_any(skb); -			} -		} - -		priv->rx_skb[r_idx] = NULL; -		if (++r_idx >= priv->rx_bd_num) -			r_idx = 0; - -		priv->rx_bd_r_index = r_idx; - -		/* repalce processed buffer by a new one */ -		w_idx = priv->rx_bd_w_index; -		while (CIRC_SPACE(priv->rx_bd_w_index, priv->rx_bd_r_index, -				  priv->rx_bd_num) > 0) { -			if (++w_idx >= priv->rx_bd_num) -				w_idx = 0; - -			ret = skb2rbd_attach(priv, w_idx); -			if (ret) { -				pr_err("failed to allocate new rx_skb[%d]\n", -				       w_idx); -				break; -			} -		} - -		processed++; -	} - -rx_out: -	if (processed < budget) { -		napi_complete(napi); -		qtnf_en_rxdone_irq(priv); -	} - -	return processed; -} - -static void -qtnf_pcie_data_tx_timeout(struct qtnf_bus *bus, struct net_device *ndev) -{ -	struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); - -	tasklet_hi_schedule(&priv->reclaim_tq); -} - -static void qtnf_pcie_data_rx_start(struct qtnf_bus *bus) -{ -	struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); - -	qtnf_enable_hdp_irqs(priv); -	napi_enable(&bus->mux_napi); -} - -static void qtnf_pcie_data_rx_stop(struct qtnf_bus *bus) -{ -	struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); - -	napi_disable(&bus->mux_napi); -	qtnf_disable_hdp_irqs(priv); -} - -static const struct qtnf_bus_ops qtnf_pcie_bus_ops = { -	/* control path methods */ -	.control_tx	= qtnf_pcie_control_tx, - -	/* data path methods */ -	.data_tx		= qtnf_pcie_data_tx, -	.data_tx_timeout	= qtnf_pcie_data_tx_timeout, -	.data_rx_start		= qtnf_pcie_data_rx_start, -	.data_rx_stop		= qtnf_pcie_data_rx_stop, -}; - -static int qtnf_dbg_mps_show(struct seq_file *s, void *data) -{ -	struct qtnf_bus *bus = dev_get_drvdata(s->private); -	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); - -	seq_printf(s, "%d\n", priv->mps); - -	return 0; -} - -static int qtnf_dbg_msi_show(struct seq_file *s, void *data) -{ -	struct qtnf_bus *bus = dev_get_drvdata(s->private); -	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); - -	seq_printf(s, "%u\n", priv->msi_enabled); - -	return 0; -} - -static int qtnf_dbg_irq_stats(struct seq_file *s, void *data) -{ -	struct qtnf_bus *bus = dev_get_drvdata(s->private); -	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); -	u32 reg = readl(PCIE_HDP_INT_EN(priv->pcie_reg_base)); -	u32 status; - -	seq_printf(s, "pcie_irq_count(%u)\n", priv->pcie_irq_count); -	seq_printf(s, "pcie_irq_tx_count(%u)\n", priv->pcie_irq_tx_count); -	status = reg &  PCIE_HDP_INT_TX_BITS; -	seq_printf(s, "pcie_irq_tx_status(%s)\n", -		   (status == PCIE_HDP_INT_TX_BITS) ? "EN" : "DIS"); -	seq_printf(s, "pcie_irq_rx_count(%u)\n", priv->pcie_irq_rx_count); -	status = reg &  PCIE_HDP_INT_RX_BITS; -	seq_printf(s, "pcie_irq_rx_status(%s)\n", -		   (status == PCIE_HDP_INT_RX_BITS) ? "EN" : "DIS"); -	seq_printf(s, "pcie_irq_uf_count(%u)\n", priv->pcie_irq_uf_count); -	status = reg &  PCIE_HDP_INT_HHBM_UF; -	seq_printf(s, "pcie_irq_hhbm_uf_status(%s)\n", -		   (status == PCIE_HDP_INT_HHBM_UF) ? "EN" : "DIS"); - -	return 0; -} - -static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data) -{ -	struct qtnf_bus *bus = dev_get_drvdata(s->private); -	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); - -	seq_printf(s, "tx_full_count(%u)\n", priv->tx_full_count); -	seq_printf(s, "tx_done_count(%u)\n", priv->tx_done_count); -	seq_printf(s, "tx_reclaim_done(%u)\n", priv->tx_reclaim_done); -	seq_printf(s, "tx_reclaim_req(%u)\n", priv->tx_reclaim_req); - -	seq_printf(s, "tx_bd_r_index(%u)\n", priv->tx_bd_r_index); -	seq_printf(s, "tx_bd_p_index(%u)\n", -		   readl(PCIE_HDP_RX0DMA_CNT(priv->pcie_reg_base)) -			& (priv->tx_bd_num - 1)); -	seq_printf(s, "tx_bd_w_index(%u)\n", priv->tx_bd_w_index); -	seq_printf(s, "tx queue len(%u)\n", -		   CIRC_CNT(priv->tx_bd_w_index, priv->tx_bd_r_index, -			    priv->tx_bd_num)); - -	seq_printf(s, "rx_bd_r_index(%u)\n", priv->rx_bd_r_index); -	seq_printf(s, "rx_bd_p_index(%u)\n", -		   readl(PCIE_HDP_TX0DMA_CNT(priv->pcie_reg_base)) -			& (priv->rx_bd_num - 1)); -	seq_printf(s, "rx_bd_w_index(%u)\n", priv->rx_bd_w_index); -	seq_printf(s, "rx alloc queue len(%u)\n", -		   CIRC_SPACE(priv->rx_bd_w_index, priv->rx_bd_r_index, -			      priv->rx_bd_num)); - -	return 0; -} - -static int qtnf_dbg_shm_stats(struct seq_file *s, void *data) -{ -	struct qtnf_bus *bus = dev_get_drvdata(s->private); -	struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); - -	seq_printf(s, "shm_ipc_ep_in.tx_packet_count(%zu)\n", -		   priv->shm_ipc_ep_in.tx_packet_count); -	seq_printf(s, "shm_ipc_ep_in.rx_packet_count(%zu)\n", -		   priv->shm_ipc_ep_in.rx_packet_count); -	seq_printf(s, "shm_ipc_ep_out.tx_packet_count(%zu)\n", -		   priv->shm_ipc_ep_out.tx_timeout_count); -	seq_printf(s, "shm_ipc_ep_out.rx_packet_count(%zu)\n", -		   priv->shm_ipc_ep_out.rx_packet_count); - -	return 0; -} - -static int qtnf_ep_fw_send(struct qtnf_pcie_bus_priv *priv, uint32_t size, -			   int blk, const u8 *pblk, const u8 *fw) -{ -	struct pci_dev *pdev = priv->pdev; -	struct qtnf_bus *bus = pci_get_drvdata(pdev); - -	struct qtnf_pcie_fw_hdr *hdr; -	u8 *pdata; - -	int hds = sizeof(*hdr); -	struct sk_buff *skb = NULL; -	int len = 0; -	int ret; - -	skb = __dev_alloc_skb(QTN_PCIE_FW_BUFSZ, GFP_KERNEL); -	if (!skb) -		return -ENOMEM; - -	skb->len = QTN_PCIE_FW_BUFSZ; -	skb->dev = NULL; - -	hdr = (struct qtnf_pcie_fw_hdr *)skb->data; -	memcpy(hdr->boardflg, QTN_PCIE_BOARDFLG, strlen(QTN_PCIE_BOARDFLG)); -	hdr->fwsize = cpu_to_le32(size); -	hdr->seqnum = cpu_to_le32(blk); - -	if (blk) -		hdr->type = cpu_to_le32(QTN_FW_DSUB); -	else -		hdr->type = cpu_to_le32(QTN_FW_DBEGIN); - -	pdata = skb->data + hds; - -	len = QTN_PCIE_FW_BUFSZ - hds; -	if (pblk >= (fw + size - len)) { -		len = fw + size - pblk; -		hdr->type = cpu_to_le32(QTN_FW_DEND); -	} - -	hdr->pktlen = cpu_to_le32(len); -	memcpy(pdata, pblk, len); -	hdr->crc = cpu_to_le32(~crc32(0, pdata, len)); - -	ret = qtnf_pcie_data_tx(bus, skb); - -	return (ret == NETDEV_TX_OK) ? len : 0; -} - -static int -qtnf_ep_fw_load(struct qtnf_pcie_bus_priv *priv, const u8 *fw, u32 fw_size) -{ -	int blk_size = QTN_PCIE_FW_BUFSZ - sizeof(struct qtnf_pcie_fw_hdr); -	int blk_count = fw_size / blk_size + ((fw_size % blk_size) ? 1 : 0); -	const u8 *pblk = fw; -	int threshold = 0; -	int blk = 0; -	int len; - -	pr_debug("FW upload started: fw_addr=0x%p size=%d\n", fw, fw_size); - -	while (blk < blk_count) { -		if (++threshold > 10000) { -			pr_err("FW upload failed: too many retries\n"); -			return -ETIMEDOUT; -		} - -		len = qtnf_ep_fw_send(priv, fw_size, blk, pblk, fw); -		if (len <= 0) -			continue; - -		if (!((blk + 1) & QTN_PCIE_FW_DLMASK) || -		    (blk == (blk_count - 1))) { -			qtnf_set_state(&priv->bda->bda_rc_state, -				       QTN_RC_FW_SYNC); -			if (qtnf_poll_state(&priv->bda->bda_ep_state, -					    QTN_EP_FW_SYNC, -					    QTN_FW_DL_TIMEOUT_MS)) { -				pr_err("FW upload failed: SYNC timed out\n"); -				return -ETIMEDOUT; -			} - -			qtnf_clear_state(&priv->bda->bda_ep_state, -					 QTN_EP_FW_SYNC); - -			if (qtnf_is_state(&priv->bda->bda_ep_state, -					  QTN_EP_FW_RETRY)) { -				if (blk == (blk_count - 1)) { -					int last_round = -						blk_count & QTN_PCIE_FW_DLMASK; -					blk -= last_round; -					pblk -= ((last_round - 1) * -						blk_size + len); -				} else { -					blk -= QTN_PCIE_FW_DLMASK; -					pblk -= QTN_PCIE_FW_DLMASK * blk_size; -				} - -				qtnf_clear_state(&priv->bda->bda_ep_state, -						 QTN_EP_FW_RETRY); - -				pr_warn("FW upload retry: block #%d\n", blk); -				continue; -			} - -			qtnf_pcie_data_tx_reclaim(priv); -		} - -		pblk += len; -		blk++; -	} - -	pr_debug("FW upload completed: totally sent %d blocks\n", blk); -	return 0; -} - -static void qtnf_fw_work_handler(struct work_struct *work) -{ -	struct qtnf_bus *bus = container_of(work, struct qtnf_bus, fw_work); -	struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); -	struct pci_dev *pdev = priv->pdev; -	const struct firmware *fw; -	int ret; -	u32 state = QTN_RC_FW_LOADRDY | QTN_RC_FW_QLINK; - -	if (flashboot) { -		state |= QTN_RC_FW_FLASHBOOT; -	} else { -		ret = request_firmware(&fw, bus->fwname, &pdev->dev); -		if (ret < 0) { -			pr_err("failed to get firmware %s\n", bus->fwname); -			goto fw_load_fail; -		} -	} - -	qtnf_set_state(&priv->bda->bda_rc_state, state); - -	if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_LOADRDY, -			    QTN_FW_DL_TIMEOUT_MS)) { -		pr_err("card is not ready\n"); - -		if (!flashboot) -			release_firmware(fw); - -		goto fw_load_fail; -	} - -	qtnf_clear_state(&priv->bda->bda_ep_state, QTN_EP_FW_LOADRDY); - -	if (flashboot) { -		pr_info("booting firmware from flash\n"); -	} else { -		pr_info("starting firmware upload: %s\n", bus->fwname); - -		ret = qtnf_ep_fw_load(priv, fw->data, fw->size); -		release_firmware(fw); -		if (ret) { -			pr_err("firmware upload error\n"); -			goto fw_load_fail; -		} -	} - -	if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_DONE, -			    QTN_FW_DL_TIMEOUT_MS)) { -		pr_err("firmware bringup timed out\n"); -		goto fw_load_fail; -	} - -	bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE; -	pr_info("firmware is up and running\n"); - -	if (qtnf_poll_state(&priv->bda->bda_ep_state, -			    QTN_EP_FW_QLINK_DONE, QTN_FW_QLINK_TIMEOUT_MS)) { -		pr_err("firmware runtime failure\n"); -		goto fw_load_fail; -	} - -	ret = qtnf_core_attach(bus); -	if (ret) { -		pr_err("failed to attach core\n"); -		goto fw_load_fail; -	} - -	qtnf_debugfs_init(bus, DRV_NAME); -	qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show); -	qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show); -	qtnf_debugfs_add_entry(bus, "hdp_stats", qtnf_dbg_hdp_stats); -	qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats); -	qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats); - -	goto fw_load_exit; - -fw_load_fail: -	bus->fw_state = QTNF_FW_STATE_DETACHED; - -fw_load_exit: -	complete(&bus->firmware_init_complete); -	put_device(&pdev->dev); -} - -static void qtnf_bringup_fw_async(struct qtnf_bus *bus) -{ -	struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); -	struct pci_dev *pdev = priv->pdev; - -	get_device(&pdev->dev); -	INIT_WORK(&bus->fw_work, qtnf_fw_work_handler); -	schedule_work(&bus->fw_work); -} - -static void qtnf_reclaim_tasklet_fn(unsigned long data) -{ -	struct qtnf_pcie_bus_priv *priv = (void *)data; - -	qtnf_pcie_data_tx_reclaim(priv); -	qtnf_en_txdone_irq(priv); -} - -static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ -	struct qtnf_pcie_bus_priv *pcie_priv; -	struct qtnf_bus *bus; -	int ret; - -	bus = devm_kzalloc(&pdev->dev, -			   sizeof(*bus) + sizeof(*pcie_priv), GFP_KERNEL); -	if (!bus) -		return -ENOMEM; - -	pcie_priv = get_bus_priv(bus); - -	pci_set_drvdata(pdev, bus); -	bus->bus_ops = &qtnf_pcie_bus_ops; -	bus->dev = &pdev->dev; -	bus->fw_state = QTNF_FW_STATE_RESET; -	pcie_priv->pdev = pdev; - -	strcpy(bus->fwname, QTN_PCI_PEARL_FW_NAME); -	init_completion(&bus->firmware_init_complete); -	mutex_init(&bus->bus_lock); -	spin_lock_init(&pcie_priv->tx0_lock); -	spin_lock_init(&pcie_priv->irq_lock); -	spin_lock_init(&pcie_priv->tx_reclaim_lock); - -	/* init stats */ -	pcie_priv->tx_full_count = 0; -	pcie_priv->tx_done_count = 0; -	pcie_priv->pcie_irq_count = 0; -	pcie_priv->pcie_irq_rx_count = 0; -	pcie_priv->pcie_irq_tx_count = 0; -	pcie_priv->pcie_irq_uf_count = 0; -	pcie_priv->tx_reclaim_done = 0; -	pcie_priv->tx_reclaim_req = 0; - -	tasklet_init(&pcie_priv->reclaim_tq, qtnf_reclaim_tasklet_fn, -		     (unsigned long)pcie_priv); - -	init_dummy_netdev(&bus->mux_dev); -	netif_napi_add(&bus->mux_dev, &bus->mux_napi, -		       qtnf_rx_poll, 10); - -	pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PEARL_PCIE"); -	if (!pcie_priv->workqueue) { -		pr_err("failed to alloc bus workqueue\n"); -		ret = -ENODEV; -		goto err_init; -	} - -	if (!pci_is_pcie(pdev)) { -		pr_err("device %s is not PCI Express\n", pci_name(pdev)); -		ret = -EIO; -		goto err_base; -	} - -	qtnf_tune_pcie_mps(pcie_priv); - -	ret = pcim_enable_device(pdev); -	if (ret) { -		pr_err("failed to init PCI device %x\n", pdev->device); -		goto err_base; -	} else { -		pr_debug("successful init of PCI device %x\n", pdev->device); -	} - -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); -#else -	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); -#endif -	if (ret) { -		pr_err("PCIE DMA coherent mask init failed\n"); -		goto err_base; -	} - -	pci_set_master(pdev); -	qtnf_pcie_init_irq(pcie_priv); - -	ret = qtnf_pcie_init_memory(pcie_priv); -	if (ret < 0) { -		pr_err("PCIE memory init failed\n"); -		goto err_base; -	} - -	pci_save_state(pdev); - -	ret = qtnf_pcie_init_shm_ipc(pcie_priv); -	if (ret < 0) { -		pr_err("PCIE SHM IPC init failed\n"); -		goto err_base; -	} - -	ret = qtnf_pcie_init_xfer(pcie_priv); -	if (ret) { -		pr_err("PCIE xfer init failed\n"); -		goto err_ipc; -	} - -	/* init default irq settings */ -	qtnf_init_hdp_irqs(pcie_priv); - -	/* start with disabled irqs */ -	qtnf_disable_hdp_irqs(pcie_priv); - -	ret = devm_request_irq(&pdev->dev, pdev->irq, &qtnf_interrupt, 0, -			       "qtnf_pcie_irq", (void *)bus); -	if (ret) { -		pr_err("failed to request pcie irq %d\n", pdev->irq); -		goto err_xfer; -	} - -	qtnf_bringup_fw_async(bus); - -	return 0; - -err_xfer: -	qtnf_free_xfer_buffers(pcie_priv); - -err_ipc: -	qtnf_pcie_free_shm_ipc(pcie_priv); - -err_base: -	flush_workqueue(pcie_priv->workqueue); -	destroy_workqueue(pcie_priv->workqueue); -	netif_napi_del(&bus->mux_napi); - -err_init: -	tasklet_kill(&pcie_priv->reclaim_tq); -	pci_set_drvdata(pdev, NULL); - -	return ret; -} - -static void qtnf_pcie_remove(struct pci_dev *pdev) -{ -	struct qtnf_pcie_bus_priv *priv; -	struct qtnf_bus *bus; - -	bus = pci_get_drvdata(pdev); -	if (!bus) -		return; - -	wait_for_completion(&bus->firmware_init_complete); - -	if (bus->fw_state == QTNF_FW_STATE_ACTIVE || -	    bus->fw_state == QTNF_FW_STATE_EP_DEAD) -		qtnf_core_detach(bus); - -	priv = get_bus_priv(bus); - -	netif_napi_del(&bus->mux_napi); -	flush_workqueue(priv->workqueue); -	destroy_workqueue(priv->workqueue); -	tasklet_kill(&priv->reclaim_tq); - -	qtnf_free_xfer_buffers(priv); -	qtnf_debugfs_remove(bus); - -	qtnf_pcie_free_shm_ipc(priv); -	qtnf_reset_card(priv); -} - -#ifdef CONFIG_PM_SLEEP -static int qtnf_pcie_suspend(struct device *dev) -{ -	return -EOPNOTSUPP; -} - -static int qtnf_pcie_resume(struct device *dev) -{ -	return 0; -} -#endif /* CONFIG_PM_SLEEP */ - -#ifdef CONFIG_PM_SLEEP -/* Power Management Hooks */ -static SIMPLE_DEV_PM_OPS(qtnf_pcie_pm_ops, qtnf_pcie_suspend, -			 qtnf_pcie_resume); -#endif - -static const struct pci_device_id qtnf_pcie_devid_table[] = { -	{ -		PCIE_VENDOR_ID_QUANTENNA, PCIE_DEVICE_ID_QTN_PEARL, -		PCI_ANY_ID, PCI_ANY_ID, 0, 0, -	}, -	{ }, -}; - -MODULE_DEVICE_TABLE(pci, qtnf_pcie_devid_table); - -static struct pci_driver qtnf_pcie_drv_data = { -	.name = DRV_NAME, -	.id_table = qtnf_pcie_devid_table, -	.probe = qtnf_pcie_probe, -	.remove = qtnf_pcie_remove, -#ifdef CONFIG_PM_SLEEP -	.driver = { -		.pm = &qtnf_pcie_pm_ops, -	}, -#endif -}; - -static int __init qtnf_pcie_register(void) -{ -	pr_info("register Quantenna QSR10g FullMAC PCIE driver\n"); -	return pci_register_driver(&qtnf_pcie_drv_data); -} - -static void __exit qtnf_pcie_exit(void) -{ -	pr_info("unregister Quantenna QSR10g FullMAC PCIE driver\n"); -	pci_unregister_driver(&qtnf_pcie_drv_data); -} - -module_init(qtnf_pcie_register); -module_exit(qtnf_pcie_exit); - -MODULE_AUTHOR("Quantenna Communications"); -MODULE_DESCRIPTION("Quantenna QSR10g PCIe bus driver for 802.11 wireless LAN."); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h deleted file mode 100644 index 397875a50fc2..000000000000 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_bus_priv.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2015-2016 Quantenna Communications, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - */ - -#ifndef _QTN_FMAC_PCIE_H_ -#define _QTN_FMAC_PCIE_H_ - -#include <linux/dma-mapping.h> -#include <linux/io.h> - -#include "pcie_regs_pearl.h" -#include "pcie_ipc.h" -#include "shm_ipc.h" - -struct bus; - -struct qtnf_pcie_bus_priv { -	struct pci_dev  *pdev; - -	/* lock for irq configuration changes */ -	spinlock_t irq_lock; - -	/* lock for tx reclaim operations */ -	spinlock_t tx_reclaim_lock; -	/* lock for tx0 operations */ -	spinlock_t tx0_lock; -	u8 msi_enabled; -	u8 tx_stopped; -	int mps; - -	struct workqueue_struct *workqueue; -	struct tasklet_struct reclaim_tq; - -	void __iomem *sysctl_bar; -	void __iomem *epmem_bar; -	void __iomem *dmareg_bar; - -	struct qtnf_shm_ipc shm_ipc_ep_in; -	struct qtnf_shm_ipc shm_ipc_ep_out; - -	struct qtnf_pcie_bda __iomem *bda; -	void __iomem *pcie_reg_base; - -	u16 tx_bd_num; -	u16 rx_bd_num; - -	struct sk_buff **tx_skb; -	struct sk_buff **rx_skb; - -	struct qtnf_tx_bd *tx_bd_vbase; -	dma_addr_t tx_bd_pbase; - -	struct qtnf_rx_bd *rx_bd_vbase; -	dma_addr_t rx_bd_pbase; - -	dma_addr_t bd_table_paddr; -	void *bd_table_vaddr; -	u32 bd_table_len; - -	u32 rx_bd_w_index; -	u32 rx_bd_r_index; - -	u32 tx_bd_w_index; -	u32 tx_bd_r_index; - -	u32 pcie_irq_mask; - -	/* diagnostics stats */ -	u32 pcie_irq_count; -	u32 pcie_irq_rx_count; -	u32 pcie_irq_tx_count; -	u32 pcie_irq_uf_count; -	u32 tx_full_count; -	u32 tx_done_count; -	u32 tx_reclaim_done; -	u32 tx_reclaim_req; -}; - -#endif /* _QTN_FMAC_PCIE_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h b/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h deleted file mode 100644 index 0bfe285b6b48..000000000000 --- a/drivers/net/wireless/quantenna/qtnfmac/pearl/pcie_regs_pearl.h +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright (c) 2015 Quantenna Communications, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - */ - -#ifndef __PEARL_PCIE_H -#define __PEARL_PCIE_H - -#define	PCIE_GEN2_BASE				(0xe9000000) -#define	PCIE_GEN3_BASE				(0xe7000000) - -#define PEARL_CUR_PCIE_BASE			(PCIE_GEN2_BASE) -#define PCIE_HDP_OFFSET				(0x2000) - -#define PCIE_HDP_CTRL(base)			((base) + 0x2c00) -#define PCIE_HDP_AXI_CTRL(base)			((base) + 0x2c04) -#define PCIE_HDP_HOST_WR_DESC0(base)		((base) + 0x2c10) -#define PCIE_HDP_HOST_WR_DESC0_H(base)		((base) + 0x2c14) -#define PCIE_HDP_HOST_WR_DESC1(base)		((base) + 0x2c18) -#define PCIE_HDP_HOST_WR_DESC1_H(base)		((base) + 0x2c1c) -#define PCIE_HDP_HOST_WR_DESC2(base)		((base) + 0x2c20) -#define PCIE_HDP_HOST_WR_DESC2_H(base)		((base) + 0x2c24) -#define PCIE_HDP_HOST_WR_DESC3(base)		((base) + 0x2c28) -#define PCIE_HDP_HOST_WR_DESC4_H(base)		((base) + 0x2c2c) -#define PCIE_HDP_RX_INT_CTRL(base)		((base) + 0x2c30) -#define PCIE_HDP_TX_INT_CTRL(base)		((base) + 0x2c34) -#define PCIE_HDP_INT_STATUS(base)		((base) + 0x2c38) -#define PCIE_HDP_INT_EN(base)			((base) + 0x2c3c) -#define PCIE_HDP_RX_DESC0_PTR(base)		((base) + 0x2c40) -#define PCIE_HDP_RX_DESC0_NOE(base)		((base) + 0x2c44) -#define PCIE_HDP_RX_DESC1_PTR(base)		((base) + 0x2c48) -#define PCIE_HDP_RX_DESC1_NOE(base)		((base) + 0x2c4c) -#define PCIE_HDP_RX_DESC2_PTR(base)		((base) + 0x2c50) -#define PCIE_HDP_RX_DESC2_NOE(base)		((base) + 0x2c54) -#define PCIE_HDP_RX_DESC3_PTR(base)		((base) + 0x2c58) -#define PCIE_HDP_RX_DESC3_NOE(base)		((base) + 0x2c5c) - -#define PCIE_HDP_TX0_BASE_ADDR(base)		((base) + 0x2c60) -#define PCIE_HDP_TX1_BASE_ADDR(base)		((base) + 0x2c64) -#define PCIE_HDP_TX0_Q_CTRL(base)		((base) + 0x2c70) -#define PCIE_HDP_TX1_Q_CTRL(base)		((base) + 0x2c74) -#define PCIE_HDP_CFG0(base)			((base) + 0x2c80) -#define PCIE_HDP_CFG1(base)			((base) + 0x2c84) -#define PCIE_HDP_CFG2(base)			((base) + 0x2c88) -#define PCIE_HDP_CFG3(base)			((base) + 0x2c8c) -#define PCIE_HDP_CFG4(base)			((base) + 0x2c90) -#define PCIE_HDP_CFG5(base)			((base) + 0x2c94) -#define PCIE_HDP_CFG6(base)			((base) + 0x2c98) -#define PCIE_HDP_CFG7(base)			((base) + 0x2c9c) -#define PCIE_HDP_CFG8(base)			((base) + 0x2ca0) -#define PCIE_HDP_CFG9(base)			((base) + 0x2ca4) -#define PCIE_HDP_CFG10(base)			((base) + 0x2ca8) -#define PCIE_HDP_CFG11(base)			((base) + 0x2cac) -#define PCIE_INT(base)				((base) + 0x2cb0) -#define PCIE_INT_MASK(base)			((base) + 0x2cb4) -#define PCIE_MSI_MASK(base)			((base) + 0x2cb8) -#define PCIE_MSI_PNDG(base)			((base) + 0x2cbc) -#define PCIE_PRI_CFG(base)			((base) + 0x2cc0) -#define PCIE_PHY_CR(base)			((base) + 0x2cc4) -#define PCIE_HDP_CTAG_CTRL(base)		((base) + 0x2cf4) -#define PCIE_HDP_HHBM_BUF_PTR(base)		((base) + 0x2d00) -#define PCIE_HDP_HHBM_BUF_PTR_H(base)		((base) + 0x2d04) -#define PCIE_HDP_HHBM_BUF_FIFO_NOE(base)	((base) + 0x2d04) -#define PCIE_HDP_RX0DMA_CNT(base)		((base) + 0x2d10) -#define PCIE_HDP_RX1DMA_CNT(base)		((base) + 0x2d14) -#define PCIE_HDP_RX2DMA_CNT(base)		((base) + 0x2d18) -#define PCIE_HDP_RX3DMA_CNT(base)		((base) + 0x2d1c) -#define PCIE_HDP_TX0DMA_CNT(base)		((base) + 0x2d20) -#define PCIE_HDP_TX1DMA_CNT(base)		((base) + 0x2d24) -#define PCIE_HDP_RXDMA_CTRL(base)		((base) + 0x2d28) -#define PCIE_HDP_TX_HOST_Q_SZ_CTRL(base)	((base) + 0x2d2c) -#define PCIE_HDP_TX_HOST_Q_BASE_L(base)		((base) + 0x2d30) -#define PCIE_HDP_TX_HOST_Q_BASE_H(base)		((base) + 0x2d34) -#define PCIE_HDP_TX_HOST_Q_WR_PTR(base)		((base) + 0x2d38) -#define PCIE_HDP_TX_HOST_Q_RD_PTR(base)		((base) + 0x2d3c) -#define PCIE_HDP_TX_HOST_Q_STS(base)		((base) + 0x2d40) - -/* Host HBM pool registers */ -#define PCIE_HHBM_CSR_REG(base)			((base) + 0x2e00) -#define PCIE_HHBM_Q_BASE_REG(base)		((base) + 0x2e04) -#define PCIE_HHBM_Q_LIMIT_REG(base)		((base) + 0x2e08) -#define PCIE_HHBM_Q_WR_REG(base)		((base) + 0x2e0c) -#define PCIE_HHBM_Q_RD_REG(base)		((base) + 0x2e10) -#define PCIE_HHBM_POOL_DATA_0_H(base)		((base) + 0x2e90) -#define PCIE_HHBM_CONFIG(base)			((base) + 0x2f9c) -#define PCIE_HHBM_POOL_REQ_0(base)		((base) + 0x2f10) -#define PCIE_HHBM_POOL_DATA_0(base)		((base) + 0x2f40) -#define PCIE_HHBM_WATERMARK_MASKED_INT(base)	((base) + 0x2f68) -#define PCIE_HHBM_WATERMARK_INT(base)		((base) + 0x2f6c) -#define PCIE_HHBM_POOL_WATERMARK(base)		((base) + 0x2f70) -#define PCIE_HHBM_POOL_OVERFLOW_CNT(base)	((base) + 0x2f90) -#define PCIE_HHBM_POOL_UNDERFLOW_CNT(base)	((base) + 0x2f94) -#define HBM_INT_STATUS(base)			((base) + 0x2f9c) -#define PCIE_HHBM_POOL_CNFIG(base)		((base) + 0x2f9c) - -/* host HBM bit field definition */ -#define HHBM_CONFIG_SOFT_RESET			(BIT(8)) -#define HHBM_WR_REQ				(BIT(0)) -#define HHBM_RD_REQ				(BIT(1)) -#define HHBM_DONE				(BIT(31)) -#define HHBM_64BIT				(BIT(10)) - -/* offsets for dual PCIE */ -#define PCIE_PORT_LINK_CTL(base)		((base) + 0x0710) -#define PCIE_GEN2_CTL(base)			((base) + 0x080C) -#define PCIE_GEN3_OFF(base)			((base) + 0x0890) -#define PCIE_ATU_CTRL1(base)			((base) + 0x0904) -#define PCIE_ATU_CTRL2(base)			((base) + 0x0908) -#define PCIE_ATU_BASE_LOW(base)			((base) + 0x090C) -#define PCIE_ATU_BASE_HIGH(base)		((base) + 0x0910) -#define PCIE_ATU_BASE_LIMIT(base)		((base) + 0x0914) -#define PCIE_ATU_TGT_LOW(base)			((base) + 0x0918) -#define PCIE_ATU_TGT_HIGH(base)			((base) + 0x091C) -#define PCIE_DMA_WR_ENABLE(base)		((base) + 0x097C) -#define PCIE_DMA_WR_CHWTLOW(base)		((base) + 0x0988) -#define PCIE_DMA_WR_CHWTHIG(base)		((base) + 0x098C) -#define PCIE_DMA_WR_INTSTS(base)		((base) + 0x09BC) -#define PCIE_DMA_WR_INTMASK(base)		((base) + 0x09C4) -#define PCIE_DMA_WR_INTCLER(base)		((base) + 0x09C8) -#define PCIE_DMA_WR_DONE_IMWR_ADDR_L(base)	((base) + 0x09D0) -#define PCIE_DMA_WR_DONE_IMWR_ADDR_H(base)	((base) + 0x09D4) -#define PCIE_DMA_WR_ABORT_IMWR_ADDR_L(base)	((base) + 0x09D8) -#define PCIE_DMA_WR_ABORT_IMWR_ADDR_H(base)	((base) + 0x09DC) -#define PCIE_DMA_WR_IMWR_DATA(base)		((base) + 0x09E0) -#define PCIE_DMA_WR_LL_ERR_EN(base)		((base) + 0x0A00) -#define PCIE_DMA_WR_DOORBELL(base)		((base) + 0x0980) -#define PCIE_DMA_RD_ENABLE(base)		((base) + 0x099C) -#define PCIE_DMA_RD_DOORBELL(base)		((base) + 0x09A0) -#define PCIE_DMA_RD_CHWTLOW(base)		((base) + 0x09A8) -#define PCIE_DMA_RD_CHWTHIG(base)		((base) + 0x09AC) -#define PCIE_DMA_RD_INTSTS(base)		((base) + 0x0A10) -#define PCIE_DMA_RD_INTMASK(base)		((base) + 0x0A18) -#define PCIE_DMA_RD_INTCLER(base)		((base) + 0x0A1C) -#define PCIE_DMA_RD_ERR_STS_L(base)		((base) + 0x0A24) -#define PCIE_DMA_RD_ERR_STS_H(base)		((base) + 0x0A28) -#define PCIE_DMA_RD_LL_ERR_EN(base)		((base) + 0x0A34) -#define PCIE_DMA_RD_DONE_IMWR_ADDR_L(base)	((base) + 0x0A3C) -#define PCIE_DMA_RD_DONE_IMWR_ADDR_H(base)	((base) + 0x0A40) -#define PCIE_DMA_RD_ABORT_IMWR_ADDR_L(base)	((base) + 0x0A44) -#define PCIE_DMA_RD_ABORT_IMWR_ADDR_H(base)	((base) + 0x0A48) -#define PCIE_DMA_RD_IMWR_DATA(base)		((base) + 0x0A4C) -#define PCIE_DMA_CHNL_CONTEXT(base)		((base) + 0x0A6C) -#define PCIE_DMA_CHNL_CNTRL(base)		((base) + 0x0A70) -#define PCIE_DMA_XFR_SIZE(base)			((base) + 0x0A78) -#define PCIE_DMA_SAR_LOW(base)			((base) + 0x0A7C) -#define PCIE_DMA_SAR_HIGH(base)			((base) + 0x0A80) -#define PCIE_DMA_DAR_LOW(base)			((base) + 0x0A84) -#define PCIE_DMA_DAR_HIGH(base)			((base) + 0x0A88) -#define PCIE_DMA_LLPTR_LOW(base)		((base) + 0x0A8C) -#define PCIE_DMA_LLPTR_HIGH(base)		((base) + 0x0A90) -#define PCIE_DMA_WRLL_ERR_ENB(base)		((base) + 0x0A00) -#define PCIE_DMA_RDLL_ERR_ENB(base)		((base) + 0x0A34) -#define PCIE_DMABD_CHNL_CNTRL(base)		((base) + 0x8000) -#define PCIE_DMABD_XFR_SIZE(base)		((base) + 0x8004) -#define PCIE_DMABD_SAR_LOW(base)		((base) + 0x8008) -#define PCIE_DMABD_SAR_HIGH(base)		((base) + 0x800c) -#define PCIE_DMABD_DAR_LOW(base)		((base) + 0x8010) -#define PCIE_DMABD_DAR_HIGH(base)		((base) + 0x8014) -#define PCIE_DMABD_LLPTR_LOW(base)		((base) + 0x8018) -#define PCIE_DMABD_LLPTR_HIGH(base)		((base) + 0x801c) -#define PCIE_WRDMA0_CHNL_CNTRL(base)		((base) + 0x8000) -#define PCIE_WRDMA0_XFR_SIZE(base)		((base) + 0x8004) -#define PCIE_WRDMA0_SAR_LOW(base)		((base) + 0x8008) -#define PCIE_WRDMA0_SAR_HIGH(base)		((base) + 0x800c) -#define PCIE_WRDMA0_DAR_LOW(base)		((base) + 0x8010) -#define PCIE_WRDMA0_DAR_HIGH(base)		((base) + 0x8014) -#define PCIE_WRDMA0_LLPTR_LOW(base)		((base) + 0x8018) -#define PCIE_WRDMA0_LLPTR_HIGH(base)		((base) + 0x801c) -#define PCIE_WRDMA1_CHNL_CNTRL(base)		((base) + 0x8020) -#define PCIE_WRDMA1_XFR_SIZE(base)		((base) + 0x8024) -#define PCIE_WRDMA1_SAR_LOW(base)		((base) + 0x8028) -#define PCIE_WRDMA1_SAR_HIGH(base)		((base) + 0x802c) -#define PCIE_WRDMA1_DAR_LOW(base)		((base) + 0x8030) -#define PCIE_WRDMA1_DAR_HIGH(base)		((base) + 0x8034) -#define PCIE_WRDMA1_LLPTR_LOW(base)		((base) + 0x8038) -#define PCIE_WRDMA1_LLPTR_HIGH(base)		((base) + 0x803c) -#define PCIE_RDDMA0_CHNL_CNTRL(base)		((base) + 0x8040) -#define PCIE_RDDMA0_XFR_SIZE(base)		((base) + 0x8044) -#define PCIE_RDDMA0_SAR_LOW(base)		((base) + 0x8048) -#define PCIE_RDDMA0_SAR_HIGH(base)		((base) + 0x804c) -#define PCIE_RDDMA0_DAR_LOW(base)		((base) + 0x8050) -#define PCIE_RDDMA0_DAR_HIGH(base)		((base) + 0x8054) -#define PCIE_RDDMA0_LLPTR_LOW(base)		((base) + 0x8058) -#define PCIE_RDDMA0_LLPTR_HIGH(base)		((base) + 0x805c) -#define PCIE_RDDMA1_CHNL_CNTRL(base)		((base) + 0x8060) -#define PCIE_RDDMA1_XFR_SIZE(base)		((base) + 0x8064) -#define PCIE_RDDMA1_SAR_LOW(base)		((base) + 0x8068) -#define PCIE_RDDMA1_SAR_HIGH(base)		((base) + 0x806c) -#define PCIE_RDDMA1_DAR_LOW(base)		((base) + 0x8070) -#define PCIE_RDDMA1_DAR_HIGH(base)		((base) + 0x8074) -#define PCIE_RDDMA1_LLPTR_LOW(base)		((base) + 0x8078) -#define PCIE_RDDMA1_LLPTR_HIGH(base)		((base) + 0x807c) - -#define PCIE_ID(base)				((base) + 0x0000) -#define PCIE_CMD(base)				((base) + 0x0004) -#define PCIE_BAR(base, n)			((base) + 0x0010 + ((n) << 2)) -#define PCIE_CAP_PTR(base)			((base) + 0x0034) -#define PCIE_MSI_LBAR(base)			((base) + 0x0054) -#define PCIE_MSI_CTRL(base)			((base) + 0x0050) -#define PCIE_MSI_ADDR_L(base)			((base) + 0x0054) -#define PCIE_MSI_ADDR_H(base)			((base) + 0x0058) -#define PCIE_MSI_DATA(base)			((base) + 0x005C) -#define PCIE_MSI_MASK_BIT(base)			((base) + 0x0060) -#define PCIE_MSI_PEND_BIT(base)			((base) + 0x0064) -#define PCIE_DEVCAP(base)			((base) + 0x0074) -#define PCIE_DEVCTLSTS(base)			((base) + 0x0078) - -#define PCIE_CMDSTS(base)			((base) + 0x0004) -#define PCIE_LINK_STAT(base)			((base) + 0x80) -#define PCIE_LINK_CTL2(base)			((base) + 0xa0) -#define PCIE_ASPM_L1_CTRL(base)			((base) + 0x70c) -#define PCIE_ASPM_LINK_CTRL(base)		(PCIE_LINK_STAT) -#define PCIE_ASPM_L1_SUBSTATE_TIMING(base)	((base) + 0xB44) -#define PCIE_L1SUB_CTRL1(base)			((base) + 0x150) -#define PCIE_PMCSR(base)			((base) + 0x44) -#define PCIE_CFG_SPACE_LIMIT(base)		((base) + 0x100) - -/* PCIe link defines */ -#define PEARL_PCIE_LINKUP			(0x7) -#define PEARL_PCIE_DATA_LINK			(BIT(0)) -#define PEARL_PCIE_PHY_LINK			(BIT(1)) -#define PEARL_PCIE_LINK_RST			(BIT(3)) -#define PEARL_PCIE_FATAL_ERR			(BIT(5)) -#define PEARL_PCIE_NONFATAL_ERR			(BIT(6)) - -/* PCIe Lane defines */ -#define PCIE_G2_LANE_X1				((BIT(0)) << 16) -#define PCIE_G2_LANE_X2				((BIT(0) | BIT(1)) << 16) - -/* PCIe DLL link enable */ -#define PCIE_DLL_LINK_EN			((BIT(0)) << 5) - -#define PCIE_LINK_GEN1				(BIT(0)) -#define PCIE_LINK_GEN2				(BIT(1)) -#define PCIE_LINK_GEN3				(BIT(2)) -#define PCIE_LINK_MODE(x)			(((x) >> 16) & 0x7) - -#define MSI_EN					(BIT(0)) -#define MSI_64_EN				(BIT(7)) -#define PCIE_MSI_ADDR_OFFSET(a)			((a) & 0xFFFF) -#define PCIE_MSI_ADDR_ALIGN(a)			((a) & (~0xFFFF)) - -#define PCIE_BAR_MASK(base, n)			((base) + 0x1010 + ((n) << 2)) -#define PCIE_MAX_BAR				(6) - -#define PCIE_ATU_VIEW(base)			((base) + 0x0900) -#define PCIE_ATU_CTL1(base)			((base) + 0x0904) -#define PCIE_ATU_CTL2(base)			((base) + 0x0908) -#define PCIE_ATU_LBAR(base)			((base) + 0x090c) -#define PCIE_ATU_UBAR(base)			((base) + 0x0910) -#define PCIE_ATU_LAR(base)			((base) + 0x0914) -#define PCIE_ATU_LTAR(base)			((base) + 0x0918) -#define PCIE_ATU_UTAR(base)			((base) + 0x091c) - -#define PCIE_MSI_ADDR_LOWER(base)		((base) + 0x0820) -#define PCIE_MSI_ADDR_UPPER(base)		((base) + 0x0824) -#define PCIE_MSI_ENABLE(base)			((base) + 0x0828) -#define PCIE_MSI_MASK_RC(base)			((base) + 0x082c) -#define PCIE_MSI_STATUS(base)			((base) + 0x0830) -#define PEARL_PCIE_MSI_REGION			(0xce000000) -#define PEARL_PCIE_MSI_DATA			(0) -#define PCIE_MSI_GPIO(base)			((base) + 0x0888) - -#define PCIE_HDP_HOST_QUEUE_FULL	(BIT(17)) -#define USE_BAR_MATCH_MODE -#define PCIE_ATU_OB_REGION		(BIT(0)) -#define PCIE_ATU_EN_REGION		(BIT(31)) -#define PCIE_ATU_EN_MATCH		(BIT(30)) -#define PCIE_BASE_REGION		(0xb0000000) -#define PCIE_MEM_MAP_SIZE		(512 * 1024) - -#define PCIE_OB_REG_REGION		(0xcf000000) -#define PCIE_CONFIG_REGION		(0xcf000000) -#define PCIE_CONFIG_SIZE		(4096) -#define PCIE_CONFIG_CH			(1) - -/* inbound mapping */ -#define PCIE_IB_BAR0			(0x00000000)	/* ddr */ -#define PCIE_IB_BAR0_CH			(0) -#define PCIE_IB_BAR3			(0xe0000000)	/* sys_reg */ -#define PCIE_IB_BAR3_CH			(1) - -/* outbound mapping */ -#define PCIE_MEM_CH			(0) -#define PCIE_REG_CH			(1) -#define PCIE_MEM_REGION			(0xc0000000) -#define	PCIE_MEM_SIZE			(0x000fffff) -#define PCIE_MEM_TAR			(0x80000000) - -#define PCIE_MSI_REGION			(0xce000000) -#define PCIE_MSI_SIZE			(KBYTE(4) - 1) -#define PCIE_MSI_CH			(1) - -/* size of config region */ -#define PCIE_CFG_SIZE			(0x0000ffff) - -#define PCIE_ATU_DIR_IB			(BIT(31)) -#define PCIE_ATU_DIR_OB			(0) -#define PCIE_ATU_DIR_CFG		(2) -#define PCIE_ATU_DIR_MATCH_IB		(BIT(31) | BIT(30)) - -#define PCIE_DMA_WR_0			(0) -#define PCIE_DMA_WR_1			(1) -#define PCIE_DMA_RD_0			(2) -#define PCIE_DMA_RD_1			(3) - -#define PCIE_DMA_CHNL_CNTRL_CB		(BIT(0)) -#define PCIE_DMA_CHNL_CNTRL_TCB		(BIT(1)) -#define PCIE_DMA_CHNL_CNTRL_LLP		(BIT(2)) -#define PCIE_DMA_CHNL_CNTRL_LIE		(BIT(3)) -#define PCIE_DMA_CHNL_CNTRL_RIE		(BIT(4)) -#define PCIE_DMA_CHNL_CNTRL_CSS		(BIT(8)) -#define PCIE_DMA_CHNL_CNTRL_LLE		(BIT(9)) -#define PCIE_DMA_CHNL_CNTRL_TLP		(BIT(26)) - -#define PCIE_DMA_CHNL_CONTEXT_RD	(BIT(31)) -#define PCIE_DMA_CHNL_CONTEXT_WR	(0) -#define PCIE_MAX_BAR			(6) - -/* PCIe HDP interrupt status definition */ -#define PCIE_HDP_INT_EP_RXDMA		(BIT(0)) -#define PCIE_HDP_INT_HBM_UF		(BIT(1)) -#define PCIE_HDP_INT_RX_LEN_ERR		(BIT(2)) -#define PCIE_HDP_INT_RX_HDR_LEN_ERR	(BIT(3)) -#define PCIE_HDP_INT_EP_TXDMA		(BIT(12)) -#define PCIE_HDP_INT_HHBM_UF		(BIT(13)) -#define PCIE_HDP_INT_EP_TXEMPTY		(BIT(15)) -#define PCIE_HDP_INT_IPC		(BIT(29)) - -/* PCIe interrupt status definition */ -#define PCIE_INT_MSI			(BIT(24)) -#define PCIE_INT_INTX			(BIT(23)) - -/* PCIe legacy INTx */ -#define PEARL_PCIE_CFG0_OFFSET		(0x6C) -#define PEARL_ASSERT_INTX		(BIT(9)) - -/* SYS CTL regs */ -#define QTN_PEARL_SYSCTL_LHOST_IRQ_OFFSET	(0x001C) - -#define QTN_PEARL_IPC_IRQ_WORD(irq)	(BIT(irq) | BIT(irq + 16)) -#define QTN_PEARL_LHOST_IPC_IRQ		(6) -#define QTN_PEARL_LHOST_EP_RESET	(7) - -#endif /* __PEARL_PCIE_H */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink.h b/drivers/net/wireless/quantenna/qtnfmac/qlink.h index 99d37e3efba6..8d62addea895 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink.h @@ -71,6 +71,7 @@ struct qlink_msg_header {   * @QLINK_HW_CAPAB_DFS_OFFLOAD: device implements DFS offload functionality   * @QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR: device supports MAC Address   *	Randomization in probe requests. + * @QLINK_HW_CAPAB_OBSS_SCAN: device can perform OBSS scanning.   */  enum qlink_hw_capab {  	QLINK_HW_CAPAB_REG_UPDATE		= BIT(0), @@ -78,6 +79,8 @@ enum qlink_hw_capab {  	QLINK_HW_CAPAB_DFS_OFFLOAD		= BIT(2),  	QLINK_HW_CAPAB_SCAN_RANDOM_MAC_ADDR	= BIT(3),  	QLINK_HW_CAPAB_PWR_MGMT			= BIT(4), +	QLINK_HW_CAPAB_OBSS_SCAN		= BIT(5), +	QLINK_HW_CAPAB_SCAN_DWELL		= BIT(6),  };  enum qlink_iface_type { @@ -1149,6 +1152,8 @@ enum qlink_tlv_id {  	QTN_TLV_ID_MAX_SCAN_SSIDS	= 0x0409,  	QTN_TLV_ID_WOWLAN_CAPAB		= 0x0410,  	QTN_TLV_ID_WOWLAN_PATTERN	= 0x0411, +	QTN_TLV_ID_SCAN_FLUSH		= 0x0412, +	QTN_TLV_ID_SCAN_DWELL		= 0x0413,  };  struct qlink_tlv_hdr { diff --git a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h index 54caeb38917c..960d5d97492f 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qlink_util.h @@ -40,6 +40,14 @@ static inline void qtnf_cmd_skb_put_tlv_arr(struct sk_buff *skb,  	memcpy(hdr->val, arr, arr_len);  } +static inline void qtnf_cmd_skb_put_tlv_tag(struct sk_buff *skb, u16 tlv_id) +{ +	struct qlink_tlv_hdr *hdr = skb_put(skb, sizeof(*hdr)); + +	hdr->type = cpu_to_le16(tlv_id); +	hdr->len = cpu_to_le16(0); +} +  static inline void qtnf_cmd_skb_put_tlv_u8(struct sk_buff *skb, u16 tlv_id,  					   u8 value)  { diff --git a/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h b/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h index c4ad40d59085..1fe798a9a667 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h +++ b/drivers/net/wireless/quantenna/qtnfmac/qtn_hw_ids.h @@ -25,8 +25,22 @@  #define	PCIE_DEVICE_ID_QTN_PEARL	(0x0008) +#define QTN_REG_SYS_CTRL_CSR		0x14 +#define QTN_CHIP_ID_MASK		0xF0 +#define QTN_CHIP_ID_TOPAZ		0x40 +#define QTN_CHIP_ID_PEARL		0x50 +#define QTN_CHIP_ID_PEARL_B		0x60 +#define QTN_CHIP_ID_PEARL_C		0x70 +  /* FW names */  #define QTN_PCI_PEARL_FW_NAME		"qtn/fmac_qsr10g.img" +static inline unsigned int qtnf_chip_id_get(const void __iomem *regs_base) +{ +	u32 board_rev = readl(regs_base + QTN_REG_SYS_CTRL_CSR); + +	return board_rev & QTN_CHIP_ID_MASK; +} +  #endif	/* _QTN_HW_IDS_H_ */ diff --git a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c index aa106dd0a14b..2ec334199c2b 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c +++ b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.c @@ -42,19 +42,18 @@ static void qtnf_shm_handle_new_data(struct qtnf_shm_ipc *ipc)  	if (unlikely(size == 0 || size > QTN_IPC_MAX_DATA_SZ)) {  		pr_err("wrong rx packet size: %zu\n", size);  		rx_buff_ok = false; -	} else { -		memcpy_fromio(ipc->rx_data, ipc->shm_region->data, size); +	} + +	if (likely(rx_buff_ok)) { +		ipc->rx_packet_count++; +		ipc->rx_callback.fn(ipc->rx_callback.arg, +				    ipc->shm_region->data, size);  	}  	writel(QTNF_SHM_IPC_ACK, &shm_reg_hdr->flags);  	readl(&shm_reg_hdr->flags); /* flush PCIe write */  	ipc->interrupt.fn(ipc->interrupt.arg); - -	if (likely(rx_buff_ok)) { -		ipc->rx_packet_count++; -		ipc->rx_callback.fn(ipc->rx_callback.arg, ipc->rx_data, size); -	}  }  static void qtnf_shm_ipc_irq_work(struct work_struct *work) diff --git a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h index 453dd6477b12..c2a3702a9ee7 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h +++ b/drivers/net/wireless/quantenna/qtnfmac/shm_ipc.h @@ -32,7 +32,7 @@ struct qtnf_shm_ipc_int {  };  struct qtnf_shm_ipc_rx_callback { -	void (*fn)(void *arg, const u8 *buf, size_t len); +	void (*fn)(void *arg, const u8 __iomem *buf, size_t len);  	void *arg;  }; @@ -51,8 +51,6 @@ struct qtnf_shm_ipc {  	u8 waiting_for_ack; -	u8 rx_data[QTN_IPC_MAX_DATA_SZ] __aligned(sizeof(u32)); -  	struct qtnf_shm_ipc_int interrupt;  	struct qtnf_shm_ipc_rx_callback rx_callback; |