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

Commit 3ee40c37 authored by David S. Miller's avatar David S. Miller
Browse files
parents 67002547 98eb0f53
Loading
Loading
Loading
Loading
+16 −8
Original line number Diff line number Diff line
@@ -505,9 +505,16 @@ void i2400m_report_hook(struct i2400m *i2400m,
	 * it. */
	case I2400M_MT_REPORT_POWERSAVE_READY:	/* zzzzz */
		if (l3l4_hdr->status == cpu_to_le16(I2400M_MS_DONE_OK)) {
			d_printf(1, dev, "ready for powersave, requesting\n");
			if (i2400m_power_save_disabled)
				d_printf(1, dev, "ready for powersave, "
					 "not requesting (disabled by module "
					 "parameter)\n");
			else {
				d_printf(1, dev, "ready for powersave, "
					 "requesting\n");
				i2400m_cmd_enter_powersave(i2400m);
			}
		}
		break;
	};
	d_fnend(3, dev, "(i2400m %p l3l4_hdr %p size %zu) = void\n",
@@ -688,8 +695,9 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m,
	d_fnstart(3, dev, "(i2400m %p buf %p len %zu)\n",
		  i2400m, buf, buf_len);

	rmb();		/* Make sure we see what i2400m_dev_reset_handle() */
	if (i2400m->boot_mode)
		return ERR_PTR(-ENODEV);
		return ERR_PTR(-EL3RST);

	msg_l3l4_hdr = buf;
	/* Check msg & payload consistency */
@@ -1389,16 +1397,16 @@ error:
 *
 * @i2400m: device descriptor
 *
 * Gracefully stops the device, moving it to the lowest power
 * consumption state possible.
 * Release resources acquired during the running of the device; in
 * theory, should also tell the device to go to sleep, switch off the
 * radio, all that, but at this point, in most cases (driver
 * disconnection, reset handling) we can't even talk to the device.
 */
void i2400m_dev_shutdown(struct i2400m *i2400m)
{
	int result = -ENODEV;
	struct device *dev = i2400m_dev(i2400m);

	d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
	result = i2400m->bus_reset(i2400m, I2400M_RT_WARM);
	d_fnend(3, dev, "(i2400m %p) = void [%d]\n", i2400m, result);
	d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
	return;
}
+28 −12
Original line number Diff line number Diff line
@@ -82,6 +82,14 @@ module_param_named(rx_reorder_disabled, i2400m_rx_reorder_disabled, int, 0644);
MODULE_PARM_DESC(rx_reorder_disabled,
		 "If true, RX reordering will be disabled.");

int i2400m_power_save_disabled;	/* 0 (power saving enabled) by default */
module_param_named(power_save_disabled, i2400m_power_save_disabled, int, 0644);
MODULE_PARM_DESC(power_save_disabled,
		 "If true, the driver will not tell the device to enter "
		 "power saving mode when it reports it is ready for it. "
		 "False by default (so the device is told to do power "
		 "saving).");

/**
 * i2400m_queue_work - schedule work on a i2400m's queue
 *
@@ -172,7 +180,6 @@ int i2400m_schedule_work(struct i2400m *i2400m,
	int result;
	struct i2400m_work *iw;

	BUG_ON(i2400m->work_queue == NULL);
	result = -ENOMEM;
	iw = kzalloc(sizeof(*iw), gfp_flags);
	if (iw == NULL)
@@ -377,6 +384,11 @@ error:
 * Uploads firmware and brings up all the resources needed to be able
 * to communicate with the device.
 *
 * The workqueue has to be setup early, at least before RX handling
 * (it's only real user for now) so it can process reports as they
 * arrive. We also want to destroy it if we retry, to make sure it is
 * flushed...easier like this.
 *
 * TX needs to be setup before the bus-specific code (otherwise on
 * shutdown, the bus-tx code could try to access it).
 */
@@ -387,7 +399,7 @@ int __i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri flags)
	struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
	struct net_device *net_dev = wimax_dev->net_dev;
	struct device *dev = i2400m_dev(i2400m);
	int times = 3;
	int times = i2400m->bus_bm_retries;

	d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
