Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d32d2ce authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "wil6210: prevent parallel suspend and dump collection"

parents d7d7dc83 54bf5d5d
Loading
Loading
Loading
Loading
+11 −3
Original line number Diff line number Diff line
@@ -973,7 +973,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
			 u64 *cookie)
{
	const u8 *buf = params->buf;
	size_t len = params->len;
	size_t len = params->len, total;
	struct wil6210_priv *wil = wiphy_to_wil(wiphy);
	int rc;
	bool tx_status = false;
@@ -998,7 +998,11 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
	if (len < sizeof(struct ieee80211_hdr_3addr))
		return -EINVAL;

	cmd = kmalloc(sizeof(*cmd) + len, GFP_KERNEL);
	total = sizeof(*cmd) + len;
	if (total < len)
		return -EINVAL;

	cmd = kmalloc(total, GFP_KERNEL);
	if (!cmd) {
		rc = -ENOMEM;
		goto out;
@@ -1008,7 +1012,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
	cmd->len = cpu_to_le16(len);
	memcpy(cmd->payload, buf, len);

	rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, sizeof(*cmd) + len,
	rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, total,
		      WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000);
	if (rc == 0)
		tx_status = !evt.evt.status;
@@ -1799,9 +1803,13 @@ static int wil_cfg80211_suspend(struct wiphy *wiphy,

	wil_dbg_pm(wil, "suspending\n");

	mutex_lock(&wil->mutex);
	wil_p2p_stop_discovery(wil);

	mutex_lock(&wil->p2p_wdev_mutex);
	wil_abort_scan(wil, true);
	mutex_unlock(&wil->p2p_wdev_mutex);
	mutex_unlock(&wil->mutex);

out:
	return rc;
+89 −7
Original line number Diff line number Diff line
@@ -242,12 +242,19 @@ static void wil_print_ring(struct seq_file *s, const char *prefix,
static int wil_mbox_debugfs_show(struct seq_file *s, void *data)
{
	struct wil6210_priv *wil = s->private;
	int ret;

	ret = wil_pm_runtime_get(wil);
	if (ret < 0)
		return ret;

	wil_print_ring(s, "tx", wil->csr + HOST_MBOX +
		       offsetof(struct wil6210_mbox_ctl, tx));
	wil_print_ring(s, "rx", wil->csr + HOST_MBOX +
		       offsetof(struct wil6210_mbox_ctl, rx));

	wil_pm_runtime_put(wil);

	return 0;
}

@@ -265,15 +272,38 @@ static const struct file_operations fops_mbox = {

static int wil_debugfs_iomem_x32_set(void *data, u64 val)
{
	writel(val, (void __iomem *)data);
	struct wil_debugfs_iomem_data *d = (struct
					    wil_debugfs_iomem_data *)data;
	struct wil6210_priv *wil = d->wil;
	int ret;

	ret = wil_pm_runtime_get(wil);
	if (ret < 0)
		return ret;

	writel_relaxed(val, (void __iomem *)d->offset);

	wmb(); /* make sure write propagated to HW */

	wil_pm_runtime_put(wil);

	return 0;
}

static int wil_debugfs_iomem_x32_get(void *data, u64 *val)
{
	*val = readl((void __iomem *)data);
	struct wil_debugfs_iomem_data *d = (struct
					    wil_debugfs_iomem_data *)data;
	struct wil6210_priv *wil = d->wil;
	int ret;

	ret = wil_pm_runtime_get(wil);
	if (ret < 0)
		return ret;

	*val = readl_relaxed((void __iomem *)d->offset);

	wil_pm_runtime_put(wil);

	return 0;
}
@@ -284,10 +314,21 @@ DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, wil_debugfs_iomem_x32_get,
static struct dentry *wil_debugfs_create_iomem_x32(const char *name,
						   umode_t mode,
						   struct dentry *parent,
						   void *value)
						   void *value,
						   struct wil6210_priv *wil)
{
	return debugfs_create_file(name, mode, parent, value,
				   &fops_iomem_x32);
	struct dentry *file;
	struct wil_debugfs_iomem_data *data = &wil->dbg_data.data_arr[
					      wil->dbg_data.iomem_data_count];

	data->wil = wil;
	data->offset = value;

	file = debugfs_create_file(name, mode, parent, data, &fops_iomem_x32);
	if (!IS_ERR_OR_NULL(file))
		wil->dbg_data.iomem_data_count++;

	return file;
}

static int wil_debugfs_ulong_set(void *data, u64 val)
@@ -346,7 +387,8 @@ static void wil6210_debugfs_init_offset(struct wil6210_priv *wil,
		case doff_io32:
			f = wil_debugfs_create_iomem_x32(tbl[i].name,
							 tbl[i].mode, dbg,
							 base + tbl[i].off);
							 base + tbl[i].off,
							 wil);
			break;
		case doff_u8:
			f = debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg,
@@ -475,13 +517,22 @@ static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
static int wil_memread_debugfs_show(struct seq_file *s, void *data)
{
	struct wil6210_priv *wil = s->private;
	void __iomem *a = wmi_buffer(wil, cpu_to_le32(mem_addr));
	void __iomem *a;
	int ret;

	ret = wil_pm_runtime_get(wil);
	if (ret < 0)
		return ret;

	a = wmi_buffer(wil, cpu_to_le32(mem_addr));

	if (a)
		seq_printf(s, "[0x%08x] = 0x%08x\n", mem_addr, readl(a));
	else
		seq_printf(s, "[0x%08x] = INVALID\n", mem_addr);

	wil_pm_runtime_put(wil);

	return 0;
}

@@ -502,10 +553,12 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
{
	enum { max_count = 4096 };
	struct wil_blob_wrapper *wil_blob = file->private_data;
	struct wil6210_priv *wil = wil_blob->wil;
	loff_t pos = *ppos;
	size_t available = wil_blob->blob.size;
	void *buf;
	size_t ret;
	int rc;

	if (test_bit(wil_status_suspending, wil_blob->wil->status) ||
	    test_bit(wil_status_suspended, wil_blob->wil->status))
@@ -526,10 +579,19 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf,
	if (!buf)
		return -ENOMEM;

	rc = wil_pm_runtime_get(wil);
	if (rc < 0) {
		kfree(buf);
		return rc;
	}

	wil_memcpy_fromio_32(buf, (const void __iomem *)
			     wil_blob->blob.data + pos, count);

	ret = copy_to_user(user_buf, buf, count);

	wil_pm_runtime_put(wil);

	kfree(buf);
	if (ret == count)
		return -EFAULT;
@@ -1781,6 +1843,13 @@ static const struct dbg_off dbg_statics[] = {
	{},
};

static const int dbg_off_count = 4 * (ARRAY_SIZE(isr_off) - 1) +
				ARRAY_SIZE(dbg_wil_regs) - 1 +
				ARRAY_SIZE(pseudo_isr_off) - 1 +
				ARRAY_SIZE(lgc_itr_cnt_off) - 1 +
				ARRAY_SIZE(tx_itr_cnt_off) - 1 +
				ARRAY_SIZE(rx_itr_cnt_off) - 1;

int wil6210_debugfs_init(struct wil6210_priv *wil)
{
	struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME,
@@ -1789,6 +1858,17 @@ int wil6210_debugfs_init(struct wil6210_priv *wil)
	if (IS_ERR_OR_NULL(dbg))
		return -ENODEV;

	wil->dbg_data.data_arr = kcalloc(dbg_off_count,
					 sizeof(struct wil_debugfs_iomem_data),
					 GFP_KERNEL);
	if (!wil->dbg_data.data_arr) {
		debugfs_remove_recursive(dbg);
		wil->debug = NULL;
		return -ENOMEM;
	}

	wil->dbg_data.iomem_data_count = 0;

	wil_pmc_init(wil);

	wil6210_debugfs_init_files(wil, dbg);
@@ -1813,6 +1893,8 @@ void wil6210_debugfs_remove(struct wil6210_priv *wil)
	debugfs_remove_recursive(wil->debug);
	wil->debug = NULL;

	kfree(wil->dbg_data.data_arr);

	/* free pmc memory without sending command to fw, as it will
	 * be reset on the way down anyway
	 */
+15 −0
Original line number Diff line number Diff line
@@ -47,9 +47,14 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev,
	struct wil6210_priv *wil = ndev_to_wil(ndev);
	u32 tx_itr_en, tx_itr_val = 0;
	u32 rx_itr_en, rx_itr_val = 0;
	int ret;

	wil_dbg_misc(wil, "ethtoolops_get_coalesce\n");

	ret = wil_pm_runtime_get(wil);
	if (ret < 0)
		return ret;

	tx_itr_en = wil_r(wil, RGF_DMA_ITR_TX_CNT_CTL);
	if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN)
		tx_itr_val = wil_r(wil, RGF_DMA_ITR_TX_CNT_TRSH);
@@ -58,6 +63,8 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev,
	if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN)
		rx_itr_val = wil_r(wil, RGF_DMA_ITR_RX_CNT_TRSH);

	wil_pm_runtime_put(wil);

	cp->tx_coalesce_usecs = tx_itr_val;
	cp->rx_coalesce_usecs = rx_itr_val;
	return 0;
@@ -67,6 +74,7 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev,
				       struct ethtool_coalesce *cp)
{
	struct wil6210_priv *wil = ndev_to_wil(ndev);
	int ret;

	wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n",
		     cp->rx_coalesce_usecs, cp->tx_coalesce_usecs);
@@ -86,8 +94,15 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev,

	wil->tx_max_burst_duration = cp->tx_coalesce_usecs;
	wil->rx_max_burst_duration = cp->rx_coalesce_usecs;

	ret = wil_pm_runtime_get(wil);
	if (ret < 0)
		return ret;

	wil_configure_interrupt_moderation(wil);

	wil_pm_runtime_put(wil);

	return 0;

out_bad:
+46 −33
Original line number Diff line number Diff line
@@ -26,14 +26,17 @@
					     prefix_type, rowsize,	\
					     groupsize, buf, len, ascii)

#define FW_ADDR_CHECK(ioaddr, val, msg) do { \
		ioaddr = wmi_buffer(wil, val); \
		if (!ioaddr) { \
			wil_err_fw(wil, "bad " msg ": 0x%08x\n", \
				   le32_to_cpu(val)); \
			return -EINVAL; \
		} \
	} while (0)
