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

Commit 70458259 authored by Andrey Borzenkov's avatar Andrey Borzenkov Committed by John W. Linville
Browse files

orinoco: reduce stack usage in firmware download path



orinoco_dl_firmware and symbol_dl_mage allocate large local
variables (1K); at least orinoco fails with panic or hung
kernel if 4K stacks is enabled.

Allocate large buffers dynamically at run time.

Tested-By: Andrey Borzenkov <arvidjaar@mail.ru> for Agere case

Signed-off-by: default avatarAndrey Borzenkov &lt; <arvidjaar@mail.ru>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 8bdd5b9c
Loading
Loading
Loading
Loading
+29 −13
Original line number Diff line number Diff line
@@ -433,7 +433,7 @@ struct fw_info {
const static struct fw_info orinoco_fw[] = {
	{ "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 },
	{ "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 },
	{ "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 0x100 }
	{ "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 }
};

/* Structure used to access fields in FW
@@ -458,7 +458,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
		    int ap)
{
	/* Plug Data Area (PDA) */
	__le16 pda[512] = { 0 };
	__le16 *pda;

	hermes_t *hw = &priv->hw;
	const struct firmware *fw_entry;
@@ -467,7 +467,11 @@ orinoco_dl_firmware(struct orinoco_private *priv,
	const unsigned char *end;
	const char *firmware;
	struct net_device *dev = priv->ndev;
	int err;
	int err = 0;

	pda = kzalloc(fw->pda_size, GFP_KERNEL);
	if (!pda)
		return -ENOMEM;

	if (ap)
		firmware = fw->ap_fw;
@@ -478,17 +482,17 @@ orinoco_dl_firmware(struct orinoco_private *priv,
	       dev->name, firmware);

	/* Read current plug data */
	err = hermes_read_pda(hw, pda, fw->pda_addr,
			      min_t(u16, fw->pda_size, sizeof(pda)), 0);
	err = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 0);
	printk(KERN_DEBUG "%s: Read PDA returned %d\n", dev->name, err);
	if (err)
		return err;
		goto free;

	err = request_firmware(&fw_entry, firmware, priv->dev);
	if (err) {
		printk(KERN_ERR "%s: Cannot find firmware %s\n",
		       dev->name, firmware);
		return -ENOENT;
		err = -ENOENT;
		goto free;
	}

	hdr = (const struct orinoco_fw_header *) fw_entry->data;
@@ -532,6 +536,9 @@ orinoco_dl_firmware(struct orinoco_private *priv,

abort:
	release_firmware(fw_entry);

free:
	kfree(pda);
	return err;
}

@@ -549,12 +556,12 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
		int secondary)
{
	hermes_t *hw = &priv->hw;
	int ret;
	int ret = 0;
	const unsigned char *ptr;
	const unsigned char *first_block;

	/* Plug Data Area (PDA) */
	__le16 pda[256];
	__le16 *pda = NULL;

	/* Binary block begins after the 0x1A marker */
	ptr = image;
@@ -563,28 +570,33 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,

	/* Read the PDA from EEPROM */
	if (secondary) {
		ret = hermes_read_pda(hw, pda, fw->pda_addr, sizeof(pda), 1);
		pda = kzalloc(fw->pda_size, GFP_KERNEL);
		if (!pda)
			return -ENOMEM;

		ret = hermes_read_pda(hw, pda, fw->pda_addr, fw->pda_size, 1);
		if (ret)
			return ret;
			goto free;
	}

	/* Stop the firmware, so that it can be safely rewritten */
	if (priv->stop_fw) {
		ret = priv->stop_fw(priv, 1);
		if (ret)
			return ret;
			goto free;
	}

	/* Program the adapter with new firmware */
	ret = hermes_program(hw, first_block, end);
	if (ret)
		return ret;
		goto free;

	/* Write the PDA to the adapter */
	if (secondary) {
		size_t len = hermes_blocks_length(first_block);
		ptr = first_block + len;
		ret = hermes_apply_pda(hw, ptr, pda);
		kfree(pda);
		if (ret)
			return ret;
	}
@@ -608,6 +620,10 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
		return -ENODEV;

	return 0;

free:
	kfree(pda);
	return ret;
}