retry:
@@ -402,15 +414,15 @@ retry:
	result = i2400m_rx_setup(i2400m);
	if (result < 0)
		goto error_rx_setup;
	result = i2400m->bus_dev_start(i2400m);
	if (result < 0)
		goto error_bus_dev_start;
	i2400m->work_queue = create_singlethread_workqueue(wimax_dev->name);
	if (i2400m->work_queue == NULL) {
		result = -ENOMEM;
		dev_err(dev, "cannot create workqueue\n");
		goto error_create_workqueue;
	}
	result = i2400m->bus_dev_start(i2400m);
	if (result < 0)
		goto error_bus_dev_start;
	result = i2400m_firmware_check(i2400m);	/* fw versions ok? */
	if (result < 0)
		goto error_fw_check;
@@ -432,17 +444,17 @@ retry:
error_dev_initialize:
error_check_mac_addr:
error_fw_check:
	destroy_workqueue(i2400m->work_queue);
error_create_workqueue:
	i2400m->bus_dev_stop(i2400m);
error_bus_dev_start:
	destroy_workqueue(i2400m->work_queue);
error_create_workqueue:
	i2400m_rx_release(i2400m);
error_rx_setup:
	i2400m_tx_release(i2400m);
error_tx_setup:
error_bootstrap:
	if (result == -ERESTARTSYS && times-- > 0) {
		flags = I2400M_BRI_SOFT;
	if (result == -EL3RST && times-- > 0) {
		flags = I2400M_BRI_SOFT|I2400M_BRI_MAC_REINIT;
		goto retry;
	}
	d_fnend(3, dev, "(net_dev %p [i2400m %p]) = %d\n",
@@ -471,7 +483,9 @@ int i2400m_dev_start(struct i2400m *i2400m, enum i2400m_bri bm_flags)
 *
 * Returns: 0 if ok, < 0 errno code on error.
 *
 * Releases all the resources allocated to communicate with the device.
 * Releases all the resources allocated to communicate with the
 * device. Note we cannot destroy the workqueue earlier as until RX is
 * fully destroyed, it could still try to schedule jobs.
 */
static
void __i2400m_dev_stop(struct i2400m *i2400m)
@@ -483,8 +497,8 @@ void __i2400m_dev_stop(struct i2400m *i2400m)
	wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING);
	i2400m_dev_shutdown(i2400m);
	i2400m->ready = 0;
	destroy_workqueue(i2400m->work_queue);
	i2400m->bus_dev_stop(i2400m);
	destroy_workqueue(i2400m->work_queue);
	i2400m_rx_release(i2400m);
	i2400m_tx_release(i2400m);
	wimax_state_change(wimax_dev, WIMAX_ST_DOWN);
@@ -546,7 +560,7 @@ void __i2400m_dev_reset_handle(struct work_struct *ws)
		 * i2400m_dev_stop() [we are shutting down anyway, so
		 * ignore it] or we are resetting somewhere else. */
		dev_err(dev, "device rebooted\n");
		i2400m_msg_to_dev_cancel_wait(i2400m, -ERESTARTSYS);
		i2400m_msg_to_dev_cancel_wait(i2400m, -EL3RST);
		complete(&i2400m->msg_completion);
		goto out;
	}
@@ -596,6 +610,8 @@ out:
 */