static bool wil_fw_addr_check(struct wil6210_priv *wil,
			      void __iomem **ioaddr, __le32 val,
			      u32 size, const char *msg)
{
	*ioaddr = wmi_buffer_block(wil, val, size);
	if (!(*ioaddr)) {
		wil_err_fw(wil, "bad %s: 0x%08x\n", msg, le32_to_cpu(val));
		return false;
	}
	return true;
}

/**
 * wil_fw_verify - verify firmware file validity
@@ -124,24 +127,19 @@ static int fw_ignore_section(struct wil6210_priv *wil, const void *data,
	return 0;
}

static int fw_handle_comment(struct wil6210_priv *wil, const void *data,
			     size_t size)
{
	wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, data, size, true);

	return 0;
}

static int
fw_handle_capabilities(struct wil6210_priv *wil, const void *data,
fw_handle_comment(struct wil6210_priv *wil, const void *data,
		  size_t size)
{
	const struct wil_fw_record_capabilities *rec = data;
	size_t capa_size;

	if (size < sizeof(*rec) ||
	    le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC)
	    le32_to_cpu(rec->magic) != WIL_FW_CAPABILITIES_MAGIC) {
		wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
				data, size, true);
		return 0;
	}

	capa_size = size - offsetof(struct wil_fw_record_capabilities,
				    capabilities);
@@ -165,7 +163,8 @@ static int fw_handle_data(struct wil6210_priv *wil, const void *data,
		return -EINVAL;
	}

	FW_ADDR_CHECK(dst, d->addr, "address");
	if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address"))
		return -EINVAL;
	wil_dbg_fw(wil, "write [0x%08x] <== %zu bytes\n", le32_to_cpu(d->addr),
		   s);
	wil_memcpy_toio_32(dst, d->data, s);
@@ -197,7 +196,8 @@ static int fw_handle_fill(struct wil6210_priv *wil, const void *data,
		return -EINVAL;
	}

	FW_ADDR_CHECK(dst, d->addr, "address");
	if (!wil_fw_addr_check(wil, &dst, d->addr, s, "address"))
		return -EINVAL;

	v = le32_to_cpu(d->value);
	wil_dbg_fw(wil, "fill [0x%08x] <== 0x%08x, %zu bytes\n",
@@ -253,7 +253,8 @@ static int fw_handle_direct_write(struct wil6210_priv *wil, const void *data,
		u32 v = le32_to_cpu(block[i].value);
		u32 x, y;

		FW_ADDR_CHECK(dst, block[i].addr, "address");
		if (!wil_fw_addr_check(wil, &dst, block[i].addr, 0, "address"))
			return -EINVAL;

		x = readl(dst);
		y = (x & m) | (v & ~m);
@@ -319,10 +320,15 @@ static int fw_handle_gateway_data(struct wil6210_priv *wil, const void *data,
	wil_dbg_fw(wil, "gw write record [%3d] blocks, cmd 0x%08x\n",
		   n, gw_cmd);

	FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr");
	FW_ADDR_CHECK(gwa_val, d->gateway_value_addr, "gateway_value_addr");
	FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
	FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
	if (!wil_fw_addr_check(wil, &gwa_addr, d->gateway_addr_addr, 0,
			       "gateway_addr_addr") ||
	    !wil_fw_addr_check(wil, &gwa_val, d->gateway_value_addr, 0,
			       "gateway_value_addr") ||
	    !wil_fw_addr_check(wil, &gwa_cmd, d->gateway_cmd_addr, 0,
			       "gateway_cmd_addr") ||
	    !wil_fw_addr_check(wil, &gwa_ctl, d->gateway_ctrl_address, 0,
			       "gateway_ctrl_address"))
		return -EINVAL;

	wil_dbg_fw(wil, "gw addresses: addr 0x%08x val 0x%08x"
		   " cmd 0x%08x ctl 0x%08x\n",
@@ -378,12 +384,19 @@ static int fw_handle_gateway_data4(struct wil6210_priv *wil, const void *data,
	wil_dbg_fw(wil, "gw4 write record [%3d] blocks, cmd 0x%08x\n",
		   n, gw_cmd);

	FW_ADDR_CHECK(gwa_addr, d->gateway_addr_addr, "gateway_addr_addr");
	if (!wil_fw_addr_check(wil, &gwa_addr, d->gateway_addr_addr, 0,
			       "gateway_addr_addr"))
		return -EINVAL;
	for (k = 0; k < ARRAY_SIZE(block->value); k++)
		FW_ADDR_CHECK(gwa_val[k], d->gateway_value_addr[k],
			      "gateway_value_addr");
	FW_ADDR_CHECK(gwa_cmd, d->gateway_cmd_addr, "gateway_cmd_addr");
	FW_ADDR_CHECK(gwa_ctl, d->gateway_ctrl_address, "gateway_ctrl_address");
		if (!wil_fw_addr_check(wil, &gwa_val[k],
				       d->gateway_value_addr[k],
				       0, "gateway_value_addr"))
			return -EINVAL;
	if (!wil_fw_addr_check(wil, &gwa_cmd, d->gateway_cmd_addr, 0,
			       "gateway_cmd_addr") ||
	    !wil_fw_addr_check(wil, &gwa_ctl, d->gateway_ctrl_address, 0,
			       "gateway_ctrl_address"))
		return -EINVAL;

	wil_dbg_fw(wil, "gw4 addresses: addr 0x%08x cmd 0x%08x ctl 0x%08x\n",
		   le32_to_cpu(d->gateway_addr_addr),
@@ -422,7 +435,7 @@ static const struct {
	int (*parse_handler)(struct wil6210_priv *wil, const void *data,
			     size_t size);
} wil_fw_handlers[] = {
	{wil_fw_type_comment, fw_handle_comment, fw_handle_capabilities},
	{wil_fw_type_comment, fw_handle_comment, fw_handle_comment},
	{wil_fw_type_data, fw_handle_data, fw_ignore_section},
	{wil_fw_type_fill, fw_handle_fill, fw_ignore_section},
	/* wil_fw_type_action */
