Esempio n. 1
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;
}
Esempio n. 2
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);
	u32 state = QTN_RC_FW_LOADRDY | QTN_RC_FW_QLINK;
	const char *fwname = QTN_PCI_PEARL_FW_NAME;
	struct pci_dev *pdev = ps->base.pdev;
	const struct firmware *fw;
	int ret;

	if (ps->base.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 (!ps->base.flashboot)
			release_firmware(fw);

		goto fw_load_exit;
	}

	qtnf_clear_state(&ps->bda->bda_ep_state, QTN_EP_FW_LOADRDY);

	if (ps->base.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;
	}

	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;
	}

	pr_info("firmware is up and running\n");

	ret = qtnf_pcie_fw_boot_done(bus);
	if (ret)
		goto fw_load_exit;

	qtnf_debugfs_add_entry(bus, "hdp_stats", qtnf_dbg_hdp_stats);
	qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats);

fw_load_exit:
	put_device(&pdev->dev);
}
Esempio n. 3
0
File: pcie.c Progetto: Lyude/linux
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);
}