[PATCH 35/40] i2400m/SDIO: firmware upload backend

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Inaky Perez-Gonzalez
Date: Friday, December 5, 2008 - 11:55 am

This implements the backends for the generic driver (i2400m) to be
able to load firmware to the SDIO device.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/sdio-fw.c |  224 ++++++++++++++++++++++++++++++++++++
 1 files changed, 224 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/wimax/i2400m/sdio-fw.c

diff --git a/drivers/net/wimax/i2400m/sdio-fw.c b/drivers/net/wimax/i2400m/sdio-fw.c
new file mode 100644
index 0000000..3487205
--- /dev/null
+++ b/drivers/net/wimax/i2400m/sdio-fw.c
@@ -0,0 +1,224 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Firmware uploader's SDIO specifics
+ *
+ *
+ * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * Intel Corporation <linux-wimax@intel.com>
+ * Yanir Lubetkin <yanirx.lubetkin@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *  - Initial implementation
+ *
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *  - Bus generic/specific split for USB
+ *
+ * Dirk Brandewie <dirk.j.brandewie@intel.com>
+ *  - Initial implementation for SDIO
+ *
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
+ *  - SDIO rehash for changes in the bus-driver model
+ *
+ * THE PROCEDURE
+ *
+ * See fw.c for the generic description of this procedure.
+ *
+ * This file implements only the SDIO specifics. It boils down to how
+ * to send a command and waiting for an acknowledgement from the
+ * device. We do polled reads.
+ *
+ * COMMAND EXECUTION
+ *
+ * THe generic firmware upload code will call i2400m_bus_bm_cmd_send()
+ * to send commands.
+ *
+ * The SDIO devices expects things in 256 byte blocks, so it will pad
+ * it, compute the checksum (if needed) and pass it to SDIO.
+ *
+ * ACK RECEPTION
+ *
+ * This works in polling mode -- the fw loader says when to wait for
+ * data and for that it calls i2400ms_bus_bm_wait_for_ack().
+ *
+ * This will poll the device for data until it is received. We need to
+ * receive at least as much bytes as where asked for (although it'll
+ * always be a multiple of 256 bytes).
+ */
+#include <linux/mmc/sdio_func.h>
+#include "i2400m-sdio.h"
+
+
+#define D_SUBMODULE fw
+#include "sdio-debug-levels.h"
+
+/*
+ * Send a boot-mode command to the SDIO function
+ *
+ * We use a bounce buffer (i2400m->bm_cmd_buf) because we need to
+ * touch the header if the RAW flag is not set.
+ *
+ * @flags: pass thru from i2400m_bm_cmd()
+ * @return: cmd_size if ok, < 0 errno code on error.
+ *
+ * Note the command is padded to the SDIO block size for the device.
+ */
+ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *i2400m,
+				const struct i2400m_bootrom_header *_cmd,
+				size_t cmd_size, int flags)
+{
+	ssize_t result;
+	struct device *dev = i2400m_dev(i2400m);
+	struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
+	int opcode = _cmd == NULL ? -1 : i2400m_brh_get_opcode(_cmd);
+	struct i2400m_bootrom_header *cmd;
+	/* SDIO restriction */
+	size_t cmd_size_a = ALIGN(cmd_size, I2400MS_BLK_SIZE);
+
+	d_fnstart(5, dev, "(i2400m %p cmd %p size %zu)\n",
+		  i2400m, _cmd, cmd_size);
+	result = -E2BIG;
+	if (cmd_size > I2400M_BM_CMD_BUF_SIZE)
+		goto error_too_big;
+
+	memcpy(i2400m->bm_cmd_buf, _cmd, cmd_size);	/* Prep command */
+	cmd = i2400m->bm_cmd_buf;
+	if (cmd_size_a > cmd_size)			/* Zero pad space */
+		memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size);
+	if ((flags & I2400M_BM_CMD_RAW) == 0) {
+		if (WARN_ON(i2400m_brh_get_response_required(cmd) == 0))
+			dev_warn(dev, "SW BUG: response_required == 0\n");
+		i2400m_bm_cmd_prepare(cmd);
+	}
+	d_printf(4, dev, "BM cmd %d: %zu bytes (%zu padded)\n",
+		 opcode, cmd_size, cmd_size_a);
+	d_dump(5, dev, cmd, cmd_size);
+
+	sdio_claim_host(i2400ms->func);			/* Send & check */
+	result = sdio_memcpy_toio(i2400ms->func, I2400MS_DATA_ADDR,
+				  i2400m->bm_cmd_buf, cmd_size_a);
+	sdio_release_host(i2400ms->func);
+	if (result < 0) {
+		dev_err(dev, "BM cmd %d: cannot send: %ld\n",
+			opcode, (long) result);
+		goto error_cmd_send;
+	}
+	result = cmd_size;
+error_cmd_send:
+error_too_big:
+	d_fnend(5, dev, "(i2400m %p cmd %p size %zu) = %d\n",
+		i2400m, _cmd, cmd_size, (int) result);
+	return result;
+}
+
+
+/*
+ * Read an ack from the device's boot-mode (polling)
+ *
+ * @i2400m:
+ * @_ack: pointer to where to store the read data
+ * @ack_size: how many bytes we should read
+ *
+ * Returns: < 0 errno code on error; otherwise, amount of received bytes.
+ *
+ * The ACK for a BM command is always at least sizeof(*ack) bytes, so
+ * check for that. We don't need to check for device reboots
+ *
+ * NOTE: We do an artificial timeout of 1 sec over the SDIO timeout;
+ *     this way we have control over it...there is no way that I know
+ *     of setting an SDIO transaction timeout.
+ */
+ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m,
+				    struct i2400m_bootrom_header *ack,
+				    size_t ack_size)
+{
+	int result;
+	ssize_t rx_size;
+	u64 timeout;
+	struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
+	struct sdio_func *func = i2400ms->func;
+	struct device *dev = &func->dev;
+
+	BUG_ON(sizeof(*ack) > ack_size);
+
+	d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n",
+		  i2400m, ack, ack_size);
+
+	timeout = get_jiffies_64() + 2 * HZ;
+	sdio_claim_host(func);
+	while (1) {
+		if (time_after64(get_jiffies_64(), timeout)) {
+			rx_size = -ETIMEDOUT;
+			dev_err(dev, "timeout waiting for ack data\n");
+			goto error_timedout;
+		}
+
+		/* Find the RX size, check if it fits or not -- it if
+		 * doesn't fit, fail, as we have no way to dispose of
+		 * the extra data. */
+		rx_size = __i2400ms_rx_get_size(i2400ms);
+		if (rx_size < 0)
+			goto error_rx_get_size;
+		result = -ENOSPC;		/* Check it fits */
+		if (rx_size < sizeof(*ack)) {
+			rx_size = -EIO;
+			dev_err(dev, "HW BUG? received is too small (%zu vs "
+				"%zu needed)\n", sizeof(*ack), rx_size);
+			goto error_too_small;
+		}
+		if (rx_size > I2400M_BM_ACK_BUF_SIZE) {
+			dev_err(dev, "SW BUG? BM_ACK_BUF is too small (%u vs "
+				"%zu needed)\n", I2400M_BM_ACK_BUF_SIZE,
+				rx_size);
+			goto error_too_small;
+		}
+
+		/* Read it */
+		result = sdio_memcpy_fromio(func, i2400m->bm_ack_buf,
+					    I2400MS_DATA_ADDR, rx_size);
+		if (result == -ETIMEDOUT || result == -ETIME)
+			continue;
+		if (result < 0) {
+			dev_err(dev, "BM SDIO receive (%zu B) failed: %d\n",
+				rx_size, result);
+			goto error_read;
+		} else
+			break;
+	}
+	rx_size = min((ssize_t)ack_size, rx_size);
+	memcpy(ack, i2400m->bm_ack_buf, rx_size);
+error_read:
+error_too_small:
+error_rx_get_size:
+error_timedout:
+	sdio_release_host(func);
+	d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %ld\n",
+		i2400m, ack, ack_size, (long) rx_size);
+	return rx_size;
+}
-- 
1.5.6.5

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[PATCH 00/40] merge request for WiMAX kernel stack and i24 ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:54 am)
[PATCH 01/40] wimax: documentation for the stack, Inaky Perez-Gonzalez, (Fri Dec 5, 11:54 am)
[PATCH 02/40] wimax: declarations for the in-kernel WiMAX API, Inaky Perez-Gonzalez, (Fri Dec 5, 11:54 am)
[PATCH 03/40] wimax: constants and definitions to interact ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:54 am)
[PATCH 04/40] wimax: internal API for the kernel space WiM ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:54 am)
[PATCH 05/40] wimax: debug macros and debug settings for t ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:54 am)
[PATCH 06/40] genetlink: export genl_unregister_mc_group(), Inaky Perez-Gonzalez, (Fri Dec 5, 11:54 am)
[PATCH 07/40] debugfs: add helpers for exporting a size_t ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 08/40] wimax: generic WiMAX device management (regi ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 09/40] wimax: Mappping of generic netlink family ID ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 10/40] wimax: Generic messaging interface between u ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 11/40] wimax: RF-kill framework integration, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 12/40] wimax: API call to reset a WiMAX device, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 13/40] wimax: debugfs controls, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 14/40] wimax: Makefile, Kconfig and docbook linkage ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 15/40] i2400m: documentation and instructions for usage, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 16/40] i2400m: host-to-device protocol definitions, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 17/40] i2400m: core driver definitions and API, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 18/40] i2400m: Generic probe/disconnect, reset and ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 19/40] i2400m: linkage to the networking stack, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 20/40] i2400m: debugfs controls, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 21/40] i2400m: rfkill integration with the WiMAX stack, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 22/40] i2400m: firmware loading and bootrom initial ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 23/40] i2400m: handling of the data/control recepti ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 24/40] i2400m: handling of the data/control transmi ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 25/40] i2400m: various functions for device management, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 26/40] i2400m/USB: header for the USB bus driver, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 27/40] i2400m/USB: error density tracking, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 28/40] i2400m/USB: main probe/disconnect and backen ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 29/40] i2400m/USB: firmware upload backend, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 30/40] i2400m/USB: handling of notifications from t ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 31/40] i2400m/USB: read transactions from the USB d ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 32/40] i2400m/USB: write transactions to the USB device, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 33/40] i2400m/SDIO: header for the SDIO subdriver, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 34/40] i2400m/SDIO: main probe/disconnect and backe ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 35/40] i2400m/SDIO: firmware upload backend, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 36/40] i2400m/SDIO: read transactions from the SDIO ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 37/40] i2400m/SDIO: write transactions to the SDIO ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 38/40] i2400m: Makefile and Kconfig, Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 39/40] wimax: export linux/wimax.h and linux/wimax/ ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
[PATCH 40/40] wimax/i2400m: add CREDITS and MAINTAINERS en ..., Inaky Perez-Gonzalez, (Fri Dec 5, 11:55 am)
Re: [PATCH 02/40] wimax: declarations for the in-kernel Wi ..., Inaky Perez-Gonzalez, (Sat Dec 6, 6:04 pm)