Skip to contentSkip to conversation

WiMAX pull request (v2)

PATCH In review Inaky Perez-Gonzalez 2 participants 12 messages May 29, 2009

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover WiMAX pull request (v2)

This pull request for 2.6.31 adds a new WiMAX API call for getting the device state (from Paulius Zaleckas), fixes random stuff in the i2400m, adds a debug facility to trace commands sent to the device and cleans up state-report handling code.

Changes in v2:

- Fix breakage of API noticed by Stephen Hemminger in "wimax: Add netlink interface to get device state".

The following changes since commit 7d18f114897ff4358419b14d551e704a4299a440:
David S. Miller (1):
net: Fix arg to trace_napi_poll() in netpoll.

are available in the git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/inaky/wimax.git linux-2.6.31.y

Patches follow for reviewing convenience.

Inaky Perez-Gonzalez (9):
wimax/i2400m: generate fake source MAC address with random_ether_addr() wimax/i2400m: trace commands sent from user space on the "echo" pipe wimax/i2400m: allow kernel commands to device to be logged too wimax/i2400m: factor out 'state report's TLV handling to a function wimax/i2400m: remove redundant readiness checks from i2400m_report_tlv_*()
wimax: document why wimax_msg_*() operations can be used in any state wimax/i2400m: sdio: set the block size before enabling the function wimax/i2400m: usb: fix device reset on autosuspend while not yet idle
wimax: a new API call was added, increment minor protocol version number

Paulius Zaleckas (1):
wimax: Add netlink interface to get device state

 drivers/net/wimax/i2400m/control.c |  100 ++++++++++++++++++++----------------
 drivers/net/wimax/i2400m/driver.c  |    5 +-
 drivers/net/wimax/i2400m/i2400m.h  |    5 ++
 drivers/net/wimax/i2400m/netdev.c  |    4 +-
 drivers/net/wimax/i2400m/rx.c      |    6 ++-
 drivers/net/wimax/i2400m/sdio.c    |   18 +++---
 drivers/net/wimax/i2400m/usb.c     |   35 +++++++++++--
 include/linux/wimax.h              |    7 ++-
 net/wimax/Makefile                 |    1 +
 net/wimax/debug-levels.h           |    1 +
 net/wimax/debugfs.c                |    1 +
 net/wimax/op-msg.c                 |   17 +++++-
 net/wimax/op-state-get.c           |   86 +++++++++++++++++++++++++++++++
 net/wimax/stack.c                  |    5 ++-
 14 files changed, 222 insertions(+), 69 deletions(-)
 create mode 100644 net/wimax/op-state-get.c
#1 lore raw

PATCH 1/10 wimax/i2400m: generate fake source MAC address with random_ether_addr()

