Esempio n. 1
0
static int carl9170_check_sequence(struct ar9170 *ar, unsigned int seq)
{
	if (ar->cmd_seq < -1)
		return 0;

	/*
	 * Initialize Counter
	 */
	if (ar->cmd_seq < 0)
		ar->cmd_seq = seq;

	/*
	 * The sequence is strictly monotonic increasing and it never skips!
	 *
	 * Therefore we can safely assume that whenever we received an
	 * unexpected sequence we have lost some valuable data.
	 */
	if (seq != ar->cmd_seq) {
		int count;

		count = (seq - ar->cmd_seq) % ar->fw.cmd_bufs;

		wiphy_err(ar->hw->wiphy, "lost %d command responses/traps! "
			  "w:%d g:%d\n", count, ar->cmd_seq, seq);

		carl9170_restart(ar, CARL9170_RR_LOST_RSP);
		return -EIO;
	}

	ar->cmd_seq = (ar->cmd_seq + 1) % ar->fw.cmd_bufs;
	return 0;
}
Esempio n. 2
0
static void carl9170_dbg_message(struct ar9170 *ar, const char *buf, u32 len)
{
	bool restart = false;
	enum carl9170_restart_reasons reason = CARL9170_RR_NO_REASON;

	if (len > 3) {
		if (memcmp(buf, CARL9170_ERR_MAGIC, 3) == 0) {
			ar->fw.err_counter++;
			if (ar->fw.err_counter > 3) {
				restart = true;
				reason = CARL9170_RR_TOO_MANY_FIRMWARE_ERRORS;
			}
		}

		if (memcmp(buf, CARL9170_BUG_MAGIC, 3) == 0) {
			ar->fw.bug_counter++;
			restart = true;
			reason = CARL9170_RR_FATAL_FIRMWARE_ERROR;
		}
	}

	wiphy_info(ar->hw->wiphy, "FW: %.*s\n", len, buf);

	if (restart)
		carl9170_restart(ar, reason);
}
Esempio n. 3
0
static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer)
{
	/*
	 * Some commands may have a variable response length
	 * and we cannot predict the correct length in advance.
	 * So we only check if we provided enough space for the data.
	 */
	if (unlikely(ar->readlen != (len - 4))) {
		dev_warn(&ar->udev->dev, "received invalid command response:"
			 "got %d, instead of %d\n", len - 4, ar->readlen);
		print_hex_dump_bytes("carl9170 cmd:", DUMP_PREFIX_OFFSET,
			ar->cmd_buf, (ar->cmd.hdr.len + 4) & 0x3f);
		print_hex_dump_bytes("carl9170 rsp:", DUMP_PREFIX_OFFSET,
			buffer, len);
		/*
		 * Do not complete. The command times out,
		 * and we get a stack trace from there.
		 */
		carl9170_restart(ar, CARL9170_RR_INVALID_RSP);
	}

	spin_lock(&ar->cmd_lock);
	if (ar->readbuf) {
		if (len >= 4)
			memcpy(ar->readbuf, buffer + 4, len - 4);

		ar->readbuf = NULL;
	}
	complete(&ar->cmd_wait);
	spin_unlock(&ar->cmd_lock);
}
Esempio n. 4
0
int carl9170_exec_cmd(struct ar9170 *ar, const enum carl9170_cmd_oids cmd,
	unsigned int plen, void *payload, unsigned int outlen, void *out)
{
	int err = -ENOMEM;

	if (!IS_ACCEPTING_CMD(ar))
		return -EIO;

	if (!(cmd & CARL9170_CMD_ASYNC_FLAG))
		might_sleep();

	ar->cmd.hdr.len = plen;
	ar->cmd.hdr.cmd = cmd;
	/* writing multiple regs fills this buffer already */
	if (plen && payload != (u8 *)(ar->cmd.data))
		memcpy(ar->cmd.data, payload, plen);

	spin_lock_bh(&ar->cmd_lock);
	ar->readbuf = (u8 *)out;
	ar->readlen = outlen;
	spin_unlock_bh(&ar->cmd_lock);

	err = __carl9170_exec_cmd(ar, &ar->cmd, false);

	if (!(cmd & CARL9170_CMD_ASYNC_FLAG)) {
		err = wait_for_completion_timeout(&ar->cmd_wait, HZ);
		if (err == 0) {
			err = -ETIMEDOUT;
			goto err_unbuf;
		}

		if (ar->readlen != outlen) {
			err = -EMSGSIZE;
			goto err_unbuf;
		}
	}

	return 0;

err_unbuf:
	/* Maybe the device was removed in the moment we were waiting? */
	if (IS_STARTED(ar)) {
		dev_err(&ar->udev->dev, "no command feedback "
			"received (%d).\n", err);

		/* provide some maybe useful debug information */
		print_hex_dump_bytes("carl9170 cmd: ", DUMP_PREFIX_NONE,
				     &ar->cmd, plen + 4);

		carl9170_restart(ar, CARL9170_RR_COMMAND_TIMEOUT);
	}

	/* invalidate to avoid completing the next command prematurely */
	spin_lock_bh(&ar->cmd_lock);
	ar->readbuf = NULL;
	ar->readlen = 0;
	spin_unlock_bh(&ar->cmd_lock);

	return err;
}
Esempio n. 5
0
static void carl9170_usb_rx_complete(struct urb *urb)
{
	struct ar9170 *ar = (struct ar9170 *)urb->context;
	int err;

	if (WARN_ON_ONCE(!ar))
		return;

	atomic_dec(&ar->rx_anch_urbs);

	switch (urb->status) {
	case 0:
		/* rx path */
		usb_anchor_urb(urb, &ar->rx_work);
		atomic_inc(&ar->rx_work_urbs);
		break;

	case -ENOENT:
	case -ECONNRESET:
	case -ENODEV:
	case -ESHUTDOWN:
		/* handle disconnect events*/
		return;

	default:
		/* handle all other errors */
		usb_anchor_urb(urb, &ar->rx_pool);
		atomic_inc(&ar->rx_pool_urbs);
		break;
	}

	err = carl9170_usb_submit_rx_urb(ar, GFP_ATOMIC);
	if (unlikely(err)) {
		/*
		 * usb_submit_rx_urb reported a problem.
		 * In case this is due to a rx buffer shortage,
		 * elevate the tasklet worker priority to
		 * the highest available level.
		 */
		tasklet_hi_schedule(&ar->usb_tasklet);

		if (atomic_read(&ar->rx_anch_urbs) == 0) {
			/*
			 * The system is too slow to cope with
			 * the enormous workload. We have simply
			 * run out of active rx urbs and this
			 * unfortunatly leads to an unpredictable
			 * device.
			 */

			carl9170_restart(ar, CARL9170_RR_SLOW_SYSTEM);
		}
	} else {
		/*
		 * Using anything less than _high_ priority absolutely
		 * kills the rx performance my UP-System...
		 */
		tasklet_hi_schedule(&ar->usb_tasklet);
	}
}
Esempio n. 6
0
void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
{
	struct carl9170_rsp *cmd = (void *) buf;
	struct ieee80211_vif *vif;

	if (carl9170_check_sequence(ar, cmd->hdr.seq))
		return;

	if ((cmd->hdr.cmd & CARL9170_RSP_FLAG) != CARL9170_RSP_FLAG) {
		if (!(cmd->hdr.cmd & CARL9170_CMD_ASYNC_FLAG))
			carl9170_cmd_callback(ar, len, buf);

		return;
	}

	if (unlikely(cmd->hdr.len != (len - 4))) {
		if (net_ratelimit()) {
			wiphy_err(ar->hw->wiphy, "FW: received over-/under"
				"sized event %x (%d, but should be %d).\n",
			       cmd->hdr.cmd, cmd->hdr.len, len - 4);

			print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE,
					     buf, len);
		}

		return;
	}

	/* hardware event handlers */
	switch (cmd->hdr.cmd) {
	case CARL9170_RSP_PRETBTT:
		/* pre-TBTT event */
		rcu_read_lock();
		vif = carl9170_get_main_vif(ar);

		if (!vif) {
			rcu_read_unlock();
			break;
		}

		switch (vif->type) {
		case NL80211_IFTYPE_STATION:
			carl9170_handle_ps(ar, cmd);
			break;

		case NL80211_IFTYPE_AP:
		case NL80211_IFTYPE_ADHOC:
			carl9170_update_beacon(ar, true);
			break;

		default:
			break;
		}
		rcu_read_unlock();

		break;


	case CARL9170_RSP_TXCOMP:
		/* TX status notification */
		carl9170_tx_process_status(ar, cmd);
		break;

	case CARL9170_RSP_BEACON_CONFIG:
		/*
		 * (IBSS) beacon send notification
		 * bytes: 04 c2 XX YY B4 B3 B2 B1
		 *
		 * XX always 80
		 * YY always 00
		 * B1-B4 "should" be the number of send out beacons.
		 */
		break;

	case CARL9170_RSP_ATIM:
		/* End of Atim Window */
		break;

	case CARL9170_RSP_WATCHDOG:
		/* Watchdog Interrupt */
		carl9170_restart(ar, CARL9170_RR_WATCHDOG);
		break;

	case CARL9170_RSP_TEXT:
		/* firmware debug */
		carl9170_dbg_message(ar, (char *)buf + 4, len - 4);
		break;

	case CARL9170_RSP_HEXDUMP:
		wiphy_dbg(ar->hw->wiphy, "FW: HD %d\n", len - 4);
		print_hex_dump_bytes("FW:", DUMP_PREFIX_NONE,
				     (char *)buf + 4, len - 4);
		break;

	case CARL9170_RSP_RADAR:
		if (!net_ratelimit())
			break;

		wiphy_info(ar->hw->wiphy, "FW: RADAR! Please report this "
		       "incident to [email protected] !\n");
		break;

	case CARL9170_RSP_GPIO:
#ifdef CONFIG_CARL9170_WPC
		if (ar->wps.pbc) {
			bool state = !!(cmd->gpio.gpio & cpu_to_le32(
				AR9170_GPIO_PORT_WPS_BUTTON_PRESSED));

			if (state != ar->wps.pbc_state) {
				ar->wps.pbc_state = state;
				input_report_key(ar->wps.pbc, KEY_WPS_BUTTON,
						 state);
				input_sync(ar->wps.pbc);
			}
		}
#endif /* CONFIG_CARL9170_WPC */
		break;

	case CARL9170_RSP_BOOT:
		complete(&ar->fw_boot_wait);
		break;

	default:
		wiphy_err(ar->hw->wiphy, "FW: received unhandled event %x\n",
			cmd->hdr.cmd);
		print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len);
		break;
	}
}