int i2400m_dev_reset_handle(struct i2400m *i2400m)
{
	i2400m->boot_mode = 1;
	wmb();		/* Make sure i2400m_msg_to_dev() sees boot_mode */
	return i2400m_schedule_work(i2400m, __i2400m_dev_reset_handle,
				    GFP_ATOMIC);
}
+20 −38
Original line number Diff line number Diff line
@@ -397,7 +397,7 @@ static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk,
				 unsigned int direct, unsigned int do_csum)
{
	int ret;
	size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_PAD);
	size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_ALIGN);
	struct device *dev = i2400m_dev(i2400m);
	struct {
		struct i2400m_bootrom_header cmd;
@@ -532,14 +532,14 @@ int i2400m_dnload_finalize(struct i2400m *i2400m,
	cmd = (void *) bcf + offset;
	if (i2400m->sboot == 0) {
		struct i2400m_bootrom_header jump_ack;
		d_printf(3, dev, "unsecure boot, jumping to 0x%08x\n",
		d_printf(1, dev, "unsecure boot, jumping to 0x%08x\n",
			le32_to_cpu(cmd->target_addr));
		i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP);
		cmd->data_size = 0;
		ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
				    &jump_ack, sizeof(jump_ack), 0);
	} else {
		d_printf(3, dev, "secure boot, jumping to 0x%08x\n",
		d_printf(1, dev, "secure boot, jumping to 0x%08x\n",
			 le32_to_cpu(cmd->target_addr));
		cmd_buf = i2400m->bm_cmd_buf;
		memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd));
@@ -696,8 +696,7 @@ error_dev_gone:
	return result;

error_timeout:
	dev_err(dev, "Timed out waiting for reboot ack, resetting\n");
	i2400m->bus_reset(i2400m, I2400M_RT_BUS);
	dev_err(dev, "Timed out waiting for reboot ack\n");
	result = -ETIMEDOUT;
	goto exit_timeout;
}
@@ -770,40 +769,21 @@ error_read_mac:
static
int i2400m_dnload_init_nonsigned(struct i2400m *i2400m)
{
#define POKE(a, d) {					\
	.address = cpu_to_le32(a),		\
	.data = cpu_to_le32(d)		\
}
	static const struct {
		__le32 address;
		__le32 data;
	} i2400m_pokes[] = {
		POKE(0x081A58, 0xA7810230),
		POKE(0x080040, 0x00000000),
		POKE(0x080048, 0x00000082),
		POKE(0x08004C, 0x0000081F),
		POKE(0x080054, 0x00000085),
		POKE(0x080058, 0x00000180),
		POKE(0x08005C, 0x00000018),
		POKE(0x080060, 0x00000010),
		POKE(0x080574, 0x00000001),
		POKE(0x080550, 0x00000005),
		POKE(0xAE0000, 0x00000000),
	};
#undef POKE
	unsigned i;
	int ret;
	unsigned i = 0;
	int ret = 0;
	struct device *dev = i2400m_dev(i2400m);

	dev_warn(dev, "WARNING!!! non-signed boot UNTESTED PATH!\n");

	d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
	for (i = 0; i < ARRAY_SIZE(i2400m_pokes); i++) {
		ret = i2400m_download_chunk(i2400m, &i2400m_pokes[i].data,
					    sizeof(i2400m_pokes[i].data),
					    i2400m_pokes[i].address, 1, 1);
	if (i2400m->bus_bm_pokes_table) {
		while (i2400m->bus_bm_pokes_table[i].address) {
			ret = i2400m_download_chunk(
				i2400m,
				&i2400m->bus_bm_pokes_table[i].data,
				sizeof(i2400m->bus_bm_pokes_table[i].data),
				i2400m->bus_bm_pokes_table[i].address, 1, 1);
			if (ret < 0)
				break;
			i++;
		}
	}
	d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret);
	return ret;
