Exemplo n.º 1
0
/*
 * Wake up the device and transmit a held SKB, then restart the net queue
 *
 * When the device goes into basestation-idle mode, we need to tell it
 * to exit that mode; it will negotiate with the base station, user
 * space may have to intervene to rehandshake crypto and then tell us
 * when it is ready to transmit the packet we have "queued". Still we
 * need to give it sometime after it reports being ok.
 *
 * On error, there is not much we can do. If the error was on TX, we
 * still wake the queue up to see if the next packet will be luckier.
 *
 * If _cmd_exit_idle() fails...well, it could be many things; most
 * commonly it is that something else took the device out of IDLE mode
 * (for example, the base station). In that case we get an -EILSEQ and
 * we are just going to ignore that one. If the device is back to
 * connected, then fine -- if it is someother state, the packet will
 * be dropped anyway.
 */
void i2400m_wake_tx_work(struct work_struct *ws)
{
	int result;
	struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws);
	struct net_device *net_dev = i2400m->wimax_dev.net_dev;
	struct device *dev = i2400m_dev(i2400m);
	struct sk_buff *skb;
	unsigned long flags;

	spin_lock_irqsave(&i2400m->tx_lock, flags);
	skb = i2400m->wake_tx_skb;
	i2400m->wake_tx_skb = NULL;
	spin_unlock_irqrestore(&i2400m->tx_lock, flags);

	d_fnstart(3, dev, "(ws %p i2400m %p skb %p)\n", ws, i2400m, skb);
	result = -EINVAL;
	if (skb == NULL) {
		dev_err(dev, "WAKE&TX: skb disappeared!\n");
		goto out_put;
	}
	/* If we have, somehow, lost the connection after this was
	 * queued, don't do anything; this might be the device got
	 * reset or just disconnected. */
	if (unlikely(!netif_carrier_ok(net_dev)))
		goto out_kfree;
	result = i2400m_cmd_exit_idle(i2400m);
	if (result == -EILSEQ)
		result = 0;
	if (result < 0) {
		dev_err(dev, "WAKE&TX: device didn't get out of idle: "
			"%d - resetting\n", result);
		i2400m_reset(i2400m, I2400M_RT_BUS);
		goto error;
	}
	result = wait_event_timeout(i2400m->state_wq,
				    i2400m->state != I2400M_SS_IDLE,
				    net_dev->watchdog_timeo - HZ/2);
	if (result == 0)
		result = -ETIMEDOUT;
	if (result < 0) {
		dev_err(dev, "WAKE&TX: error waiting for device to exit IDLE: "
			"%d - resetting\n", result);
		i2400m_reset(i2400m, I2400M_RT_BUS);
		goto error;
	}
	msleep(20);	/* device still needs some time or it drops it */
	result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA);
error:
	netif_wake_queue(net_dev);
out_kfree:
	kfree_skb(skb);	/* refcount transferred by _hard_start_xmit() */
out_put:
	i2400m_put(i2400m);
	d_fnend(3, dev, "(ws %p i2400m %p skb %p) = void [%d]\n",
		ws, i2400m, skb, result);
}
Exemplo n.º 2
0
/*
 * Act on a TLV System State reported by the device
 *
 * @i2400m: device descriptor
 * @ss: validated System State TLV
 */
