[PATCH] wimax/i2400m: implement RX reorder support

Previous thread: none

Next thread: PATCH tcp_init_wl / tcp_update_wl argument cleanup by ithilgore.ryu.L@gmail.com on Sunday, March 1, 2009 - 3:37 am. (4 messages)
From: Inaky Perez-Gonzalez
Date: Sunday, March 1, 2009 - 2:42 am

In order to support backwards compatibility with older firmwares when
a driver is updated by a new kernel release, the i2400m bus drivers
can declare a list of firmware files they can work with (in general
these will be each a different version). The firmware loader will try
them in sequence until one loads.

Thus, if a user doesn't have the latest and greatest firmware that a
newly installed kernel would require, the driver would fall back to
the firmware from a previous release.

To support this, the i2400m->bus_fw_name is changed to be a NULL
terminated array firmware file names (and renamed to bus_fw_names) and
we add a new entry (i2400m->fw_name) that points to the name of the
firmware being currently used. All code that needs to print the
firmware file name uses i2400m->fw_name instead of the old
i2400m->bus_fw_name.

The code in i2400m_dev_bootstrap() that loads the firmware is changed
with an iterator over the firmware file name list that tries to load
each form user space, using the first one that succeeds in
request_firmware() (and thus stopping the iteration).

The USB and SDIO bus drivers are updated to take advantage of this and
reflect which firmwares they support.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/fw.c     |   53 +++++++++++++++++++++++--------------
 drivers/net/wimax/i2400m/i2400m.h |   21 ++++++++------
 drivers/net/wimax/i2400m/sdio.c   |   11 +++++--
 drivers/net/wimax/i2400m/usb.c    |   14 +++++++--
 4 files changed, 64 insertions(+), 35 deletions(-)

diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index ecd0cfa..675c6ce 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -483,7 +483,7 @@ ssize_t i2400m_dnload_bcf(struct i2400m *i2400m,
 		if (offset + section_size > bcf_len) {
 			dev_err(dev, "fw %s: bad section #%zu, "
 				"end (@%zu) beyond EOF (@%zu)\n",
-				i2400m->bus_fw_name, section,
+				i2400m->fw_name, section,
 ...
From: Inaky Perez-Gonzalez
Date: Sunday, March 1, 2009 - 2:42 am

Firmware interface version 8.x.x has long been deprecated and is no
longer supported (nor available, as it is a preproduction firmware),
so it can be safely dropped.

Add support for firmware interface v9.2.x (current is 9.1.x). Firmware
version 9.2.x is backwards compatible with 9.1.x; new features are
enabled if switches are pressed to turn them on. Forthcoming commits
to the driver will start pressing those switches when the firmware
interface supports it.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/control.c |   14 +++++---------
 1 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index 15d9f51..ac8fb6d 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -942,8 +942,8 @@ error_cmd_failed:
 /* Firmware interface versions we support */
 enum {
 	I2400M_HDIv_MAJOR = 9,
-	I2400M_HDIv_MAJOR_2 = 8,
 	I2400M_HDIv_MINOR = 1,
+	I2400M_HDIv_MINOR_2 = 2,
 };
 
 
@@ -1009,18 +1009,14 @@ int i2400m_firmware_check(struct i2400m *i2400m)
 	minor = le16_to_cpu(l4mv->minor);
 	branch = le16_to_cpu(l4mv->branch);
 	result = -EINVAL;
-	if (major != I2400M_HDIv_MAJOR
-	    && major != I2400M_HDIv_MAJOR_2) {
-		dev_err(dev, "unsupported major fw interface version "
+	if (major != I2400M_HDIv_MAJOR) {
+		dev_err(dev, "unsupported major fw version "
 			"%u.%u.%u\n", major, minor, branch);
 		goto error_bad_major;
 	}
-	if (major == I2400M_HDIv_MAJOR_2)
-		dev_err(dev, "deprecated major fw interface version "
-			"%u.%u.%u\n", major, minor, branch);
 	result = 0;
-	if (minor != I2400M_HDIv_MINOR)
-		dev_warn(dev, "untested minor fw firmware version %u.%u.%u\n",
+	if (minor < I2400M_HDIv_MINOR_2 && minor > I2400M_HDIv_MINOR)
+		dev_warn(dev, "untested minor fw version %u.%u.%u\n",
 			 major, minor, branch);
 error_bad_major:
 	dev_info(dev, "firmware interface version %u.%u.%u\n",
-- 
1.5.6.5

--

From: Inaky Perez-Gonzalez
Date: Sunday, March 1, 2009 - 2:42 am

Upcoming modifications will need to test for the running firmware
version before activating a feature or not. This is helpful to
implement backward compatibility with older firmware versions.

Modify i2400m_firmware_check() to encode in i2400m->fw_version the
major and minor version numbers of the firmware interface.

As well, move the call to be done as the very first operation once we
have communication with the device during probe() [in
__i2400m_dev_start()]. This is needed so any operation that is
executed afterwards can determine which fw version it is talking to.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/control.c |   12 +++++++-----
 drivers/net/wimax/i2400m/driver.c  |    5 +++++
 drivers/net/wimax/i2400m/i2400m.h  |    4 ++++
 3 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index ac8fb6d..c8b3a68 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -52,7 +52,6 @@
  *
  * i2400m_dev_initalize()       Called by i2400m_dev_start()
  *   i2400m_set_init_config()
- *   i2400m_firmware_check()
  *   i2400m_cmd_get_state()
  * i2400m_dev_shutdown()        Called by i2400m_dev_stop()
  *   i2400m->bus_reset()
@@ -959,6 +958,10 @@ enum {
  * Long function, but quite simple; first chunk launches the command
  * and double checks the reply for the right TLV. Then we process the
  * TLV (where the meat is).
+ *
+ * Once we process the TLV that gives us the firmware's interface
+ * version, we encode it and save it in i2400m->fw_version for future
+ * reference.
  */
 int i2400m_firmware_check(struct i2400m *i2400m)
 {
@@ -1018,9 +1021,11 @@ int i2400m_firmware_check(struct i2400m *i2400m)
 	if (minor < I2400M_HDIv_MINOR_2 && minor > I2400M_HDIv_MINOR)
 		dev_warn(dev, "untested minor fw version %u.%u.%u\n",
 			 major, minor, branch);
-error_bad_major:
+	/* Yes, we ignore the branch -- we ...
From: Inaky Perez-Gonzalez
Date: Sunday, March 1, 2009 - 2:42 am

For power saving reasons, WiMAX links can be put in idle mode while
connected after a certain time of the link not being used for tx or
rx. In this mode, the device pages the base-station regularly and when
data is ready to be transmitted, the link is revived.

This patch allows the user to control the time the device has to be
idle before it decides to go to idle mode from a sysfs
interace.

It also updates the initialization code to acknowledge the module
variable 'idle_mode_disabled' when the firmware is a newer version
(upcoming 1.4 vs 2.6.29's v1.3).

The method for setting the idle mode timeout in the older firmwares is
much more limited and can be only done at initialization time. Thus,
the sysfs file will return -ENOSYS on older ones.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/Makefile       |    1 +
 drivers/net/wimax/i2400m/control.c      |   98 ++++++++++++++++++++++++++++---
 drivers/net/wimax/i2400m/debug-levels.h |    1 +
 drivers/net/wimax/i2400m/driver.c       |   10 +++
 drivers/net/wimax/i2400m/i2400m.h       |   29 +++++++++
 drivers/net/wimax/i2400m/sysfs.c        |   80 +++++++++++++++++++++++++
 include/linux/wimax/i2400m.h            |   10 +++
 7 files changed, 221 insertions(+), 8 deletions(-)
 create mode 100644 drivers/net/wimax/i2400m/sysfs.c

diff --git a/drivers/net/wimax/i2400m/Makefile b/drivers/net/wimax/i2400m/Makefile
index 1696e93..5d9e018 100644
--- a/drivers/net/wimax/i2400m/Makefile
+++ b/drivers/net/wimax/i2400m/Makefile
@@ -8,6 +8,7 @@ i2400m-y :=		\
 	driver.o	\
 	fw.o		\
 	op-rfkill.o	\
+	sysfs.o		\
 	netdev.o	\
 	tx.o		\
 	rx.o
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index c8b3a68..c3968b2 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -1222,6 +1222,77 @@ EXPORT_SYMBOL_GPL(i2400m_set_init_config);
 
 
 /**
+ * i2400m_set_idle_timeout - Set the device's idle mode timeout
+ *
+ * ...
From: Inaky Perez-Gonzalez
Date: Sunday, March 1, 2009 - 2:42 am

From: Kay Sievers <kay.sievers@vrfy.org>

Cc: inaky.perez-gonzalez@intel.com
Cc: linux-wimax@intel.com
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/driver.c    |    2 +-
 drivers/net/wimax/i2400m/usb-notif.c |    2 +-
 include/linux/wimax/debug.h          |    2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index f988771..e4f1ce5 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -618,7 +618,7 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
 	d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
 
 	snprintf(wimax_dev->name, sizeof(wimax_dev->name),
-		 "i2400m-%s:%s", dev->bus->name, dev->bus_id);
+		 "i2400m-%s:%s", dev->bus->name, dev_name(dev));
 
 	i2400m->bm_cmd_buf = kzalloc(I2400M_BM_CMD_BUF_SIZE, GFP_KERNEL);
 	if (i2400m->bm_cmd_buf == NULL) {
diff --git a/drivers/net/wimax/i2400m/usb-notif.c b/drivers/net/wimax/i2400m/usb-notif.c
index 9702c22..6add27c 100644
--- a/drivers/net/wimax/i2400m/usb-notif.c
+++ b/drivers/net/wimax/i2400m/usb-notif.c
@@ -102,7 +102,7 @@ int i2400mu_notification_grok(struct i2400mu *i2400mu, const void *buf,
 		dev_err(dev, "HW BUG? Unknown/unexpected data in notification "
 			"message (%zu bytes)\n", buf_len);
 		snprintf(prefix, sizeof(prefix), "%s %s: ",
-			 dev_driver_string(dev) , dev->bus_id);
+			 dev_driver_string(dev), dev_name(dev));
 		if (buf_len > 64) {
 			print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET,
 				       8, 4, buf, 64, 0);
diff --git a/include/linux/wimax/debug.h b/include/linux/wimax/debug.h
index ba0c493..c703e03 100644
--- a/include/linux/wimax/debug.h
+++ b/include/linux/wimax/debug.h
@@ -178,7 +178,7 @@ void __d_head(char *head, size_t head_size,
 		WARN_ON(1);
 	} else
 		snprintf(head, head_size, "%s %s: ",
-			 ...
From: Inaky Perez-Gonzalez
Date: Sunday, March 1, 2009 - 2:42 am

Newer i2400m firmwares (>= v1.4) extend the data RX protocol so that
each packet has a 16 byte header. This header is mainly used to
implement host reordeing (which is addressed in later commits).

However, this header also allows us to overwrite it (once data has
been extracted) with an Ethernet header and deliver to the networking
stack without having to reallocate the skb (as it happened in fw <=
v1.3) to make room for it.

- control.c: indicate the device [dev_initialize()] that the driver
  wants to use the extended data RX protocol. Also involves adding the
  definition of the needed data types in include/linux/wimax/i2400m.h.

- rx.c: handle the new payload type for the extended RX data
  protocol. Prepares the skb for delivery to
  netdev.c:i2400m_net_erx().

- netdev.c: Introduce i2400m_net_erx() that adds the fake ethernet
  address to a prepared skb and delivers it to the networking
  stack.

- cleanup: in most instances in rx.c, the variable 'single' was
  renamed to 'single_last' for it better conveys its meaning.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/control.c |    9 +++
 drivers/net/wimax/i2400m/i2400m.h  |    2 +
 drivers/net/wimax/i2400m/netdev.c  |  104 ++++++++++++++++++++++++--------
 drivers/net/wimax/i2400m/rx.c      |  117 +++++++++++++++++++++++++++++++++---
 include/linux/wimax/i2400m.h       |   35 +++++++++++
 5 files changed, 234 insertions(+), 33 deletions(-)

diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index c3968b2..4073c3e 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -1311,6 +1311,7 @@ int i2400m_dev_initialize(struct i2400m *i2400m)
 	struct device *dev = i2400m_dev(i2400m);
 	struct i2400m_tlv_config_idle_parameters idle_params;
 	struct i2400m_tlv_config_idle_timeout idle_timeout;
+	struct i2400m_tlv_config_d2h_data_format df;
 	const struct i2400m_tlv_hdr *args[9];
 	unsigned argc = 0;
 
@@ ...
From: Inaky Perez-Gonzalez
Date: Sunday, March 1, 2009 - 2:42 am

From: Harvey Harrison <harvey.harrison@gmail.com>

Base versions handle constant folding now.

Edited by Inaky to fix conflicts due to changes in netdev.c

Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/netdev.c |   10 ++++++----
 1 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
index 2bdd0cd..a98eb4b 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -402,13 +402,13 @@ void i2400m_tx_timeout(struct net_device *net_dev)
  */
 static
 void i2400m_rx_fake_eth_header(struct net_device *net_dev,
-			       void *_eth_hdr, int protocol)
+			       void *_eth_hdr, __be16 protocol)
 {
 	struct ethhdr *eth_hdr = _eth_hdr;
 
 	memcpy(eth_hdr->h_dest, net_dev->dev_addr, sizeof(eth_hdr->h_dest));
 	memset(eth_hdr->h_source, 0, sizeof(eth_hdr->h_dest));
-	eth_hdr->h_proto = cpu_to_be16(protocol);
+	eth_hdr->h_proto = protocol;
 }
 
 
@@ -474,7 +474,8 @@ void i2400m_net_rx(struct i2400m *i2400m, struct sk_buff *skb_rx,
 		memcpy(skb_put(skb, buf_len), buf, buf_len);
 	}
 	i2400m_rx_fake_eth_header(i2400m->wimax_dev.net_dev,
-				  skb->data - ETH_HLEN, ETH_P_IP);
+				  skb->data - ETH_HLEN,
+				  cpu_to_be16(ETH_P_IP));
 	skb_set_mac_header(skb, -ETH_HLEN);
 	skb->dev = i2400m->wimax_dev.net_dev;
 	skb->protocol = htons(ETH_P_IP);
@@ -526,7 +527,8 @@ void i2400m_net_erx(struct i2400m *i2400m, struct sk_buff *skb,
 	case I2400M_CS_IPV4:
 		protocol = ETH_P_IP;
 		i2400m_rx_fake_eth_header(i2400m->wimax_dev.net_dev,
-					  skb->data - ETH_HLEN, ETH_P_IP);
+					  skb->data - ETH_HLEN,
+					  cpu_to_be16(ETH_P_IP));
 		skb_set_mac_header(skb, -ETH_HLEN);
 		skb->dev = i2400m->wimax_dev.net_dev;
 		skb->protocol = htons(ETH_P_IP);
-- 
1.5.6.5

--

From: Harvey Harrison
Date: Sunday, March 1, 2009 - 12:06 pm

I'm not sure the description matches the patch...or the rest of the
patch is missing.

Harvey

--

From: Inaky Perez-Gonzalez
Date: Sunday, March 1, 2009 - 5:07 pm

This is a conflict fix -- yours (the original) is still in the tree, (way) 
before this series. 

However, some of the code merged in with my fixes conflicted with your 
edits, so only those are changed to reflect the new code (hence the 
"Edited" line).

Hope this clarifies

-- 
Inaky
--

From: Inaky Perez-Gonzalez
Date: Sunday, March 1, 2009 - 2:42 am

Allow the device to give the driver RX data with reorder information.

When that is done, the device will indicate the driver if a packet has
to be held in a (sorted) queue. It will also tell the driver when held
packets have to be released to the OS.

This is done to improve the WiMAX-protocol level retransmission
support when missing frames are detected.

The code docs provide details about the implementation.

In general, this just hooks into the RX path in rx.c; if a packet with
the reorder bit in the RX header is detected, the reorder information
in the header is extracted and one of the four main reorder operations
are executed. In one case (queue) no packet will be delivered to the
networking stack, just queued, whereas in the others (reset, update_ws
and queue_update_ws), queued packet might be delivered depending on
the window start for the specific queue.

The modifications to files other than rx.c are:

- control.c: during device initialization, enable reordering support
  if the rx_reorder_disabled module parameter is not enabled

- driver.c: expose a rx_reorder_disable module parameter and call
  i2400m_rx_setup/release() to initialize/shutdown RX reorder
  support.

- i2400m.h: introduce members in 'struct i2400m' needed for
  implementing reorder support.

- linux/i2400m.h: introduce TLVs, commands and constant definitions
  related to RX reorder

Last but not least, the rx reorder code includes an small circular log
where the last N reorder operations are recorded to be displayed in
case of inconsistency. Otherwise diagnosing issues would be almost
impossible.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/control.c |   14 +
 drivers/net/wimax/i2400m/driver.c  |   11 +
 drivers/net/wimax/i2400m/i2400m.h  |   19 +-
 drivers/net/wimax/i2400m/rx.c      |  677 ++++++++++++++++++++++++++++++++++--
 include/linux/wimax/i2400m.h       |   32 ++-
 5 files changed, 723 insertions(+), 30 deletions(-)

diff --git ...
From: Inaky Perez-Gonzalez
Date: Sunday, March 1, 2009 - 2:56 am

Apologies, I just realized I missed sending the cover letter

This patch series corresponds to the wimax-next tree as it stands
today, with feature additions for the i2400m driver:

 - support extended data-RX protocol and data-RX reordering
 - ability to query for a list of firmware files if the default
   doesn't work
 - control of base station idle mode timeout (with firmware >= 1.4).

The wimax stack NAP level interface (scan, connect, disconnect, etc) 
that has been proposed in the mailing list is still not really ready 
for merging, so it will be kept in a branch of wimax-next.

Harvey Harrison (1):
  wimax: replace uses of __constant_{endian}

Inaky Perez-Gonzalez (6):
  wimax/i2400m: add the ability to fallback to other firmware files if
    the default is not there
  wimax/i2400m: drop support for deprecated major fw interface, add for
    new minor
  wimax/i2400m: firmware_check() encodes the firmware version in
    i2400m->fw_version
  wimax/i2400m: allow control of the base-station idle mode timeout
  wimax/i2400m: support extended data RX protocol (no need to
    reallocate skbs)
  wimax/i2400m: implement RX reorder support

Kay Sievers (1):
  wimax: struct device - replace bus_id with dev_name(), dev_set_name()

 drivers/net/wimax/i2400m/Makefile       |    1 +
 drivers/net/wimax/i2400m/control.c      |  147 +++++-
 drivers/net/wimax/i2400m/debug-levels.h |    1 +
 drivers/net/wimax/i2400m/driver.c       |   28 ++-
 drivers/net/wimax/i2400m/fw.c           |   53 ++-
 drivers/net/wimax/i2400m/i2400m.h       |   75 +++-
 drivers/net/wimax/i2400m/netdev.c       |  106 ++++-
 drivers/net/wimax/i2400m/rx.c           |  746 
++++++++++++++++++++++++++++++-
 drivers/net/wimax/i2400m/sdio.c         |   11 +-
 drivers/net/wimax/i2400m/sysfs.c        |   80 ++++
 drivers/net/wimax/i2400m/usb-notif.c    |    2 +-
 drivers/net/wimax/i2400m/usb.c          |   14 +-
 include/linux/wimax/debug.h             |    2 +-
 include/linux/wimax/i2400m.h            |   69 ...
From: David Miller
Date: Monday, March 2, 2009 - 4:12 am

From: Inaky Perez-Gonzalez <inaky@linux.intel.com>

All applied to net-next-2.6, thanks!
--

Previous thread: none

Next thread: PATCH tcp_init_wl / tcp_update_wl argument cleanup by ithilgore.ryu.L@gmail.com on Sunday, March 1, 2009 - 3:37 am. (4 messages)