The WiMAX i2400m driver needs to generate a fake source MAC address to fake an ethernet header (for destination, the card's MAC is used). This is the source of the packet, which is the basestation it came from. The basestation's mac address is not usable for this, as it uses its own namespace and it is not always available.

Currently the fake source MAC address was being set to all zeros, which was causing trouble with bridging.

Use random_ether_addr() to generate a proper one that creates no trouble.

---
 drivers/net/wimax/i2400m/driver.c |    2 ++
 drivers/net/wimax/i2400m/i2400m.h |    5 +++++
 drivers/net/wimax/i2400m/netdev.c |    4 +++-
 3 files changed, 10 insertions(+), 1 deletions(-)
drivers/net/wimax/i2400m/driver.c +2 -0
index 07a54ba..a21318b 100644
@@ -62,6 +62,7 @@
  *   unregister_netdev()
  */
 #include "i2400m.h"
+#include <linux/etherdevice.h>
 #include <linux/wimax/i2400m.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -650,6 +651,7 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
 	result = i2400m_read_mac_addr(i2400m);
 	if (result < 0)
 		goto error_read_mac_addr;
+	random_ether_addr(i2400m->src_mac_addr);
 
 	result = register_netdev(net_dev);	/* Okey dokey, bring it up */
 	if (result < 0) {
drivers/net/wimax/i2400m/i2400m.h +5 -0
index 3ae2df3..434ba31 100644
@@ -323,6 +323,10 @@ struct i2400m_roq;
  *     delivered. Then the driver can release them to the host. See
  *     drivers/net/i2400m/rx.c for details.
  *
+ * @src_mac_addr: MAC address used to make ethernet packets be coming
+ *     from. This is generated at i2400m_setup() time and used during
+ *     the life cycle of the instance. See i2400m_fake_eth_header().
+ *
  * @init_mutex: Mutex used for serializing the device bringup
  *     sequence; this way if the device reboots in the middle, we
  *     don't try to do a bringup again while we are tearing down the
@@ -421,6 +425,7 @@ struct i2400m {
 	unsigned rx_pl_num, rx_pl_max, rx_pl_min,
 		rx_num, rx_size_acc, rx_size_min, rx_size_max;
 	struct i2400m_roq *rx_roq;	/* not under rx_lock! */
+	u8 src_mac_addr[ETH_HLEN];
 
 	struct mutex msg_mutex;		/* serialize command execution */
 	struct completion msg_completion;
drivers/net/wimax/i2400m/netdev.c +3 -1
index 6b1fe7a..9653f47 100644
@@ -404,10 +404,12 @@ static
 void i2400m_rx_fake_eth_header(struct net_device *net_dev,
 			       void *_eth_hdr, __be16 protocol)
 {
+	struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
 	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));
+	memcpy(eth_hdr->h_source, i2400m->src_mac_addr,
+	       sizeof(eth_hdr->h_source));
 	eth_hdr->h_proto = protocol;
 }
 
Signature · 1 line
1.6.2.3
#2 lore raw

PATCH 2/10 wimax/i2400m: trace commands sent from user space on the "echo" pipe

In reply to Inaky Perez-Gonzalez

When commands are sent from user space, trace both the command sent and the answer received over the "echo" pipe instead of over the "trace" pipe when command tracing is enabled. As well, when the device sends a reports/indications, send it over the "echo" pipe.

The "trace" pipe is used by the device to send firmware traces; gets confusing. Another named pipe makes it easier to split debug information.

---
 drivers/net/wimax/i2400m/driver.c |   13 ++++++++++---
 drivers/net/wimax/i2400m/rx.c     |    3 +++
 2 files changed, 13 insertions(+), 3 deletions(-)
drivers/net/wimax/i2400m/driver.c +10 -3
index a21318b..d33389f 100644
@@ -231,13 +231,20 @@ int i2400m_op_msg_from_user(struct wimax_dev *wimax_dev,
 	d_fnstart(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p "
 		  "msg_len %zu genl_info %p)\n", wimax_dev, i2400m,
 		  msg_buf, msg_len, genl_info);
+	if (unlikely(i2400m->trace_msg_from_user))
+		wimax_msg(&i2400m->wimax_dev, "echo",
+			  msg_buf, msg_len, GFP_KERNEL);
 	ack_skb = i2400m_msg_to_dev(i2400m, msg_buf, msg_len);
 	result = PTR_ERR(ack_skb);
 	if (IS_ERR(ack_skb))
 		goto error_msg_to_dev;
-	if (unlikely(i2400m->trace_msg_from_user))
-		wimax_msg(&i2400m->wimax_dev, "trace",
-			  msg_buf, msg_len, GFP_KERNEL);
+	if (unlikely(i2400m->trace_msg_from_user)) {
+		const void *ack_data;
+		size_t ack_len;
+		ack_data = wimax_msg_data_len(ack_skb, &ack_len);
+		wimax_msg(&i2400m->wimax_dev, "echo",
+			  ack_data, ack_len, GFP_KERNEL);
+	}
 	result = wimax_msg_send(&i2400m->wimax_dev, ack_skb);
 error_msg_to_dev:
 	d_fnend(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p msg_len %zu "
drivers/net/wimax/i2400m/rx.c +3 -0
index f9fc389..a4adc78 100644
@@ -309,6 +309,9 @@ void i2400m_rx_ctl(struct i2400m *i2400m, struct sk_buff *skb_rx,
 		skb_get(skb_rx);
 		i2400m_queue_work(i2400m, i2400m_report_hook_work,
 				  GFP_KERNEL, &args, sizeof(args));
+		if (unlikely(i2400m->trace_msg_from_user))
+			wimax_msg(&i2400m->wimax_dev, "echo",
+				  l3l4_hdr, size, GFP_KERNEL);
 		result = wimax_msg(&i2400m->wimax_dev, NULL, l3l4_hdr, size,
 				   GFP_KERNEL);
 		if (result < 0)
Signature · 1 line
1.6.2.3
#3 lore raw

PATCH 3/10 wimax/i2400m: allow kernel commands to device to be logged too

In reply to Inaky Perez-Gonzalez

By running 'echo 1 > /sys/kernel/debug/wimax:wmxX/i2400m/trace_msg_from_user', the driver will echo to user space all the commands being sent to the device from user space, along with the responses.

However, this only helps with the commands being sent from user space; with this patch, the trace hook is moved to i2400m_msg_to_dev(), which is the single access point for running commands to the device (both by user space and the kernel driver). This allows better debugging by having a complete stream of commands/acks and reports.

---
 drivers/net/wimax/i2400m/control.c |    5 +++++
 drivers/net/wimax/i2400m/driver.c  |   10 ----------
 2 files changed, 5 insertions(+), 10 deletions(-)
drivers/net/wimax/i2400m/control.c +5 -0
index b3cadb6..0f58418 100644
@@ -721,6 +721,8 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m,
 		ack_timeout = HZ;
 	};
 
+	if (unlikely(i2400m->trace_msg_from_user))
+		wimax_msg(&i2400m->wimax_dev, "echo", buf, buf_len, GFP_KERNEL);
 	/* The RX path in rx.c will put any response for this message
 	 * in i2400m->ack_skb and wake us up. If we cancel the wait,
 	 * we need to change the value of i2400m->ack_skb to something
@@ -755,6 +757,9 @@ struct sk_buff *i2400m_msg_to_dev(struct i2400m *i2400m,
 	ack_l3l4_hdr = wimax_msg_data_len(ack_skb, &ack_len);
 
 	/* Check the ack and deliver it if it is ok */
+	if (unlikely(i2400m->trace_msg_from_user))
+		wimax_msg(&i2400m->wimax_dev, "echo",
+			  ack_l3l4_hdr, ack_len, GFP_KERNEL);
 	result = i2400m_msg_size_check(i2400m, ack_l3l4_hdr, ack_len);
 	if (result < 0) {
 		dev_err(dev, "HW BUG? reply to message 0x%04x: %d\n",
drivers/net/wimax/i2400m/driver.c +0 -10
index d33389f..ef16c57 100644
@@ -231,20 +231,10 @@ int i2400m_op_msg_from_user(struct wimax_dev *wimax_dev,
 	d_fnstart(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p "
 		  "msg_len %zu genl_info %p)\n", wimax_dev, i2400m,
 		  msg_buf, msg_len, genl_info);
-	if (unlikely(i2400m->trace_msg_from_user))
-		wimax_msg(&i2400m->wimax_dev, "echo",
-			  msg_buf, msg_len, GFP_KERNEL);
 	ack_skb = i2400m_msg_to_dev(i2400m, msg_buf, msg_len);
 	result = PTR_ERR(ack_skb);
 	if (IS_ERR(ack_skb))
 		goto error_msg_to_dev;
-	if (unlikely(i2400m->trace_msg_from_user)) {
-		const void *ack_data;
-		size_t ack_len;
-		ack_data = wimax_msg_data_len(ack_skb, &ack_len);
-		wimax_msg(&i2400m->wimax_dev, "echo",
-			  ack_data, ack_len, GFP_KERNEL);
-	}
 	result = wimax_msg_send(&i2400m->wimax_dev, ack_skb);
 error_msg_to_dev:
 	d_fnend(4, dev, "(wimax_dev %p [i2400m %p] msg_buf %p msg_len %zu "
Signature · 1 line
1.6.2.3
#4 lore raw

PATCH 4/10 wimax/i2400m: factor out 'state report's TLV handling to a function

In reply to Inaky Perez-Gonzalez

i2400m_report_state_hook() is going to get messier as we add handling code.

---
 drivers/net/wimax/i2400m/control.c |   89 ++++++++++++++++++++----------------
 1 files changed, 50 insertions(+), 39 deletions(-)
drivers/net/wimax/i2400m/control.c +50 -39
index 0f58418..b42e347 100644
@@ -400,7 +400,53 @@ out:
 
 
 /*
- * Parse a 'state report' and extract carrier on/off information
+ * Process a TLV from a 'state report'
+ *
+ * @i2400m: device descriptor
+ * @tlv: pointer to the TLV header; it has been already validated for
+ *     consistent size.
+ * @tag: for error messages
+ *
+ * Act on the TLVs from a 'state report'.
+ */
+static
+void i2400m_report_state_parse_tlv(struct i2400m *i2400m,
+				   const struct i2400m_tlv_hdr *tlv,
+				   const char *tag)
+{
+	struct device *dev = i2400m_dev(i2400m);
+	const struct i2400m_tlv_media_status *ms;
+	const struct i2400m_tlv_system_state *ss;
+	const struct i2400m_tlv_rf_switches_status *rfss;
+
+	if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE, sizeof(*ss))) {
+		ss = container_of(tlv, typeof(*ss), hdr);
+		d_printf(2, dev, "%s: system state TLV "
+			 "found (0x%04x), state 0x%08x\n",
+			 tag, I2400M_TLV_SYSTEM_STATE,
+			 le32_to_cpu(ss->state));
+		i2400m_report_tlv_system_state(i2400m, ss);
+	}
+	if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS, sizeof(*rfss))) {
+		rfss = container_of(tlv, typeof(*rfss), hdr);
+		d_printf(2, dev, "%s: RF status TLV "
+			 "found (0x%04x), sw 0x%02x hw 0x%02x\n",
+			 tag, I2400M_TLV_RF_STATUS,
+			 le32_to_cpu(rfss->sw_rf_switch),
+			 le32_to_cpu(rfss->hw_rf_switch));
+		i2400m_report_tlv_rf_switches_status(i2400m, rfss);
+	}
+	if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS, sizeof(*ms))) {
+		ms = container_of(tlv, typeof(*ms), hdr);
+		d_printf(2, dev, "%s: Media Status TLV: %u\n",
+			 tag, le32_to_cpu(ms->media_status));
+		i2400m_report_tlv_media_status(i2400m, ms);
+	}
+}
+
+
+/*
+ * Parse a 'state report' and extract information
  *
  * @i2400m: device descriptor
  * @l3l4_hdr: pointer to message; it has been already validated for
@@ -409,13 +455,7 @@ out:
  *        declaration is assumed to be congruent with @size (as in
  *        sizeof(*l3l4_hdr) + l3l4_hdr->length == size)
  *
- * Extract from the report state the system state TLV and infer from
- * there if we have a carrier or not. Update our local state and tell
- * netdev.
- *
- * When setting the carrier, it's fine to set OFF twice (for example),
- * as netif_carrier_off() will not generate two OFF events (just on
- * the transitions).
+ * Walk over the TLVs in a report state and act on them.
  */
 static
 void i2400m_report_state_hook(struct i2400m *i2400m,
@@ -424,9 +464,6 @@ void i2400m_report_state_hook(struct i2400m *i2400m,
 {
 	struct device *dev = i2400m_dev(i2400m);
 	const struct i2400m_tlv_hdr *tlv;
-	const struct i2400m_tlv_system_state *ss;
-	const struct i2400m_tlv_rf_switches_status *rfss;
-	const struct i2400m_tlv_media_status *ms;
 	size_t tlv_size = le16_to_cpu(l3l4_hdr->length);
 
 	d_fnstart(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s)\n",
@@ -434,34 +471,8 @@ void i2400m_report_state_hook(struct i2400m *i2400m,
 	tlv = NULL;
 
 	while ((tlv = i2400m_tlv_buffer_walk(i2400m, &l3l4_hdr->pl,
-					     tlv_size, tlv))) {
-		if (0 == i2400m_tlv_match(tlv, I2400M_TLV_SYSTEM_STATE,
-					  sizeof(*ss))) {
-			ss = container_of(tlv, typeof(*ss), hdr);
-			d_printf(2, dev, "%s: system state TLV "
-				 "found (0x%04x), state 0x%08x\n",
-				 tag, I2400M_TLV_SYSTEM_STATE,
-				 le32_to_cpu(ss->state));
-			i2400m_report_tlv_system_state(i2400m, ss);
-		}
-		if (0 == i2400m_tlv_match(tlv, I2400M_TLV_RF_STATUS,
-					  sizeof(*rfss))) {
-			rfss = container_of(tlv, typeof(*rfss), hdr);
-			d_printf(2, dev, "%s: RF status TLV "
-				 "found (0x%04x), sw 0x%02x hw 0x%02x\n",
-				 tag, I2400M_TLV_RF_STATUS,
-				 le32_to_cpu(rfss->sw_rf_switch),
-				 le32_to_cpu(rfss->hw_rf_switch));
-			i2400m_report_tlv_rf_switches_status(i2400m, rfss);
-		}
-		if (0 == i2400m_tlv_match(tlv, I2400M_TLV_MEDIA_STATUS,
-					  sizeof(*ms))) {
-			ms = container_of(tlv, typeof(*ms), hdr);
-			d_printf(2, dev, "%s: Media Status TLV: %u\n",
-				 tag, le32_to_cpu(ms->media_status));
-			i2400m_report_tlv_media_status(i2400m, ms);
-		}
-	}
+					     tlv_size, tlv)))
+		i2400m_report_state_parse_tlv(i2400m, tlv, tag);
 	d_fnend(4, dev, "(i2400m %p, l3l4_hdr %p, size %zu, %s) = void\n",
 		i2400m, l3l4_hdr, size, tag);
 }
Signature · 1 line
1.6.2.3
#5 lore raw

PATCH 5/10 wimax/i2400m: remove redundant readiness checks from i2400m_report_tlv_*()

In reply to Inaky Perez-Gonzalez

Functions i2400m_report_tlv*() are only called from i2400m_report_hook(), called in a workqueue by i2400m_report_hook_work(). The scheduler checks for device readiness before scheduling.

Added an extra check for readiness in i2400m_report_hook_work(), which makes all the checks down the line redundant.

Obviously the device state could change in the middle, but error handling would take care of that.

---
 drivers/net/wimax/i2400m/control.c |    6 ------
 drivers/net/wimax/i2400m/rx.c      |    3 ++-
 2 files changed, 2 insertions(+), 7 deletions(-)
drivers/net/wimax/i2400m/control.c +0 -6
index b42e347..bd193ae 100644
@@ -292,8 +292,6 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m,
 
 	d_fnstart(3, dev, "(i2400m %p ss %p [%u])\n", i2400m, ss, i2400m_state);
 
-	if (unlikely(i2400m->ready == 0))	/* act if up */
-		goto out;
 	if (i2400m->state != i2400m_state) {
 		i2400m->state = i2400m_state;
 		wake_up_all(&i2400m->state_wq);
@@ -341,7 +339,6 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m,
 		i2400m->bus_reset(i2400m, I2400M_RT_WARM);
 		break;
 	};
-out:
 	d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n",
 		i2400m, ss, i2400m_state);
 }