static
void i2400m_report_tlv_system_state(struct i2400m *i2400m,
				    const struct i2400m_tlv_system_state *ss)
{
	struct device *dev = i2400m_dev(i2400m);
	struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
	enum i2400m_system_state i2400m_state = le32_to_cpu(ss->state);

	d_fnstart(3, dev, "(i2400m %p ss %p [%u])\n", i2400m, ss, i2400m_state);

	if (i2400m->state != i2400m_state) {
		i2400m->state = i2400m_state;
		wake_up_all(&i2400m->state_wq);
	}
	switch (i2400m_state) {
	case I2400M_SS_UNINITIALIZED:
	case I2400M_SS_INIT:
	case I2400M_SS_CONFIG:
	case I2400M_SS_PRODUCTION:
		wimax_state_change(wimax_dev, WIMAX_ST_UNINITIALIZED);
		break;

	case I2400M_SS_RF_OFF:
	case I2400M_SS_RF_SHUTDOWN:
		wimax_state_change(wimax_dev, WIMAX_ST_RADIO_OFF);
		break;

	case I2400M_SS_READY:
	case I2400M_SS_STANDBY:
	case I2400M_SS_SLEEPACTIVE:
		wimax_state_change(wimax_dev, WIMAX_ST_READY);
		break;

	case I2400M_SS_CONNECTING:
	case I2400M_SS_WIMAX_CONNECTED:
		wimax_state_change(wimax_dev, WIMAX_ST_READY);
		break;

	case I2400M_SS_SCAN:
	case I2400M_SS_OUT_OF_ZONE:
		wimax_state_change(wimax_dev, WIMAX_ST_SCANNING);
		break;

	case I2400M_SS_IDLE:
		d_printf(1, dev, "entering BS-negotiated idle mode\n");
	case I2400M_SS_DISCONNECTING:
	case I2400M_SS_DATA_PATH_CONNECTED:
		wimax_state_change(wimax_dev, WIMAX_ST_CONNECTED);
		break;

	default:
		/* Huh? just in case, shut it down */
		dev_err(dev, "HW BUG? unknown state %u: shutting down\n",
			i2400m_state);
		i2400m_reset(i2400m, I2400M_RT_WARM);
		break;
	}
	d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n",
		i2400m, ss, i2400m_state);
}
Exemplo n.º 3
0
/*
 * Reset the device
 *
 * Write 0 to ask the device to soft reset, 1 to cold reset, 2 to bus
 * reset (as defined by enum i2400m_reset_type).
 */
static
int debugfs_i2400m_reset_set(void *data, u64 val)
{
	int result;
	struct i2400m *i2400m = data;
	enum i2400m_reset_type rt = val;
	switch(rt) {
	case I2400M_RT_WARM:
	case I2400M_RT_COLD:
	case I2400M_RT_BUS:
		result = i2400m_reset(i2400m, rt);
		if (result >= 0)
			result = 0;
	default:
		result = -EINVAL;
	}
	return result;
}
Exemplo n.º 4
0
Arquivo: fw.c Projeto: 020gzh/linux
/**
 * i2400m_bootrom_init - Reboots a powered device into boot mode
 *
 * @i2400m: device descriptor
 * @flags:
 *      I2400M_BRI_SOFT: a reboot barker has been seen
 *          already, so don't wait for it.
 *
 *      I2400M_BRI_NO_REBOOT: Don't send a reboot command, but wait
 *          for a reboot barker notification. This is a one shot; if
 *          the state machine needs to send a reboot command it will.
 *
 * Returns:
 *
 *     < 0 errno code on error, 0 if ok.
 *
 * Description:
 *
 * Tries hard enough to put the device in boot-mode. There are two
 * main phases to this:
 *
 * a. (1) send a reboot command and (2) get a reboot barker
 *
 * b. (1) echo/ack the reboot sending the reboot barker back and (2)
 *        getting an ack barker in return
 *
 * We want to skip (a) in some cases [soft]. The state machine is
 * horrible, but it is basically: on each phase, send what has to be
 * sent (if any), wait for the answer and act on the answer. We might
 * have to backtrack and retry, so we keep a max tries counter for
 * that.
 *
 * It sucks because we don't know ahead of time which is going to be
 * the reboot barker (the device might send different ones depending
 * on its EEPROM config) and once the device reboots and waits for the
 * echo/ack reboot barker being sent back, it doesn't understand
 * anything else. So we can be left at the point where we don't know
 * what to send to it -- cold reset and bus reset seem to have little
 * effect. So the function iterates (in this case) through all the
 * known barkers and tries them all until an ACK is
 * received. Otherwise, it gives up.
 *
 * If we get a timeout after sending a warm reset, we do it again.
 */