@@ -517,7 +530,7 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name,

	rc = request_firmware(&fw, name, wil_to_dev(wil));
	if (rc) {
		wil_err_fw(wil, "Failed to load firmware %s\n", name);
		wil_err_fw(wil, "Failed to load firmware %s rc %d\n", name, rc);
		return rc;
	}
	wil_dbg_fw(wil, "Loading <%s>, %zu bytes\n", name, fw->size);
+21 −1
Original line number Diff line number Diff line
@@ -358,6 +358,25 @@ static void wil_cache_mbox_regs(struct wil6210_priv *wil)
	wil_mbox_ring_le2cpus(&wil->mbox_ctl.tx);
}

static bool wil_validate_mbox_regs(struct wil6210_priv *wil)
{
	size_t min_size = sizeof(struct wil6210_mbox_hdr) +
		sizeof(struct wmi_cmd_hdr);

	if (wil->mbox_ctl.rx.entry_size < min_size) {
		wil_err(wil, "rx mbox entry too small (%d)\n",
			wil->mbox_ctl.rx.entry_size);
		return false;
	}
	if (wil->mbox_ctl.tx.entry_size < min_size) {
		wil_err(wil, "tx mbox entry too small (%d)\n",
			wil->mbox_ctl.tx.entry_size);
		return false;
	}

	return true;
}

static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
{
	struct wil6210_priv *wil = cookie;
@@ -393,6 +412,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
	if (isr & ISR_MISC_FW_READY) {
		wil_dbg_irq(wil, "IRQ: FW ready\n");
		wil_cache_mbox_regs(wil);
		if (wil_validate_mbox_regs(wil))
			set_bit(wil_status_mbox_ready, wil->status);
		/**
		 * Actual FW ready indicated by the
Loading