@@ -372,8 +369,6 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m,
 
 	d_fnstart(3, dev, "(i2400m %p ms %p [%u])\n", i2400m, ms, status);
 
-	if (unlikely(i2400m->ready == 0))	/* act if up */
-		goto out;
 	switch (status) {
 	case I2400M_MEDIA_STATUS_LINK_UP:
 		netif_carrier_on(net_dev);
@@ -393,7 +388,6 @@ void i2400m_report_tlv_media_status(struct i2400m *i2400m,
 		dev_err(dev, "HW BUG? unknown media status %u\n",
 			status);
 	};
-out:
 	d_fnend(3, dev, "(i2400m %p ms %p [%u]) = void\n",
 		i2400m, ms, status);
 }
drivers/net/wimax/i2400m/rx.c +2 -1
index a4adc78..7643850 100644
@@ -177,7 +177,8 @@ void i2400m_report_hook_work(struct work_struct *ws)
 	struct i2400m_work *iw =
 		container_of(ws, struct i2400m_work, ws);
 	struct i2400m_report_hook_args *args = (void *) iw->pl;
-	i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size);
+	if (iw->i2400m->ready)
+		i2400m_report_hook(iw->i2400m, args->l3l4_hdr, args->size);
 	kfree_skb(args->skb_rx);
 	i2400m_put(iw->i2400m);
 	kfree(iw);
