diff options
Diffstat (limited to 'drivers/net')
19 files changed, 318 insertions, 128 deletions
| diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index f74bacf071fc..bb9c3d6ef435 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -427,6 +427,8 @@ static int bond_ipsec_add_sa(struct xfrm_state *xs,  			     struct netlink_ext_ack *extack)  {  	struct net_device *bond_dev = xs->xso.dev; +	struct net_device *real_dev; +	netdevice_tracker tracker;  	struct bond_ipsec *ipsec;  	struct bonding *bond;  	struct slave *slave; @@ -438,74 +440,80 @@ static int bond_ipsec_add_sa(struct xfrm_state *xs,  	rcu_read_lock();  	bond = netdev_priv(bond_dev);  	slave = rcu_dereference(bond->curr_active_slave); -	if (!slave) { -		rcu_read_unlock(); -		return -ENODEV; +	real_dev = slave ? slave->dev : NULL; +	netdev_hold(real_dev, &tracker, GFP_ATOMIC); +	rcu_read_unlock(); +	if (!real_dev) { +		err = -ENODEV; +		goto out;  	} -	if (!slave->dev->xfrmdev_ops || -	    !slave->dev->xfrmdev_ops->xdo_dev_state_add || -	    netif_is_bond_master(slave->dev)) { +	if (!real_dev->xfrmdev_ops || +	    !real_dev->xfrmdev_ops->xdo_dev_state_add || +	    netif_is_bond_master(real_dev)) {  		NL_SET_ERR_MSG_MOD(extack, "Slave does not support ipsec offload"); -		rcu_read_unlock(); -		return -EINVAL; +		err = -EINVAL; +		goto out;  	} -	ipsec = kmalloc(sizeof(*ipsec), GFP_ATOMIC); +	ipsec = kmalloc(sizeof(*ipsec), GFP_KERNEL);  	if (!ipsec) { -		rcu_read_unlock(); -		return -ENOMEM; +		err = -ENOMEM; +		goto out;  	} -	xs->xso.real_dev = slave->dev; -	err = slave->dev->xfrmdev_ops->xdo_dev_state_add(xs, extack); +	xs->xso.real_dev = real_dev; +	err = real_dev->xfrmdev_ops->xdo_dev_state_add(xs, extack);  	if (!err) {  		ipsec->xs = xs;  		INIT_LIST_HEAD(&ipsec->list); -		spin_lock_bh(&bond->ipsec_lock); +		mutex_lock(&bond->ipsec_lock);  		list_add(&ipsec->list, &bond->ipsec_list); -		spin_unlock_bh(&bond->ipsec_lock); +		mutex_unlock(&bond->ipsec_lock);  	} else {  		kfree(ipsec);  	} -	rcu_read_unlock(); +out: +	netdev_put(real_dev, &tracker);  	return err;  }  static void bond_ipsec_add_sa_all(struct bonding *bond)  {  	struct net_device *bond_dev = bond->dev; +	struct net_device *real_dev;  	struct bond_ipsec *ipsec;  	struct slave *slave; -	rcu_read_lock(); -	slave = rcu_dereference(bond->curr_active_slave); -	if (!slave) -		goto out; +	slave = rtnl_dereference(bond->curr_active_slave); +	real_dev = slave ? slave->dev : NULL; +	if (!real_dev) +		return; -	if (!slave->dev->xfrmdev_ops || -	    !slave->dev->xfrmdev_ops->xdo_dev_state_add || -	    netif_is_bond_master(slave->dev)) { -		spin_lock_bh(&bond->ipsec_lock); +	mutex_lock(&bond->ipsec_lock); +	if (!real_dev->xfrmdev_ops || +	    !real_dev->xfrmdev_ops->xdo_dev_state_add || +	    netif_is_bond_master(real_dev)) {  		if (!list_empty(&bond->ipsec_list)) -			slave_warn(bond_dev, slave->dev, +			slave_warn(bond_dev, real_dev,  				   "%s: no slave xdo_dev_state_add\n",  				   __func__); -		spin_unlock_bh(&bond->ipsec_lock);  		goto out;  	} -	spin_lock_bh(&bond->ipsec_lock);  	list_for_each_entry(ipsec, &bond->ipsec_list, list) { -		ipsec->xs->xso.real_dev = slave->dev; -		if (slave->dev->xfrmdev_ops->xdo_dev_state_add(ipsec->xs, NULL)) { -			slave_warn(bond_dev, slave->dev, "%s: failed to add SA\n", __func__); +		/* If new state is added before ipsec_lock acquired */ +		if (ipsec->xs->xso.real_dev == real_dev) +			continue; + +		ipsec->xs->xso.real_dev = real_dev; +		if (real_dev->xfrmdev_ops->xdo_dev_state_add(ipsec->xs, NULL)) { +			slave_warn(bond_dev, real_dev, "%s: failed to add SA\n", __func__);  			ipsec->xs->xso.real_dev = NULL;  		}  	} -	spin_unlock_bh(&bond->ipsec_lock);  out: -	rcu_read_unlock(); +	mutex_unlock(&bond->ipsec_lock);  }  /** @@ -515,6 +523,8 @@ out:  static void bond_ipsec_del_sa(struct xfrm_state *xs)  {  	struct net_device *bond_dev = xs->xso.dev; +	struct net_device *real_dev; +	netdevice_tracker tracker;  	struct bond_ipsec *ipsec;  	struct bonding *bond;  	struct slave *slave; @@ -525,6 +535,9 @@ static void bond_ipsec_del_sa(struct xfrm_state *xs)  	rcu_read_lock();  	bond = netdev_priv(bond_dev);  	slave = rcu_dereference(bond->curr_active_slave); +	real_dev = slave ? slave->dev : NULL; +	netdev_hold(real_dev, &tracker, GFP_ATOMIC); +	rcu_read_unlock();  	if (!slave)  		goto out; @@ -532,18 +545,19 @@ static void bond_ipsec_del_sa(struct xfrm_state *xs)  	if (!xs->xso.real_dev)  		goto out; -	WARN_ON(xs->xso.real_dev != slave->dev); +	WARN_ON(xs->xso.real_dev != real_dev); -	if (!slave->dev->xfrmdev_ops || -	    !slave->dev->xfrmdev_ops->xdo_dev_state_delete || -	    netif_is_bond_master(slave->dev)) { -		slave_warn(bond_dev, slave->dev, "%s: no slave xdo_dev_state_delete\n", __func__); +	if (!real_dev->xfrmdev_ops || +	    !real_dev->xfrmdev_ops->xdo_dev_state_delete || +	    netif_is_bond_master(real_dev)) { +		slave_warn(bond_dev, real_dev, "%s: no slave xdo_dev_state_delete\n", __func__);  		goto out;  	} -	slave->dev->xfrmdev_ops->xdo_dev_state_delete(xs); +	real_dev->xfrmdev_ops->xdo_dev_state_delete(xs);  out: -	spin_lock_bh(&bond->ipsec_lock); +	netdev_put(real_dev, &tracker); +	mutex_lock(&bond->ipsec_lock);  	list_for_each_entry(ipsec, &bond->ipsec_list, list) {  		if (ipsec->xs == xs) {  			list_del(&ipsec->list); @@ -551,40 +565,72 @@ out:  			break;  		}  	} -	spin_unlock_bh(&bond->ipsec_lock); -	rcu_read_unlock(); +	mutex_unlock(&bond->ipsec_lock);  }  static void bond_ipsec_del_sa_all(struct bonding *bond)  {  	struct net_device *bond_dev = bond->dev; +	struct net_device *real_dev;  	struct bond_ipsec *ipsec;  	struct slave *slave; -	rcu_read_lock(); -	slave = rcu_dereference(bond->curr_active_slave); -	if (!slave) { -		rcu_read_unlock(); +	slave = rtnl_dereference(bond->curr_active_slave); +	real_dev = slave ? slave->dev : NULL; +	if (!real_dev)  		return; -	} -	spin_lock_bh(&bond->ipsec_lock); +	mutex_lock(&bond->ipsec_lock);  	list_for_each_entry(ipsec, &bond->ipsec_list, list) {  		if (!ipsec->xs->xso.real_dev)  			continue; -		if (!slave->dev->xfrmdev_ops || -		    !slave->dev->xfrmdev_ops->xdo_dev_state_delete || -		    netif_is_bond_master(slave->dev)) { -			slave_warn(bond_dev, slave->dev, +		if (!real_dev->xfrmdev_ops || +		    !real_dev->xfrmdev_ops->xdo_dev_state_delete || +		    netif_is_bond_master(real_dev)) { +			slave_warn(bond_dev, real_dev,  				   "%s: no slave xdo_dev_state_delete\n",  				   __func__);  		} else { -			slave->dev->xfrmdev_ops->xdo_dev_state_delete(ipsec->xs); +			real_dev->xfrmdev_ops->xdo_dev_state_delete(ipsec->xs); +			if (real_dev->xfrmdev_ops->xdo_dev_state_free) +				real_dev->xfrmdev_ops->xdo_dev_state_free(ipsec->xs);  		}  	} -	spin_unlock_bh(&bond->ipsec_lock); +	mutex_unlock(&bond->ipsec_lock); +} + +static void bond_ipsec_free_sa(struct xfrm_state *xs) +{ +	struct net_device *bond_dev = xs->xso.dev; +	struct net_device *real_dev; +	netdevice_tracker tracker; +	struct bonding *bond; +	struct slave *slave; + +	if (!bond_dev) +		return; + +	rcu_read_lock(); +	bond = netdev_priv(bond_dev); +	slave = rcu_dereference(bond->curr_active_slave); +	real_dev = slave ? slave->dev : NULL; +	netdev_hold(real_dev, &tracker, GFP_ATOMIC);  	rcu_read_unlock(); + +	if (!slave) +		goto out; + +	if (!xs->xso.real_dev) +		goto out; + +	WARN_ON(xs->xso.real_dev != real_dev); + +	if (real_dev && real_dev->xfrmdev_ops && +	    real_dev->xfrmdev_ops->xdo_dev_state_free) +		real_dev->xfrmdev_ops->xdo_dev_state_free(xs); +out: +	netdev_put(real_dev, &tracker);  }  /** @@ -627,6 +673,7 @@ out:  static const struct xfrmdev_ops bond_xfrmdev_ops = {  	.xdo_dev_state_add = bond_ipsec_add_sa,  	.xdo_dev_state_delete = bond_ipsec_del_sa, +	.xdo_dev_state_free = bond_ipsec_free_sa,  	.xdo_dev_offload_ok = bond_ipsec_offload_ok,  };  #endif /* CONFIG_XFRM_OFFLOAD */ @@ -5877,7 +5924,7 @@ void bond_setup(struct net_device *bond_dev)  	/* set up xfrm device ops (only supported in active-backup right now) */  	bond_dev->xfrmdev_ops = &bond_xfrmdev_ops;  	INIT_LIST_HEAD(&bond->ipsec_list); -	spin_lock_init(&bond->ipsec_lock); +	mutex_init(&bond->ipsec_lock);  #endif /* CONFIG_XFRM_OFFLOAD */  	/* don't acquire bond device's netif_tx_lock when transmitting */ @@ -5926,6 +5973,10 @@ static void bond_uninit(struct net_device *bond_dev)  		__bond_release_one(bond_dev, slave->dev, true, true);  	netdev_info(bond_dev, "Released all slaves\n"); +#ifdef CONFIG_XFRM_OFFLOAD +	mutex_destroy(&bond->ipsec_lock); +#endif /* CONFIG_XFRM_OFFLOAD */ +  	bond_set_slave_arr(bond, NULL, NULL);  	list_del_rcu(&bond->bond_list); diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index fddfd1dd5070..4c546c3aef0f 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -572,7 +572,7 @@ static bool ftgmac100_rx_packet(struct ftgmac100 *priv, int *processed)  	(*processed)++;  	return true; - drop: +drop:  	/* Clean rxdes0 (which resets own bit) */  	rxdes->rxdes0 = cpu_to_le32(status & priv->rxdes0_edorr_mask);  	priv->rx_pointer = ftgmac100_next_rx_pointer(priv, pointer); @@ -656,6 +656,11 @@ static bool ftgmac100_tx_complete_packet(struct ftgmac100 *priv)  	ftgmac100_free_tx_packet(priv, pointer, skb, txdes, ctl_stat);  	txdes->txdes0 = cpu_to_le32(ctl_stat & priv->txdes0_edotr_mask); +	/* Ensure the descriptor config is visible before setting the tx +	 * pointer. +	 */ +	smp_wmb(); +  	priv->tx_clean_pointer = ftgmac100_next_tx_pointer(priv, pointer);  	return true; @@ -809,6 +814,11 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb,  	dma_wmb();  	first->txdes0 = cpu_to_le32(f_ctl_stat); +	/* Ensure the descriptor config is visible before setting the tx +	 * pointer. +	 */ +	smp_wmb(); +  	/* Update next TX pointer */  	priv->tx_pointer = pointer; @@ -829,7 +839,7 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb,  	return NETDEV_TX_OK; - dma_err: +dma_err:  	if (net_ratelimit())  		netdev_err(netdev, "map tx fragment failed\n"); @@ -851,7 +861,7 @@ static netdev_tx_t ftgmac100_hard_start_xmit(struct sk_buff *skb,  	 * last fragment, so we know ftgmac100_free_tx_packet()  	 * hasn't freed the skb yet.  	 */ - drop: +drop:  	/* Drop the packet */  	dev_kfree_skb_any(skb);  	netdev->stats.tx_dropped++; @@ -1344,7 +1354,7 @@ static void ftgmac100_reset(struct ftgmac100 *priv)  	ftgmac100_init_all(priv, true);  	netdev_dbg(netdev, "Reset done !\n"); - bail: +bail:  	if (priv->mii_bus)  		mutex_unlock(&priv->mii_bus->mdio_lock);  	if (netdev->phydev) @@ -1543,15 +1553,15 @@ static int ftgmac100_open(struct net_device *netdev)  	return 0; - err_ncsi: +err_ncsi:  	napi_disable(&priv->napi);  	netif_stop_queue(netdev); - err_alloc: +err_alloc:  	ftgmac100_free_buffers(priv);  	free_irq(netdev->irq, netdev); - err_irq: +err_irq:  	netif_napi_del(&priv->napi); - err_hw: +err_hw:  	iowrite32(0, priv->base + FTGMAC100_OFFSET_IER);  	ftgmac100_free_rings(priv);  	return err; diff --git a/drivers/net/ethernet/microsoft/mana/hw_channel.c b/drivers/net/ethernet/microsoft/mana/hw_channel.c index cafded2f9382..a00f915c5188 100644 --- a/drivers/net/ethernet/microsoft/mana/hw_channel.c +++ b/drivers/net/ethernet/microsoft/mana/hw_channel.c @@ -52,9 +52,33 @@ static int mana_hwc_verify_resp_msg(const struct hwc_caller_ctx *caller_ctx,  	return 0;  } +static int mana_hwc_post_rx_wqe(const struct hwc_wq *hwc_rxq, +				struct hwc_work_request *req) +{ +	struct device *dev = hwc_rxq->hwc->dev; +	struct gdma_sge *sge; +	int err; + +	sge = &req->sge; +	sge->address = (u64)req->buf_sge_addr; +	sge->mem_key = hwc_rxq->msg_buf->gpa_mkey; +	sge->size = req->buf_len; + +	memset(&req->wqe_req, 0, sizeof(struct gdma_wqe_request)); +	req->wqe_req.sgl = sge; +	req->wqe_req.num_sge = 1; +	req->wqe_req.client_data_unit = 0; + +	err = mana_gd_post_and_ring(hwc_rxq->gdma_wq, &req->wqe_req, NULL); +	if (err) +		dev_err(dev, "Failed to post WQE on HWC RQ: %d\n", err); +	return err; +} +  static void mana_hwc_handle_resp(struct hw_channel_context *hwc, u32 resp_len, -				 const struct gdma_resp_hdr *resp_msg) +				 struct hwc_work_request *rx_req)  { +	const struct gdma_resp_hdr *resp_msg = rx_req->buf_va;  	struct hwc_caller_ctx *ctx;  	int err; @@ -62,6 +86,7 @@ static void mana_hwc_handle_resp(struct hw_channel_context *hwc, u32 resp_len,  		      hwc->inflight_msg_res.map)) {  		dev_err(hwc->dev, "hwc_rx: invalid msg_id = %u\n",  			resp_msg->response.hwc_msg_id); +		mana_hwc_post_rx_wqe(hwc->rxq, rx_req);  		return;  	} @@ -75,30 +100,13 @@ static void mana_hwc_handle_resp(struct hw_channel_context *hwc, u32 resp_len,  	memcpy(ctx->output_buf, resp_msg, resp_len);  out:  	ctx->error = err; -	complete(&ctx->comp_event); -} - -static int mana_hwc_post_rx_wqe(const struct hwc_wq *hwc_rxq, -				struct hwc_work_request *req) -{ -	struct device *dev = hwc_rxq->hwc->dev; -	struct gdma_sge *sge; -	int err; - -	sge = &req->sge; -	sge->address = (u64)req->buf_sge_addr; -	sge->mem_key = hwc_rxq->msg_buf->gpa_mkey; -	sge->size = req->buf_len; -	memset(&req->wqe_req, 0, sizeof(struct gdma_wqe_request)); -	req->wqe_req.sgl = sge; -	req->wqe_req.num_sge = 1; -	req->wqe_req.client_data_unit = 0; +	/* Must post rx wqe before complete(), otherwise the next rx may +	 * hit no_wqe error. +	 */ +	mana_hwc_post_rx_wqe(hwc->rxq, rx_req); -	err = mana_gd_post_and_ring(hwc_rxq->gdma_wq, &req->wqe_req, NULL); -	if (err) -		dev_err(dev, "Failed to post WQE on HWC RQ: %d\n", err); -	return err; +	complete(&ctx->comp_event);  }  static void mana_hwc_init_event_handler(void *ctx, struct gdma_queue *q_self, @@ -235,14 +243,12 @@ static void mana_hwc_rx_event_handler(void *ctx, u32 gdma_rxq_id,  		return;  	} -	mana_hwc_handle_resp(hwc, rx_oob->tx_oob_data_size, resp); +	mana_hwc_handle_resp(hwc, rx_oob->tx_oob_data_size, rx_req); -	/* Do no longer use 'resp', because the buffer is posted to the HW -	 * in the below mana_hwc_post_rx_wqe(). +	/* Can no longer use 'resp', because the buffer is posted to the HW +	 * in mana_hwc_handle_resp() above.  	 */  	resp = NULL; - -	mana_hwc_post_rx_wqe(hwc_rxq, rx_req);  }  static void mana_hwc_tx_event_handler(void *ctx, u32 gdma_txq_id, diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index c647033f3ad2..f2f07bf88545 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -32,7 +32,7 @@  #define IONIC_ADMIN_DOORBELL_DEADLINE	(HZ / 2)	/* 500ms */  #define IONIC_TX_DOORBELL_DEADLINE	(HZ / 100)	/* 10ms */  #define IONIC_RX_MIN_DOORBELL_DEADLINE	(HZ / 100)	/* 10ms */ -#define IONIC_RX_MAX_DOORBELL_DEADLINE	(HZ * 5)	/* 5s */ +#define IONIC_RX_MAX_DOORBELL_DEADLINE	(HZ * 4)	/* 4s */  struct ionic_dev_bar {  	void __iomem *vaddr; diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index aa0cc31dfe6e..86774d9922d8 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -3220,7 +3220,7 @@ int ionic_lif_alloc(struct ionic *ionic)  	netdev->netdev_ops = &ionic_netdev_ops;  	ionic_ethtool_set_ops(netdev); -	netdev->watchdog_timeo = 2 * HZ; +	netdev->watchdog_timeo = 5 * HZ;  	netif_carrier_off(netdev);  	lif->identity = lid; diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c index 3e51b3a9b0a5..e3451beed323 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c @@ -1452,6 +1452,7 @@ static const struct prueth_pdata am654_icssg_pdata = {  static const struct prueth_pdata am64x_icssg_pdata = {  	.fdqring_mode = K3_RINGACC_RING_MODE_RING, +	.quirk_10m_link_issue = 1,  	.switch_mode = 1,  }; diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 0696faf60013..2e94d10348cc 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -1653,7 +1653,7 @@ static struct sock *gtp_encap_enable_socket(int fd, int type,  	sock = sockfd_lookup(fd, &err);  	if (!sock) {  		pr_debug("gtp socket fd=%d not found\n", fd); -		return NULL; +		return ERR_PTR(err);  	}  	sk = sock->sk; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 79774c8c7ff4..8c8880b44827 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -725,22 +725,25 @@ int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt)  				entry = &wifi_pkg->package.elements[entry_idx];  				entry_idx++;  				if (entry->type != ACPI_TYPE_INTEGER || -				    entry->integer.value > num_profiles) { +				    entry->integer.value > num_profiles || +				    entry->integer.value < +					rev_data[idx].min_profiles) {  					ret = -EINVAL;  					goto out_free;  				} -				num_profiles = entry->integer.value;  				/* -				 * this also validates >= min_profiles since we -				 * otherwise wouldn't have gotten the data when -				 * looking up in ACPI +				 * Check to see if we received package count +				 * same as max # of profiles  				 */  				if (wifi_pkg->package.count !=  				    hdr_size + profile_size * num_profiles) {  					ret = -EINVAL;  					goto out_free;  				} + +				/* Number of valid profiles */ +				num_profiles = entry->integer.value;  			}  			goto read_table;  		} diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index fa57df336785..fb2ea38e89ac 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -3348,7 +3348,7 @@ void iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt,  {  	int ret __maybe_unused = 0; -	if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) +	if (!iwl_trans_fw_running(fwrt->trans))  		return;  	if (fw_has_capa(&fwrt->fw->ucode_capa, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h index 595fa6ddf084..8ef5ed2db051 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h @@ -85,6 +85,10 @@ struct iwl_cfg;   *	May sleep   * @wimax_active: invoked when WiMax becomes active. May sleep   * @time_point: called when transport layer wants to collect debug data + * @device_powered_off: called upon resume from hibernation but not only. + *	Op_mode needs to reset its internal state because the device did not + *	survive the system state transition. The firmware is no longer running, + *	etc...   */  struct iwl_op_mode_ops {  	struct iwl_op_mode *(*start)(struct iwl_trans *trans, @@ -107,6 +111,7 @@ struct iwl_op_mode_ops {  	void (*time_point)(struct iwl_op_mode *op_mode,  			   enum iwl_fw_ini_time_point tp_id,  			   union iwl_dbg_tlv_tp_data *tp_data); +	void (*device_powered_off)(struct iwl_op_mode *op_mode);  };  int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops); @@ -204,4 +209,11 @@ static inline void iwl_op_mode_time_point(struct iwl_op_mode *op_mode,  	op_mode->ops->time_point(op_mode, tp_id, tp_data);  } +static inline void iwl_op_mode_device_powered_off(struct iwl_op_mode *op_mode) +{ +	if (!op_mode || !op_mode->ops || !op_mode->ops->device_powered_off) +		return; +	op_mode->ops->device_powered_off(op_mode); +} +  #endif /* __iwl_op_mode_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 6148acbac6af..0ef48effeefb 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1128,8 +1128,8 @@ static inline void iwl_trans_fw_error(struct iwl_trans *trans, bool sync)  	/* prevent double restarts due to the same erroneous FW */  	if (!test_and_set_bit(STATUS_FW_ERROR, &trans->status)) { -		iwl_op_mode_nic_error(trans->op_mode, sync);  		trans->state = IWL_TRANS_NO_FW; +		iwl_op_mode_nic_error(trans->op_mode, sync);  	}  } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index b4d650583ac2..99a541d442bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -3439,6 +3439,16 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)  	mutex_lock(&mvm->mutex); +	/* Apparently, the device went away and device_powered_off() was called, +	 * don't even try to read the rt_status, the device is currently +	 * inaccessible. +	 */ +	if (!test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status)) { +		IWL_INFO(mvm, +			 "Can't resume, device_powered_off() was called during wowlan\n"); +		goto err; +	} +  	mvm->last_reset_or_resume_time_jiffies = jiffies;  	/* get the BSS vif pointer again */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 835a05b91833..625ccf566e1c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -5818,6 +5818,10 @@ static void iwl_mvm_flush_no_vif(struct iwl_mvm *mvm, u32 queues, bool drop)  	int i;  	if (!iwl_mvm_has_new_tx_api(mvm)) { +		/* we can't ask the firmware anything if it is dead */ +		if (test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, +			     &mvm->status)) +			return;  		if (drop) {  			guard(mvm)(mvm);  			iwl_mvm_flush_tx_path(mvm, @@ -5911,8 +5915,11 @@ void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,  	/* this can take a while, and we may need/want other operations  	 * to succeed while doing this, so do it without the mutex held +	 * If the firmware is dead, this can't work...  	 */ -	if (!drop && !iwl_mvm_has_new_tx_api(mvm)) +	if (!drop && !iwl_mvm_has_new_tx_api(mvm) && +	    !test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, +		      &mvm->status))  		iwl_trans_wait_tx_queues_empty(mvm->trans, msk);  } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index b7dcae76a05d..b9daaffd9c7f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1198,10 +1198,12 @@ static void iwl_mvm_trig_link_selection(struct wiphy *wiphy,  	struct iwl_mvm *mvm =  		container_of(wk, struct iwl_mvm, trig_link_selection_wk); +	mutex_lock(&mvm->mutex);  	ieee80211_iterate_active_interfaces(mvm->hw,  					    IEEE80211_IFACE_ITER_NORMAL,  					    iwl_mvm_find_link_selection_vif,  					    NULL); +	mutex_unlock(&mvm->mutex);  }  static struct iwl_op_mode * @@ -1511,6 +1513,8 @@ void iwl_mvm_stop_device(struct iwl_mvm *mvm)  	clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); +	iwl_mvm_pause_tcm(mvm, false); +  	iwl_fw_dbg_stop_sync(&mvm->fwrt);  	iwl_trans_stop_device(mvm->trans);  	iwl_free_fw_paging(&mvm->fwrt); @@ -2090,6 +2094,20 @@ static void iwl_op_mode_mvm_time_point(struct iwl_op_mode *op_mode,  	iwl_dbg_tlv_time_point(&mvm->fwrt, tp_id, tp_data);  } +static void iwl_op_mode_mvm_device_powered_off(struct iwl_op_mode *op_mode) +{ +	struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + +	mutex_lock(&mvm->mutex); +	clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status); +	mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED; +	iwl_mvm_stop_device(mvm); +#ifdef CONFIG_PM +	mvm->fast_resume = false; +#endif +	mutex_unlock(&mvm->mutex); +} +  #define IWL_MVM_COMMON_OPS					\  	/* these could be differentiated */			\  	.queue_full = iwl_mvm_stop_sw_queue,			\ @@ -2102,7 +2120,8 @@ static void iwl_op_mode_mvm_time_point(struct iwl_op_mode *op_mode,  	/* as we only register one, these MUST be common! */	\  	.start = iwl_op_mode_mvm_start,				\  	.stop = iwl_op_mode_mvm_stop,				\ -	.time_point = iwl_op_mode_mvm_time_point +	.time_point = iwl_op_mode_mvm_time_point,		\ +	.device_powered_off = iwl_op_mode_mvm_device_powered_off  static const struct iwl_op_mode_ops iwl_mvm_ops = {  	IWL_MVM_COMMON_OPS, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 8e0df31f1b3e..1cc9c426bb15 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -48,6 +48,8 @@  /* Number of iterations on the channel for mei filtered scan */  #define IWL_MEI_SCAN_NUM_ITER	5U +#define WFA_TPC_IE_LEN	9 +  struct iwl_mvm_scan_timing_params {  	u32 suspend_time;  	u32 max_out_time; @@ -303,8 +305,8 @@ static int iwl_mvm_max_scan_ie_fw_cmd_room(struct iwl_mvm *mvm)  	max_probe_len = SCAN_OFFLOAD_PROBE_REQ_SIZE; -	/* we create the 802.11 header and SSID element */ -	max_probe_len -= 24 + 2; +	/* we create the 802.11 header SSID element and WFA TPC element */ +	max_probe_len -= 24 + 2 + WFA_TPC_IE_LEN;  	/* DS parameter set element is added on 2.4GHZ band if required */  	if (iwl_mvm_rrm_scan_needed(mvm)) @@ -731,8 +733,6 @@ static u8 *iwl_mvm_copy_and_insert_ds_elem(struct iwl_mvm *mvm, const u8 *ies,  	return newpos;  } -#define WFA_TPC_IE_LEN	9 -  static void iwl_mvm_add_tpc_report_ie(u8 *pos)  {  	pos[0] = WLAN_EID_VENDOR_SPECIFIC; @@ -837,8 +837,8 @@ static inline bool iwl_mvm_scan_fits(struct iwl_mvm *mvm, int n_ssids,  	return ((n_ssids <= PROBE_OPTION_MAX) &&  		(n_channels <= mvm->fw->ucode_capa.n_scan_channels) &  		(ies->common_ie_len + -		 ies->len[NL80211_BAND_2GHZ] + -		 ies->len[NL80211_BAND_5GHZ] <= +		 ies->len[NL80211_BAND_2GHZ] + ies->len[NL80211_BAND_5GHZ] + +		 ies->len[NL80211_BAND_6GHZ] <=  		 iwl_mvm_max_scan_ie_fw_cmd_room(mvm)));  } @@ -1659,6 +1659,17 @@ iwl_mvm_umac_scan_cfg_channels_v7(struct iwl_mvm *mvm,  		cfg->v2.channel_num = channels[i]->hw_value;  		if (cfg80211_channel_is_psc(channels[i]))  			cfg->flags = 0; + +		if (band == NL80211_BAND_6GHZ) { +			/* 6 GHz channels should only appear in a scan request +			 * that has scan_6ghz set. The only exception is MLO +			 * scan, which has to be passive. +			 */ +			WARN_ON_ONCE(cfg->flags != 0); +			cfg->flags = +				cpu_to_le32(IWL_UHB_CHAN_CFG_FLAG_FORCE_PASSIVE); +		} +  		cfg->v2.iter_count = 1;  		cfg->v2.iter_interval = 0;  		if (version < 17) @@ -3168,18 +3179,16 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,  		params.n_channels = j;  	} -	if (non_psc_included && -	    !iwl_mvm_scan_fits(mvm, req->n_ssids, ies, params.n_channels)) { -		kfree(params.channels); -		return -ENOBUFS; +	if (!iwl_mvm_scan_fits(mvm, req->n_ssids, ies, params.n_channels)) { +		ret = -ENOBUFS; +		goto out;  	}  	uid = iwl_mvm_build_scan_cmd(mvm, vif, &hcmd, ¶ms, type); - -	if (non_psc_included) -		kfree(params.channels); -	if (uid < 0) -		return uid; +	if (uid < 0) { +		ret = uid; +		goto out; +	}  	ret = iwl_mvm_send_cmd(mvm, &hcmd);  	if (!ret) { @@ -3197,6 +3206,9 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,  		mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED;  	} +out: +	if (non_psc_included) +		kfree(params.channels);  	return ret;  } diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c index e63efbf809f0..ae93a72542b2 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-gen3.c @@ -89,7 +89,8 @@ iwl_pcie_ctxt_info_dbg_enable(struct iwl_trans *trans,  		}  		break;  	default: -		IWL_ERR(trans, "WRT: Invalid buffer destination\n"); +		IWL_DEBUG_FW(trans, "WRT: Invalid buffer destination (%d)\n", +			     le32_to_cpu(fw_mon_cfg->buf_location));  	}  out:  	if (dbg_flags) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 9ad43464b702..84fd93278450 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1577,11 +1577,12 @@ static int iwl_pci_suspend(struct device *device)  	return 0;  } -static int iwl_pci_resume(struct device *device) +static int _iwl_pci_resume(struct device *device, bool restore)  {  	struct pci_dev *pdev = to_pci_dev(device);  	struct iwl_trans *trans = pci_get_drvdata(pdev);  	struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); +	bool device_was_powered_off = false;  	/* Before you put code here, think about WoWLAN. You cannot check here  	 * whether WoWLAN is enabled or not, and your code will run even if @@ -1597,6 +1598,26 @@ static int iwl_pci_resume(struct device *device)  	if (!trans->op_mode)  		return 0; +	/* +	 * Scratch value was altered, this means the device was powered off, we +	 * need to reset it completely. +	 * Note: MAC (bits 0:7) will be cleared upon suspend even with wowlan, +	 * so assume that any bits there mean that the device is usable. +	 */ +	if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ && +	    !iwl_read32(trans, CSR_FUNC_SCRATCH)) +		device_was_powered_off = true; + +	if (restore || device_was_powered_off) { +		trans->state = IWL_TRANS_NO_FW; +		/* Hope for the best here ... If one of those steps fails we +		 * won't really know how to recover. +		 */ +		iwl_pcie_prepare_card_hw(trans); +		iwl_finish_nic_init(trans); +		iwl_op_mode_device_powered_off(trans->op_mode); +	} +  	/* In WOWLAN, let iwl_trans_pcie_d3_resume do the rest of the work */  	if (test_bit(STATUS_DEVICE_ENABLED, &trans->status))  		return 0; @@ -1617,9 +1638,23 @@ static int iwl_pci_resume(struct device *device)  	return 0;  } +static int iwl_pci_restore(struct device *device) +{ +	return _iwl_pci_resume(device, true); +} + +static int iwl_pci_resume(struct device *device) +{ +	return _iwl_pci_resume(device, false); +} +  static const struct dev_pm_ops iwl_dev_pm_ops = { -	SET_SYSTEM_SLEEP_PM_OPS(iwl_pci_suspend, -				iwl_pci_resume) +	.suspend = pm_sleep_ptr(iwl_pci_suspend), +	.resume = pm_sleep_ptr(iwl_pci_resume), +	.freeze = pm_sleep_ptr(iwl_pci_suspend), +	.thaw = pm_sleep_ptr(iwl_pci_resume), +	.poweroff = pm_sleep_ptr(iwl_pci_suspend), +	.restore = pm_sleep_ptr(iwl_pci_restore),  };  #define IWL_PM_OPS	(&iwl_dev_pm_ops) diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 155eb0fab12a..bf35c92f91d7 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -4363,11 +4363,27 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)  	if (ISSUPP_ADHOC_ENABLED(adapter->fw_cap_info))  		wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC); -	wiphy->bands[NL80211_BAND_2GHZ] = &mwifiex_band_2ghz; -	if (adapter->config_bands & BAND_A) -		wiphy->bands[NL80211_BAND_5GHZ] = &mwifiex_band_5ghz; -	else +	wiphy->bands[NL80211_BAND_2GHZ] = devm_kmemdup(adapter->dev, +						       &mwifiex_band_2ghz, +						       sizeof(mwifiex_band_2ghz), +						       GFP_KERNEL); +	if (!wiphy->bands[NL80211_BAND_2GHZ]) { +		ret = -ENOMEM; +		goto err; +	} + +	if (adapter->config_bands & BAND_A) { +		wiphy->bands[NL80211_BAND_5GHZ] = devm_kmemdup(adapter->dev, +							       &mwifiex_band_5ghz, +							       sizeof(mwifiex_band_5ghz), +							       GFP_KERNEL); +		if (!wiphy->bands[NL80211_BAND_5GHZ]) { +			ret = -ENOMEM; +			goto err; +		} +	} else {  		wiphy->bands[NL80211_BAND_5GHZ] = NULL; +	}  	if (adapter->drcs_enabled && ISSUPP_DRCS_ENABLED(adapter->fw_cap_info))  		wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta_drcs; @@ -4461,8 +4477,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)  	if (ret < 0) {  		mwifiex_dbg(adapter, ERROR,  			    "%s: wiphy_register failed: %d\n", __func__, ret); -		wiphy_free(wiphy); -		return ret; +		goto err;  	}  	if (!adapter->regd) { @@ -4504,4 +4519,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)  	adapter->wiphy = wiphy;  	return ret; + +err: +	wiphy_free(wiphy); + +	return ret;  } diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index 216d43c8bd6e..7c04810dbf3d 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -352,8 +352,11 @@ static int wfx_set_mfp_ap(struct wfx_vif *wvif)  	ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN, skb->data + ieoffset,  				      skb->len - ieoffset); -	if (unlikely(!ptr)) +	if (!ptr) { +		/* No RSN IE is fine in open networks */ +		ret = 0;  		goto free_skb; +	}  	ptr += pairwise_cipher_suite_count_offset;  	if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) | 