@@ -980,11 +960,12 @@ int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf,
{
	int ret = 0;
	struct device *dev = i2400m_dev(i2400m);
	int count = I2400M_BOOT_RETRIES;
	int count = i2400m->bus_bm_retries;

	d_fnstart(5, dev, "(i2400m %p bcf %p size %zu)\n",
		  i2400m, bcf, bcf_size);
	i2400m->boot_mode = 1;
	wmb();		/* Make sure other readers see it */
hw_reboot:
	if (count-- == 0) {
		ret = -ERESTARTSYS;
@@ -1033,6 +1014,7 @@ hw_reboot:
	d_printf(2, dev, "fw %s successfully uploaded\n",
		 i2400m->fw_name);
	i2400m->boot_mode = 0;
	wmb();		/* Make sure i2400m_msg_to_dev() sees boot_mode */
error_dnload_finalize:
error_dnload_bcf:
error_dnload_init:
+9 −0
Original line number Diff line number Diff line
@@ -78,6 +78,8 @@ enum {
	/* The number of ticks to wait for the device to signal that
	 * it is ready */
	I2400MS_INIT_SLEEP_INTERVAL = 10,
	/* How long to wait for the device to settle after reset */
	I2400MS_SETTLE_TIME = 40,
};


@@ -105,6 +107,10 @@ struct i2400ms {
	char tx_wq_name[32];

	struct dentry *debugfs_dentry;

	wait_queue_head_t bm_wfa_wq;
	int bm_wait_result;
	size_t bm_ack_size;
};


@@ -129,4 +135,7 @@ extern ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *,
extern ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *,
					   struct i2400m_bootrom_header *,
					   size_t);
extern void i2400ms_bus_bm_release(struct i2400m *);
extern int i2400ms_bus_bm_setup(struct i2400m *);

#endif /* #ifndef __I2400M_SDIO_H__ */
+43 −0
Original line number Diff line number Diff line
@@ -150,11 +150,33 @@
enum {
	/* Firmware uploading */
	I2400M_BOOT_RETRIES = 3,
	I3200_BOOT_RETRIES = 3,
	/* Size of the Boot Mode Command buffer */
	I2400M_BM_CMD_BUF_SIZE = 16 * 1024,
	I2400M_BM_ACK_BUF_SIZE = 256,
};

/**
 * struct i2400m_poke_table - Hardware poke table for the Intel 2400m
 *
 * This structure will be used to create a device specific poke table
 * to put the device in a consistant state at boot time.
 *
 * @address: The device address to poke
 *
 * @data: The data value to poke to the device address
 *
 */
struct i2400m_poke_table{
	__le32 address;
	__le32 data;
};

#define I2400M_FW_POKE(a, d) {		\
	.address = cpu_to_le32(a),	\
	.data = cpu_to_le32(d)		\
}


/**
 * i2400m_reset_type - methods to reset a device
@@ -224,6 +246,17 @@ struct i2400m_roq;
 *     process, so it cannot rely on common infrastructure being laid
 *     out.
 *
 * @bus_bm_retries: [fill] How many times shall a firmware upload /
 *     device initialization be retried? Different models of the same
 *     device might need different values, hence it is set by the
 *     bus-specific driver. Note this value is used in two places,
 *     i2400m_fw_dnload() and __i2400m_dev_start(); they won't become
 *     multiplicative (__i2400m_dev_start() calling N times
 *     i2400m_fw_dnload() and this trying N times to download the
 *     firmware), as if __i2400m_dev_start() only retries if the
 *     firmware crashed while initializing the device (not in a
 *     general case).
 *
 * @bus_bm_cmd_send: [fill] Function called to send a boot-mode
 *     command. Flags are defined in 'enum i2400m_bm_cmd_flags'. This
 *     is synchronous and has to return 0 if ok or < 0 errno code in
@@ -252,6 +285,12 @@ struct i2400m_roq;
 *     address provided in boot mode is kind of broken and needs to
 *     be re-read later on.
 *
 * @bus_bm_pokes_table: [fill/optional] A table of device addresses
 *     and values that will be poked at device init time to move the
 *     device to the correct state for the type of boot/firmware being
 *     used.  This table MUST be terminated with (0x000000,
 *     0x00000000) or bad things will happen.
 *
 *
 * @wimax_dev: WiMAX generic device for linkage into the kernel WiMAX
 *     stack. Due to the way a net_device is allocated, we need to
@@ -399,6 +438,8 @@ struct i2400m {

	size_t bus_tx_block_size;
	size_t bus_pl_size_max;
	unsigned bus_bm_retries;

	int (*bus_dev_start)(struct i2400m *);
	void (*bus_dev_stop)(struct i2400m *);
	void (*bus_tx_kick)(struct i2400m *);
@@ -410,6 +451,7 @@ struct i2400m {
				       struct i2400m_bootrom_header *, size_t);
	const char **bus_fw_names;
	unsigned bus_bm_mac_addr_impaired:1;
	const struct i2400m_poke_table *bus_bm_pokes_table;

	spinlock_t tx_lock;		/* protect TX state */
	void *tx_buf;
@@ -709,6 +751,7 @@ static const __le32 i2400m_SBOOT_BARKER[4] = {
	cpu_to_le32(I2400M_SBOOT_BARKER)
};

extern int i2400m_power_save_disabled;

/*
 * Utility functions
Loading