Signature · 1 line
1.6.2.3
#6 lore raw

PATCH 6/10 wimax: document why wimax_msg_*() operations can be used in any state

In reply to Inaky Perez-Gonzalez

Funcion documentation for wimax_msg_alloc() and wimax_msg_send() needs to clarify that they can be used in the very early stages of a wimax_dev lifecycle.

---
 net/wimax/op-msg.c |   17 ++++++++++++++---
 1 files changed, 14 insertions(+), 3 deletions(-)
net/wimax/op-msg.c +14 -3
index 9ad4d89..d631a17 100644
@@ -108,6 +108,12 @@
  * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as
  * wimax_msg_send() depends on skb->data being placed at the
  * beginning of the user message.
+ *
+ * Unlike other WiMAX stack calls, this call can be used way early,
+ * even before wimax_dev_add() is called, as long as the
+ * wimax_dev->net_dev pointer is set to point to a proper
+ * net_dev. This is so that drivers can use it early in case they need
+ * to send stuff around or communicate with user space.
  */
 struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev,
 				const char *pipe_name,
@@ -115,7 +121,7 @@ struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev,
 				gfp_t gfp_flags)
 {
 	int result;
-	struct device *dev = wimax_dev->net_dev->dev.parent;
+	struct device *dev = wimax_dev_to_dev(wimax_dev);
 	size_t msg_size;
 	void *genl_msg;
 	struct sk_buff *skb;
@@ -161,7 +167,6 @@ error_genlmsg_put:
 error_new:
 	nlmsg_free(skb);
 	return ERR_PTR(result);
-
 }
 EXPORT_SYMBOL_GPL(wimax_msg_alloc);
 