int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags)
{
	int result;
	struct device *dev = i2400m_dev(i2400m);
	struct i2400m_bootrom_header *cmd;
	struct i2400m_bootrom_header ack;
	int count = i2400m->bus_bm_retries;
	int ack_timeout_cnt = 1;
	unsigned i;

	BUILD_BUG_ON(sizeof(*cmd) != sizeof(i2400m_barker_db[0].data));
	BUILD_BUG_ON(sizeof(ack) != sizeof(i2400m_ACK_BARKER));

	d_fnstart(4, dev, "(i2400m %p flags 0x%08x)\n", i2400m, flags);
	result = -ENOMEM;
	cmd = i2400m->bm_cmd_buf;
	if (flags & I2400M_BRI_SOFT)
		goto do_reboot_ack;
do_reboot:
	ack_timeout_cnt = 1;
	if (--count < 0)
		goto error_timeout;
	d_printf(4, dev, "device reboot: reboot command [%d # left]\n",
		 count);
	if ((flags & I2400M_BRI_NO_REBOOT) == 0)
		i2400m_reset(i2400m, I2400M_RT_WARM);
	result = i2400m_bm_cmd(i2400m, NULL, 0, &ack, sizeof(ack),
			       I2400M_BM_CMD_RAW);
	flags &= ~I2400M_BRI_NO_REBOOT;
	switch (result) {
	case -ERESTARTSYS:
		/*
		 * at this point, i2400m_bm_cmd(), through
		 * __i2400m_bm_ack_process(), has updated
		 * i2400m->barker and we are good to go.
		 */
		d_printf(4, dev, "device reboot: got reboot barker\n");
		break;
	case -EISCONN:	/* we don't know how it got here...but we follow it */
		d_printf(4, dev, "device reboot: got ack barker - whatever\n");
		goto do_reboot;
	case -ETIMEDOUT:
		/*
		 * Device has timed out, we might be in boot mode
		 * already and expecting an ack; if we don't know what
		 * the barker is, we just send them all. Cold reset
		 * and bus reset don't work. Beats me.
		 */
		if (i2400m->barker != NULL) {
			dev_err(dev, "device boot: reboot barker timed out, "
				"trying (set) %08x echo/ack\n",
				le32_to_cpu(i2400m->barker->data[0]));
			goto do_reboot_ack;
		}
		for (i = 0; i < i2400m_barker_db_used; i++) {
			struct i2400m_barker_db *barker = &i2400m_barker_db[i];
			memcpy(cmd, barker->data, sizeof(barker->data));
			result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
					       &ack, sizeof(ack),
					       I2400M_BM_CMD_RAW);
			if (result == -EISCONN) {
				dev_warn(dev, "device boot: got ack barker "
					 "after sending echo/ack barker "
					 "#%d/%08x; rebooting j.i.c.\n",
					 i, le32_to_cpu(barker->data[0]));
				flags &= ~I2400M_BRI_NO_REBOOT;
				goto do_reboot;
			}
		}
		dev_err(dev, "device boot: tried all the echo/acks, could "
			"not get device to respond; giving up");
		result = -ESHUTDOWN;
	case -EPROTO:
	case -ESHUTDOWN:	/* dev is gone */
	case -EINTR:		/* user cancelled */
		goto error_dev_gone;
	default:
		dev_err(dev, "device reboot: error %d while waiting "
			"for reboot barker - rebooting\n", result);
		d_dump(1, dev, &ack, result);
		goto do_reboot;
	}
	/* At this point we ack back with 4 REBOOT barkers and expect
	 * 4 ACK barkers. This is ugly, as we send a raw command --
	 * hence the cast. _bm_cmd() will catch the reboot ack
	 * notification and report it as -EISCONN. */
do_reboot_ack:
	d_printf(4, dev, "device reboot ack: sending ack [%d # left]\n", count);
	memcpy(cmd, i2400m->barker->data, sizeof(i2400m->barker->data));
	result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
			       &ack, sizeof(ack), I2400M_BM_CMD_RAW);
	switch (result) {
	case -ERESTARTSYS:
		d_printf(4, dev, "reboot ack: got reboot barker - retrying\n");
		if (--count < 0)
			goto error_timeout;
		goto do_reboot_ack;
	case -EISCONN:
		d_printf(4, dev, "reboot ack: got ack barker - good\n");
		break;
	case -ETIMEDOUT:	/* no response, maybe it is the other type? */
		if (ack_timeout_cnt-- < 0) {
			d_printf(4, dev, "reboot ack timedout: retrying\n");
			goto do_reboot_ack;
		} else {
			dev_err(dev, "reboot ack timedout too long: "
				"trying reboot\n");
			goto do_reboot;
		}
		break;
	case -EPROTO:
	case -ESHUTDOWN:	/* dev is gone */
		goto error_dev_gone;
	default:
		dev_err(dev, "device reboot ack: error %d while waiting for "
			"reboot ack barker - rebooting\n", result);
		goto do_reboot;
	}
	d_printf(2, dev, "device reboot ack: got ack barker - boot done\n");
	result = 0;
exit_timeout:
error_dev_gone:
	d_fnend(4, dev, "(i2400m %p flags 0x%08x) = %d\n",
		i2400m, flags, result);
	return result;

error_timeout:
	dev_err(dev, "Timed out waiting for reboot ack\n");
	result = -ETIMEDOUT;
	goto exit_timeout;
}