drivers/net/wireless/silabs/wfx/fwio.c

Source file repositories/reference/linux-study-clean/drivers/net/wireless/silabs/wfx/fwio.c

File Facts

System
Linux kernel
Corpus path
drivers/net/wireless/silabs/wfx/fwio.c
Extension
.c
Size
11444 bytes
Lines
390
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (ret) {
			dev_err(wdev->dev, "can't load %s\n", filename);
			*fw = NULL;
			return ret;
		}
	}

	data = (*fw)->data;
	if (memcmp(data, "KEYSET", 6) != 0) {
		/* Legacy firmware format */
		*file_offset = 0;
		keyset_file = 0x90;
	} else {
		*file_offset = 8;
		keyset_file = (hex_to_bin(data[6]) * 16) | hex_to_bin(data[7]);
		if (keyset_file < 0) {
			dev_err(wdev->dev, "%s corrupted\n", filename);
			release_firmware(*fw);
			*fw = NULL;
			return -EINVAL;
		}
	}
	if (keyset_file != keyset_chip) {
		dev_err(wdev->dev, "firmware keyset is incompatible with chip (file: 0x%02X, chip: 0x%02X)\n",
			keyset_file, keyset_chip);
		release_firmware(*fw);
		*fw = NULL;
		return -ENODEV;
	}
	wdev->keyset = keyset_file;
	return 0;
}

static int wait_ncp_status(struct wfx_dev *wdev, u32 status)
{
	ktime_t now, start;
	u32 reg;
	int ret;

	start = ktime_get();
	for (;;) {
		ret = wfx_sram_reg_read(wdev, WFX_DCA_NCP_STATUS, &reg);
		if (ret < 0)
			return -EIO;
		now = ktime_get();
		if (reg == status)
			break;
		if (ktime_after(now, ktime_add_ms(start, DCA_TIMEOUT)))
			return -ETIMEDOUT;
	}
	if (ktime_compare(now, start))
		dev_dbg(wdev->dev, "chip answer after %lldus\n", ktime_us_delta(now, start));
	else
		dev_dbg(wdev->dev, "chip answer immediately\n");
	return 0;
}

static int upload_firmware(struct wfx_dev *wdev, const u8 *data, size_t len)
{
	int ret;
	u32 offs, bytes_done = 0;
	ktime_t now, start;

	if (len % DNLD_BLOCK_SIZE) {
		dev_err(wdev->dev, "firmware size is not aligned. Buffer overrun will occur\n");
		return -EIO;
	}
	offs = 0;
	while (offs < len) {
		start = ktime_get();
		for (;;) {
			now = ktime_get();
			if (offs + DNLD_BLOCK_SIZE - bytes_done < DNLD_FIFO_SIZE)
				break;
			if (ktime_after(now, ktime_add_ms(start, DCA_TIMEOUT)))
				return -ETIMEDOUT;
			ret = wfx_sram_reg_read(wdev, WFX_DCA_GET, &bytes_done);
			if (ret < 0)
				return ret;
		}
		if (ktime_compare(now, start))
			dev_dbg(wdev->dev, "answer after %lldus\n", ktime_us_delta(now, start));

		ret = wfx_sram_write_dma_safe(wdev, WFX_DNLD_FIFO + (offs % DNLD_FIFO_SIZE),
					      data + offs, DNLD_BLOCK_SIZE);
		if (ret < 0)
			return ret;

		/* The device seems to not support writing 0 in this register during first loop */
		offs += DNLD_BLOCK_SIZE;

Annotation

Implementation Notes