@@ -256,10 +261,16 @@ EXPORT_SYMBOL_GPL(wimax_msg_len);
  * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as
  * wimax_msg_send() depends on skb->data being placed at the
  * beginning of the user message.
+ *
+ * Unlike other WiMAX stack calls, this call can be used way early,
+ * even before wimax_dev_add() is called, as long as the
+ * wimax_dev->net_dev pointer is set to point to a proper
+ * net_dev. This is so that drivers can use it early in case they need
+ * to send stuff around or communicate with user space.
  */
 int wimax_msg_send(struct wimax_dev *wimax_dev, struct sk_buff *skb)
 {
-	struct device *dev = wimax_dev->net_dev->dev.parent;
+	struct device *dev = wimax_dev_to_dev(wimax_dev);
 	void *msg = skb->data;
 	size_t size = skb->len;
 	might_sleep();
Signature · 1 line
1.6.2.3
#7 lore raw

PATCH 7/10 wimax/i2400m: sdio: set the block size before enabling the function

In reply to Inaky Perez-Gonzalez
Quoted 1 line

From a fix by Cindy H Kao:

Block size has to be set before sending IOE enable because the firmware reads the block size register before it reads IOE register.

---
 drivers/net/wimax/i2400m/sdio.c |   18 +++++++++---------
 1 files changed, 9 insertions(+), 9 deletions(-)
drivers/net/wimax/i2400m/sdio.c +9 -9
index 5ac5e76..777c981 100644
@@ -409,19 +409,19 @@ int i2400ms_probe(struct sdio_func *func,
 	i2400m->bus_fw_names = i2400ms_bus_fw_names;
 	i2400m->bus_bm_mac_addr_impaired = 1;
 
-	result = i2400ms_enable_function(i2400ms->func);
-	if (result < 0) {
-		dev_err(dev, "Cannot enable SDIO function: %d\n", result);
-		goto error_func_enable;
-	}
-
 	sdio_claim_host(func);
 	result = sdio_set_block_size(func, I2400MS_BLK_SIZE);
+	sdio_release_host(func);
 	if (result < 0) {
 		dev_err(dev, "Failed to set block size: %d\n", result);
 		goto error_set_blk_size;
 	}
-	sdio_release_host(func);
+
+	result = i2400ms_enable_function(i2400ms->func);
+	if (result < 0) {
+		dev_err(dev, "Cannot enable SDIO function: %d\n", result);
+		goto error_func_enable;
+	}
 
 	result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT);
 	if (result < 0) {
@@ -440,12 +440,12 @@ int i2400ms_probe(struct sdio_func *func,
 error_debugfs_add:
 	i2400m_release(i2400m);
 error_setup:
-	sdio_set_drvdata(func, NULL);
 	sdio_claim_host(func);
-error_set_blk_size:
 	sdio_disable_func(func);
 	sdio_release_host(func);
 error_func_enable:
+error_set_blk_size:
+	sdio_set_drvdata(func, NULL);
 	free_netdev(net_dev);
 error_alloc_netdev:
 	return result;
Signature · 1 line
1.6.2.3
#8 lore raw

PATCH 8/10 wimax: Add netlink interface to get device state

In reply to Inaky Perez-Gonzalez

From: Paulius Zaleckas <[email protected]>

wimax connection manager / daemon has to know what is current state of the device. Previously it was only possible to get notification whet state has changed.

Note:

By mistake, the new generic netlink's number for WIMAX_GNL_OP_STATE_GET was declared inserting into the existing list of API calls, not appending; thus, it'd break existing API.

Fixed by Inaky Perez-Gonzalez <[email protected]> by moving to the tail, where we add to the interface, not modify the interface.

Thanks to Stephen Hemminger <[email protected]> for catching this.

---
 include/linux/wimax.h    |    5 +++
 net/wimax/Makefile       |    1 +
 net/wimax/debug-levels.h |    1 +
 net/wimax/debugfs.c      |    1 +
 net/wimax/op-state-get.c |   86 ++++++++++++++++++++++++++++++++++++++++++++++
 net/wimax/stack.c        |    5 ++-
 6 files changed, 98 insertions(+), 1 deletions(-)
 create mode 100644 net/wimax/op-state-get.c
include/linux/wimax.h +5 -0
index c89de7f..2f7a6b7 100644
@@ -78,6 +78,7 @@ enum {
 	WIMAX_GNL_OP_RFKILL,	/* Run wimax_rfkill() */
 	WIMAX_GNL_OP_RESET,	/* Run wimax_rfkill() */
 	WIMAX_GNL_RE_STATE_CHANGE,	/* Report: status change */
+	WIMAX_GNL_OP_STATE_GET,		/* Request for current state */
 };
 
 
@@ -113,6 +114,10 @@ enum {
 	WIMAX_GNL_RESET_IFIDX = 1,
 };
 
+/* Atributes for wimax_state_get() */
+enum {
+	WIMAX_GNL_STGET_IFIDX = 1,
+};
 
 /*
  * Attributes for the Report State Change
net/wimax/Makefile +1 -0
index 5b80b94..8f1510d 100644
@@ -6,6 +6,7 @@ wimax-y :=		\
 	op-msg.o	\
 	op-reset.o	\
 	op-rfkill.o	\
+	op-state-get.o	\
 	stack.o
 
 wimax-$(CONFIG_DEBUG_FS) += debugfs.o
net/wimax/debug-levels.h +1 -0
index 1c29123..0975adb 100644
@@ -36,6 +36,7 @@ enum d_module {
 	D_SUBMODULE_DECLARE(op_msg),
 	D_SUBMODULE_DECLARE(op_reset),
 	D_SUBMODULE_DECLARE(op_rfkill),
+	D_SUBMODULE_DECLARE(op_state_get),
 	D_SUBMODULE_DECLARE(stack),
 };
 
net/wimax/debugfs.c +1 -0
index 94d216a..6c9bedb 100644
@@ -61,6 +61,7 @@ int wimax_debugfs_add(struct wimax_dev *wimax_dev)
 	__debugfs_register("wimax_dl_", op_msg, dentry);
 	__debugfs_register("wimax_dl_", op_reset, dentry);
 	__debugfs_register("wimax_dl_", op_rfkill, dentry);
+	__debugfs_register("wimax_dl_", op_state_get, dentry);
 	__debugfs_register("wimax_dl_", stack, dentry);
 	result = 0;
 out:
net/wimax/op-state-get.c new file +86 -0

86 lines not on this page · raw message

net/wimax/stack.c +4 -1
index 933e142..79fb7d7 100644
@@ -402,13 +402,15 @@ EXPORT_SYMBOL_GPL(wimax_dev_init);
 extern struct genl_ops
 	wimax_gnl_msg_from_user,
 	wimax_gnl_reset,
-	wimax_gnl_rfkill;
+	wimax_gnl_rfkill,
+	wimax_gnl_state_get;
 
 static
 struct genl_ops *wimax_gnl_ops[] = {
 	&wimax_gnl_msg_from_user,
 	&wimax_gnl_reset,
 	&wimax_gnl_rfkill,
+	&wimax_gnl_state_get,
 };
 
 
@@ -533,6 +535,7 @@ struct d_level D_LEVEL[] = {
 	D_SUBMODULE_DEFINE(op_msg),
 	D_SUBMODULE_DEFINE(op_reset),
 	D_SUBMODULE_DEFINE(op_rfkill),
+	D_SUBMODULE_DEFINE(op_state_get),
 	D_SUBMODULE_DEFINE(stack),
 };
 size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL);
Signature · 1 line
1.6.2.3
#9 lore raw

PATCH 9/10 wimax/i2400m: usb: fix device reset on autosuspend while not yet idle

In reply to Inaky Perez-Gonzalez

When the i2400m is connected to a network, the host interface (USB) cannot be suspended. For that to happen, the device has to have negotiated with the basestation to put the link on IDLE state.

If the host tries to put the device in standby while it is connected but not idle, the device resets, as the driver should not do that.

To avoid triggering that, when the USB susbsytem requires the driver to autosuspend the device, the driver checks if the device is not yet idle. If it is not, the request is requested (will be retried again later on after the autosuspend timeout). At some point the device will enter idle and the request will succeed (unless of course, there is network traffic, but at that point, there is no idle neither in the link or the host interface).

---
 drivers/net/wimax/i2400m/usb.c |   35 ++++++++++++++++++++++++++++++-----
 1 files changed, 30 insertions(+), 5 deletions(-)
drivers/net/wimax/i2400m/usb.c +30 -5
index ca4151a..1785132 100644
@@ -505,27 +505,52 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg)
 #ifdef CONFIG_PM
 	struct usb_device *usb_dev = i2400mu->usb_dev;
 #endif
+	unsigned is_autosuspend = 0;
 	struct i2400m *i2400m = &i2400mu->i2400m;
 
+#ifdef CONFIG_PM
+	if (usb_dev->auto_pm > 0)
+		is_autosuspend = 1;
+#endif
+
 	d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event);
 	if (i2400m->updown == 0)
 		goto no_firmware;
-	d_printf(1, dev, "fw up, requesting standby\n");
+	if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) {
+		/* ugh -- the device is connected and this suspend
+		 * request is an autosuspend one (not a system standby
+		 * / hibernate).
+		 *
+		 * The only way the device can go to standby is if the
+		 * link with the base station is in IDLE mode; that
+		 * were the case, we'd be in status
+		 * I2400M_SS_CONNECTED_IDLE. But we are not.
+		 *
+		 * If we *tell* him to go power save now, it'll reset
+		 * as a precautionary measure, so if this is an
+		 * autosuspend thing, say no and it'll come back
+		 * later, when the link is IDLE
+		 */
+		result = -EBADF;
+		d_printf(1, dev, "fw up, link up, not-idle, autosuspend: "
+			 "not entering powersave\n");
+		goto error_not_now;
+	}
+	d_printf(1, dev, "fw up: entering powersave\n");
 	atomic_dec(&i2400mu->do_autopm);
 	result = i2400m_cmd_enter_powersave(i2400m);
 	atomic_inc(&i2400mu->do_autopm);
-#ifdef CONFIG_PM
-	if (result < 0 && usb_dev->auto_pm == 0) {
+	if (result < 0 && !is_autosuspend) {
 		/* System suspend, can't fail */
 		dev_err(dev, "failed to suspend, will reset on resume\n");
 		result = 0;
 	}
-#endif
 	if (result < 0)
 		goto error_enter_powersave;
 	i2400mu_notification_release(i2400mu);
-	d_printf(1, dev, "fw up, got standby\n");
+	d_printf(1, dev, "powersave requested\n");
 error_enter_powersave:
+error_not_now:
 no_firmware:
 	d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n",
 		iface, pm_msg.event, result);
Signature · 1 line
1.6.2.3
#10 lore raw

PATCH 10/10 wimax: a new API call was added, increment minor protocol version number

In reply to Inaky Perez-Gonzalez

As the 'state_get' API call was added, we need to increase the minor protocol version number so applications that depend on the can check it's presence.

---
 include/linux/wimax.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
include/linux/wimax.h +1 -1
index 2f7a6b7..4fdcc56 100644
@@ -59,7 +59,7 @@ enum {
 	 * M - Major: change if removing or modifying an existing call.
 	 * m - minor: change when adding a new call
 	 */
-	WIMAX_GNL_VERSION = 00,
+	WIMAX_GNL_VERSION = 01,
 	/* Generic NetLink attributes */
 	WIMAX_GNL_ATTR_INVALID = 0x00,
 	WIMAX_GNL_ATTR_MAX = 10,
Signature · 1 line
1.6.2.3
maintainer
#11 lore raw
In reply to Inaky Perez-Gonzalez

From: Inaky Perez-Gonzalez <[email protected]>
Date: Thu, 28 May 2009 18:12:04 -0700

Quoted 4 lines

This pull request for 2.6.31 adds a new WiMAX API call for getting the device state (from Paulius Zaleckas), fixes random stuff in the i2400m, adds a debug facility to trace commands sent to the device and cleans up state-report handling code.

...

Quoted 1 line

git://git.kernel.org/pub/scm/linux/kernel/git/inaky/wimax.git linux-2.6.31.y

Pulled, thanks a lot!