Netdev List
 help / color / mirror / Atom feed
* Re: [RFC] [PATCH] udp: optimize lookup of UDP sockets to by including destination address in the hash key
From: Eric Dumazet @ 2009-11-04 21:30 UTC (permalink / raw)
  To: Lucian Adrian Grijincu; +Cc: netdev, Octavian Purdila
In-Reply-To: <4AF1EC18.9090106@ixiacom.com>

Lucian Adrian Grijincu a écrit :
> Hi,
> 
> Before you look at the patch attached: I know it's not the prettiest of patches sent here. It's a work-in-progress and is ugly and incomplete (for example IPv6 is not properly updated to benefit this patch and may even be as buggy as hell right now).
> I'm sending it here to ask for an opinion on the approach.
> 
> The current approach uses one single hash to lookup UDP sockets.
> The key to the hash is calculated based on the port only.
> This works well if there aren't many sockets bound to the same port, but becomes a linear linked list search for a setup with many UPD packets bound to the same port, which does not scale much.
> 
> In this patch the hashtable lookup key takes into consideration the address the socket is bound to too.
> This will lead to better distribution for setup where there are many UDP sockets bound to the same port but different IP addresses.
> 
> There's a subtle bug lurking here: because some sockets may be bound to INADDR_ANY when checking whether a given UPD port is already taken one must search two buckets:
> * one with the key computed from the port and for the IP address of the socket
> * one with the key computed from the port and INADDR_ANY
> 
> Now if the address by which we must do the lookup is INADDR_ANY there's another problem: we can't just search it's own bucket and the bucket for INADDR_ANY (the same bucket twice) like above because there might be a socket bound to a specific address and the port we're trying to bind to.
> 
> In this case we could search the whole hash (which would take forever) or use another hash that is computed based on the port only (which this patch does).
> 
> There are other things to look after: when modifying the hashes we must take spin_locks or spin_lock_bhs. Because we now have two hashtables and one hashtable might be searched twice locks must be taken in the proper order.
> 
> I ran the attached UDP tester: it's a program that binds to a lot of UDP sockets and if run as a sender it sends lots of datagrams to the receiver which will just count the number of packets recevied.
> 
> 
> 
> == Performance stats ==
> I ran this on a 2.6.31 with and without the patch on two powerpc single core processors connected directly by 100Mbps ethernet.
> 
> * nsocks      = number of IPv4 bound sockets
> * ndgrams     = number of datagrams sent by each socket
> * payloadlen  = the lenght of the UPD message sent
> * send_time   = how many second did the sending operation take?
> * recv_dgrams = how many datagrams were successfully received?
> 
> 
> 1. nsocks=512 ndgrams=2000 payloadlen=1
> - without patch:
> 	* send_time   = 27s to 31s
> 	* recv_dgrams = 550 to 850
> - with patch:
> 	* send_time   = 35s to 36s
> 	* recv_dgrams = 507000 to 516000
> 
> 2. nsocks=512 ndgrams=4000 payloadlen=1
> - without patch:
> 	* send_time   = 53s to 60s
> 	* recv_dgrams = 650 to 1100
> - with patch:
> 	* send_time   = ~70s
> 	* recv_dgrams = 1010000 to 1034000
> 
> 3. nsocks=512 ndgrams=4000 payloadlen=1000
> - without patch:
> 	* send_time   = ~74s
> 	* recv_dgrams = 650
> - with patch:
> 	* send_time   = ~88s
> 	* recv_dgrams = 995000
> 
> 4. nsocks=256 ndgrams=2000 payloadlen=1
> - without patch:
> 	* send_time   = 13s
> 	* recv_dgrams = 370 to 720
> - with patch:
> 	* send_time   = 17s
> 	* recv_dgrams = 267000
> 
> 
> As you can see this has a hit on total send time, but the number of received packets increases by two orders of magnitude.
> 
> I'd like hear your opinion about this approach.
> If you'd like to test this, I'll be happy to port it to net-next and provide the patch.
> 
> 

I knew someone would do this kind of patch one day, I tried it one year ago :)

First of all, you are mixing several things in this patch.

Dont do this, its not possible for us to correctly review such complex patch.

Then, your patch is not based on net-next-2.6, and you really need to work on this tree.

Then, if you had worked on net-next-2.6, you whould have noticed UDP hash tables
are now dynamically sized at boot.
An admin can even force a 65536 slots hash table for heavy duty UDP servers.

Then, last point : Say I have a machine with 65000 udp sockets bound to a different port,
and a 65536 slots hash table, (sane values in fact, in order to have best performances),
then your two phase lookup will be slower than the one-phase current lookup (two cache misses
instead of one)

So your patch seems to solve a pathological case (where many udp sockets are
bounded to a particular port, but on many different IPs), and slow down 99%
of other uses.

Thanks

^ permalink raw reply

* [PATCH net-next-2.6] net_cls: Use __dev_get_by_index()
From: Eric Dumazet @ 2009-11-04 21:32 UTC (permalink / raw)
  To: David S. Miller; +Cc: Linux Netdev List

We hold RTNL in tc_dump_tfilter(), we can avoid dev_hold()/dev_put()

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 net/sched/cls_api.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 7cf6c0f..c024da7 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -404,6 +404,7 @@ static int tcf_node_dump(struct tcf_proto *tp, unsigned long n,
 			     a->cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWTFILTER);
 }
 
+/* called with RTNL */
 static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	struct net *net = sock_net(skb->sk);
@@ -422,7 +423,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
 
 	if (cb->nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*tcm)))
 		return skb->len;
-	if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
+	if ((dev = __dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
 		return skb->len;
 
 	if (!tcm->tcm_parent)
@@ -484,7 +485,6 @@ errout:
 	if (cl)
 		cops->put(q, cl);
 out:
-	dev_put(dev);
 	return skb->len;
 }
 

^ permalink raw reply related

* Re: [PATCH 19/25] mlx4: Randomizing mac addresses for slaves
From: Or Gerlitz @ 2009-11-04 21:33 UTC (permalink / raw)
  To: Roland Dreier; +Cc: Yevgeny Petrilin, linux-rdma, netdev, liranl, tziporet
In-Reply-To: <adar5seys3e.fsf@cisco.com>

On Wed, Nov 4, 2009 at 10:04 PM, Roland Dreier <rdreier@cisco.com> wrote:
>> +#define MLX4_MAC_HEAD               0x2c9000000ULL

> Is this a good idea?  You're basically choosing 24 random bits within your OUI...
> seems the chance of collision with another MAC used on the same network is
> high enough that it could easily happen in practice on a moderately big network.

yes, this has been brought by Stephen and others on this last back on
September 11th, this year @
http://marc.info/?l=linux-netdev&m=125263488409128

> Can you pick a reserved range or something?

Using different OUI for the VF device wouldn't help either I think,
since the #VF becomes fairly big even on a modest side cluster with
(say) a VM consuming VF per 1-2 cores.

Or.

^ permalink raw reply

* [PATCH 2.6.33/1 01/12] wimax/i2400m/usb: remove unnecessary power management primitive in i2400m
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax; +Cc: Oliver Neukum
In-Reply-To: <cover.1257370735.git.inaky@linux.intel.com>

From: Oliver Neukum <oliver@neukum.org>

This patch removes an unneeded power management primitive.
Power management is automatically enabled as probe ends.

Signed-off-by: Oliver Neukum <oliver@neukum.org>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/usb.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 7eadd11..bfa45f5 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -415,7 +415,6 @@ int i2400mu_probe(struct usb_interface *iface,
 #ifdef CONFIG_PM
 	iface->needs_remote_wakeup = 1;		/* autosuspend (15s delay) */
 	device_init_wakeup(dev, 1);
-	usb_autopm_enable(i2400mu->usb_iface);
 	usb_dev->autosuspend_delay = 15 * HZ;
 	usb_dev->autosuspend_disabled = 0;
 #endif
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 2.6.33/1 02/12] wimax/i2400m: fix the bootmode RX deadlock in SDIO driver
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax; +Cc: Cindy H Kao
In-Reply-To: <cover.1257370735.git.inaky@linux.intel.com>

From: Cindy H Kao <cindy.h.kao@intel.com>

i2400ms_bus_bm_wait_for_ack() causes a race condition. It happens
because this function clears i2400ms->bm_ack_size before waiting for
an interrupt, which is set by the interrupt service routine i2400ms_rx()
to indicate reception and size of received data; thus, if the interrupt
came right before the clearing/waiting, it is lost.

The fix is clear the bm_ack_size to -EINPROGRESS before we are enabling
the RX interrupt configuration in i2400ms_rx_setup(). Then everytime
when the interrupt service routine i2400ms_rx() is invoked during bootmode,
bm_ack_size is updated with the actual rx_size and it is cleared to
-EINPROGRESS again after the RX data is handled.

Signed-off-by: Cindy H Kao <cindy.h.kao@intel.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/sdio-fw.c |    8 ++++----
 drivers/net/wimax/i2400m/sdio-rx.c |    7 +++++++
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wimax/i2400m/sdio-fw.c b/drivers/net/wimax/i2400m/sdio-fw.c
index 7d6ec0f..c8dc538 100644
--- a/drivers/net/wimax/i2400m/sdio-fw.c
+++ b/drivers/net/wimax/i2400m/sdio-fw.c
@@ -177,10 +177,6 @@ ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m,
 	d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n",
 		  i2400m, ack, ack_size);
 
-	spin_lock(&i2400m->rx_lock);
-	i2400ms->bm_ack_size = -EINPROGRESS;
-	spin_unlock(&i2400m->rx_lock);
-
 	result = wait_event_timeout(i2400ms->bm_wfa_wq,
 				    i2400ms->bm_ack_size != -EINPROGRESS,
 				    2 * HZ);
@@ -199,6 +195,10 @@ ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m,
 		size = min(ack_size, i2400ms->bm_ack_size);
 		memcpy(ack, i2400m->bm_ack_buf, size);
 	}
+	/*
+	 * Remember always to clear the bm_ack_size to -EINPROGRESS
+	 * after the RX data is processed
+	 */
 	i2400ms->bm_ack_size = -EINPROGRESS;
 	spin_unlock(&i2400m->rx_lock);
 
diff --git a/drivers/net/wimax/i2400m/sdio-rx.c b/drivers/net/wimax/i2400m/sdio-rx.c
index 321bead..f6ca51a 100644
--- a/drivers/net/wimax/i2400m/sdio-rx.c
+++ b/drivers/net/wimax/i2400m/sdio-rx.c
@@ -234,6 +234,13 @@ int i2400ms_rx_setup(struct i2400ms *i2400ms)
 	init_waitqueue_head(&i2400ms->bm_wfa_wq);
 	spin_lock(&i2400m->rx_lock);
 	i2400ms->bm_wait_result = -EINPROGRESS;
+	/*
+	 * Before we are about to enable the RX interrupt, make sure
+	 * bm_ack_size is cleared to -EINPROGRESS which indicates
+	 * no RX interrupt happened yet or the previous interrupt
+	 * has been handled, we are ready to take the new interrupt
+	 */
+	i2400ms->bm_ack_size = -EINPROGRESS;
 	spin_unlock(&i2400m->rx_lock);
 
 	sdio_claim_host(func);
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 2.6.33/1 05/12] wimax: misplaced parenthesis
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax; +Cc: Roel Kluin
In-Reply-To: <cover.1257370735.git.inaky@linux.intel.com>

From: Roel Kluin <roel.kluin@gmail.com>

Fix misplaced parenthesis

Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/tx.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c
index fa16ccf..8c20802 100644
--- a/drivers/net/wimax/i2400m/tx.c
+++ b/drivers/net/wimax/i2400m/tx.c
@@ -310,7 +310,7 @@ size_t __i2400m_tx_tail_room(struct i2400m *i2400m)
 	size_t tail_room;
 	size_t tx_in;
 
-	if (unlikely(i2400m->tx_in) == 0)
+	if (unlikely(i2400m->tx_in == 0))
 		return I2400M_TX_BUF_SIZE;
 	tx_in = i2400m->tx_in % I2400M_TX_BUF_SIZE;
 	tail_room = I2400M_TX_BUF_SIZE - tx_in;
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 2.6.33/1 08/12] wimax/i2400m: Ensure boot mode cmd and ack buffers are alloc'd before first message
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax
In-Reply-To: <cover.1257370735.git.inaky@linux.intel.com>

From: Dirk Brandewie <dirk.j.brandewie@intel.com>

The change to the SDIO boot mode RX chain could try to use the cmd and
ack buffers befor they were allocated.  USB does not have the problem
but both were changed for consistency's sake.

Signed-off-by: Dirk Brandewie <dirk.j.brandewie@intel.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/driver.c |   54 +++++++++++++++++++++++++++---------
 drivers/net/wimax/i2400m/i2400m.h |    2 +
 drivers/net/wimax/i2400m/sdio.c   |   14 +++++++++
 drivers/net/wimax/i2400m/usb.c    |    8 +++++
 4 files changed, 64 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 304f044..20d574c 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -619,6 +619,46 @@ EXPORT_SYMBOL_GPL(i2400m_dev_reset_handle);
 
 
 /**
+ * i2400m_bm_buf_alloc - Alloc the command and ack buffers for boot mode
+ *
+ * Get the buffers needed to deal with boot mode messages.  These
+ * buffers need to be allocated before the sdio recieve irq is setup.
+ */
+int i2400m_bm_buf_alloc(struct i2400m *i2400m)
+{
+	int result;
+
+	result = -ENOMEM;
+	i2400m->bm_cmd_buf = kzalloc(I2400M_BM_CMD_BUF_SIZE, GFP_KERNEL);
+	if (i2400m->bm_cmd_buf == NULL)
+		goto error_bm_cmd_kzalloc;
+	i2400m->bm_ack_buf = kzalloc(I2400M_BM_ACK_BUF_SIZE, GFP_KERNEL);
+	if (i2400m->bm_ack_buf == NULL)
+		goto error_bm_ack_buf_kzalloc;
+	return 0;
+
+error_bm_ack_buf_kzalloc:
+	kfree(i2400m->bm_cmd_buf);
+error_bm_cmd_kzalloc:
+	return result;
+}
+EXPORT_SYMBOL_GPL(i2400m_bm_buf_alloc);
+
+/**
+ * i2400m_bm_buf_free - Free boot mode command and ack buffers.
+ *
+ * Free the command and ack buffers
+ *
+ */
+void i2400m_bm_buf_free(struct i2400m *i2400m)
+{
+	kfree(i2400m->bm_ack_buf);
+	kfree(i2400m->bm_cmd_buf);
+	return;
+}
+EXPORT_SYMBOL_GPL(i2400m_bm_buf_free
+);
+/**
  * i2400m_setup - bus-generic setup function for the i2400m device
  *
  * @i2400m: device descriptor (bus-specific parts have been initialized)
@@ -645,16 +685,6 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
 	snprintf(wimax_dev->name, sizeof(wimax_dev->name),
 		 "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) {
-		dev_err(dev, "cannot allocate USB command buffer\n");
-		goto error_bm_cmd_kzalloc;
-	}
-	i2400m->bm_ack_buf = kzalloc(I2400M_BM_ACK_BUF_SIZE, GFP_KERNEL);
-	if (i2400m->bm_ack_buf == NULL) {
-		dev_err(dev, "cannot allocate USB ack buffer\n");
-		goto error_bm_ack_buf_kzalloc;
-	}
 	result = i2400m_bootrom_init(i2400m, bm_flags);
 	if (result < 0) {
 		dev_err(dev, "read mac addr: bootrom init "
@@ -713,10 +743,6 @@ error_dev_start:
 error_register_netdev:
 error_read_mac_addr:
 error_bootrom_init:
-	kfree(i2400m->bm_ack_buf);
-error_bm_ack_buf_kzalloc:
-	kfree(i2400m->bm_cmd_buf);
-error_bm_cmd_kzalloc:
 	d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
 	return result;
 }
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 60330f3..a6e59f1 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -725,6 +725,8 @@ void i2400m_put(struct i2400m *i2400m)
 }
 
 extern int i2400m_dev_reset_handle(struct i2400m *);
+extern int i2400m_bm_buf_alloc(struct i2400m *i2400m);
+extern void i2400m_bm_buf_free(struct i2400m *i2400m);
 
 /*
  * _setup()/_release() are called by the probe/disconnect functions of
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index c67b026..a68232a 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -451,6 +451,18 @@ int i2400ms_probe(struct sdio_func *func,
 		goto error_func_enable;
 	}
 
+	/*
+	 * Before we are enabling the device interrupt register, make
+	 * sure the buffer used during bootmode operation is setup so
+	 * when the first D2H data interrupt comes, the memory is
+	 * available for copying the D2H data.
+	 */
+	result = i2400m_bm_buf_alloc(i2400m);
+	if (result < 0) {
+		dev_err(dev, "cannot allocate SDIO bootmode buffer\n");
+		goto error_bootmode_buf_setup;
+	}
+
 	result = i2400ms_rx_setup(i2400ms);
 	if (result < 0)
 		goto error_rx_setup;
@@ -474,6 +486,8 @@ error_debugfs_add:
 error_setup:
 	i2400ms_rx_release(i2400ms);
 error_rx_setup:
+	i2400m_bm_buf_free(i2400m);
+error_bootmode_buf_setup:
 	sdio_claim_host(func);
 	sdio_disable_func(func);
 	sdio_release_host(func);
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index bfa45f5..49d7554 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -419,6 +419,12 @@ int i2400mu_probe(struct usb_interface *iface,
 	usb_dev->autosuspend_disabled = 0;
 #endif
 
+	result = i2400m_bm_buf_alloc(i2400m);
+	if (result < 0) {
+		dev_err(dev, "cannot allocate USB bootmode buffer\n");
+		goto error_bm_buf_alloc;
+	}
+
 	result = i2400m_setup(i2400m, I2400M_BRI_MAC_REINIT);
 	if (result < 0) {
 		dev_err(dev, "cannot setup device: %d\n", result);
@@ -434,6 +440,8 @@ int i2400mu_probe(struct usb_interface *iface,
 error_debugfs_add:
 	i2400m_release(i2400m);
 error_setup:
+	i2400m_bm_buf_free(i2400m);
+error_bm_buf_alloc:
 	usb_set_intfdata(iface, NULL);
 	usb_put_dev(i2400mu->usb_dev);
 	free_netdev(net_dev);
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 2.6.33/1 09/12] wimax/i2400m: Make boot retries a BUS-specific parameter
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax; +Cc: Cindy H Kao
In-Reply-To: <cover.1257370735.git.inaky@linux.intel.com>

From: Dirk Brandewie <dirk.j.brandewie@intel.com>

In i2400m-based devices, the driver's bootloader will retry to load
the firmware when things go wrong. The driver currently has a constant
(I2400M_BOOT_RETRIES) which governs the max number of tries.

However, different SKUs of the same hardware may admit or require
different numbers of retries due to it's particulars, so it is made a
BUS specific parameter and different values are assigned for 5x50
devices versus the 3200 ones.

Signed-off-by: Dirk Brandewie <dirk.j.brandewie@intel.com>
Signed-off-by: Cindy H Kao <cindy.h.kao@intel.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/fw.c          |    2 +-
 drivers/net/wimax/i2400m/i2400m-sdio.h |    1 +
 drivers/net/wimax/i2400m/i2400m-usb.h  |    1 +
 drivers/net/wimax/i2400m/i2400m.h      |    3 ---
 drivers/net/wimax/i2400m/sdio.c        |    2 +-
 drivers/net/wimax/i2400m/usb.c         |    2 +-
 6 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index e81750e..55bd69e 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -602,7 +602,7 @@ int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags)
 	struct device *dev = i2400m_dev(i2400m);
 	struct i2400m_bootrom_header *cmd;
 	struct i2400m_bootrom_header ack;
-	int count = I2400M_BOOT_RETRIES;
+	int count = i2400m->bus_bm_retries;
 	int ack_timeout_cnt = 1;
 
 	BUILD_BUG_ON(sizeof(*cmd) != sizeof(i2400m_NBOOT_BARKER));
diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h
index 9c4e318..66884eb 100644
--- a/drivers/net/wimax/i2400m/i2400m-sdio.h
+++ b/drivers/net/wimax/i2400m/i2400m-sdio.h
@@ -67,6 +67,7 @@
 
 /* Host-Device interface for SDIO */
 enum {
+	I2400M_SDIO_BOOT_RETRIES = 3,
 	I2400MS_BLK_SIZE = 256,
 	I2400MS_PL_SIZE_MAX = 0x3E00,
 
diff --git a/drivers/net/wimax/i2400m/i2400m-usb.h b/drivers/net/wimax/i2400m/i2400m-usb.h
index 6f76558..79c3753 100644
--- a/drivers/net/wimax/i2400m/i2400m-usb.h
+++ b/drivers/net/wimax/i2400m/i2400m-usb.h
@@ -137,6 +137,7 @@ static inline int edc_inc(struct edc *edc, u16 max_err, u16 timeframe)
 
 /* Host-Device interface for USB */
 enum {
+	I2400M_USB_BOOT_RETRIES = 3,
 	I2400MU_MAX_NOTIFICATION_LEN = 256,
 	I2400MU_BLK_SIZE = 16,
 	I2400MU_PL_SIZE_MAX = 0x3EFF,
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index a6e59f1..73b4e6a 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -148,9 +148,6 @@
 
 /* Misc constants */
 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,
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index a68232a..1429608 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -430,7 +430,7 @@ int i2400ms_probe(struct sdio_func *func,
 	i2400m->bus_reset = i2400ms_bus_reset;
 	/* The iwmc3200-wimax sometimes requires the driver to try
 	 * hard when we paint it into a corner. */
-	i2400m->bus_bm_retries = I3200_BOOT_RETRIES;
+	i2400m->bus_bm_retries = I2400M_SDIO_BOOT_RETRIES;
 	i2400m->bus_bm_cmd_send = i2400ms_bus_bm_cmd_send;
 	i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack;
 	i2400m->bus_fw_names = i2400ms_bus_fw_names;
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 49d7554..8f7b16a 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -406,7 +406,7 @@ int i2400mu_probe(struct usb_interface *iface,
 	i2400m->bus_dev_stop = i2400mu_bus_dev_stop;
 	i2400m->bus_tx_kick = i2400mu_bus_tx_kick;
 	i2400m->bus_reset = i2400mu_bus_reset;
-	i2400m->bus_bm_retries = I2400M_BOOT_RETRIES;
+	i2400m->bus_bm_retries = I2400M_USB_BOOT_RETRIES;
 	i2400m->bus_bm_cmd_send = i2400mu_bus_bm_cmd_send;
 	i2400m->bus_bm_wait_for_ack = i2400mu_bus_bm_wait_for_ack;
 	i2400m->bus_fw_names = i2400mu_bus_fw_names;
-- 
1.6.2.5

^ permalink raw reply related

* [PATCH 2.6.33/1 00/12] WiMAX patches for 2.6.33 (batch #1)
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax

  [this series of patches has been split in four batches as it was too
  long; the grouping is just sequential as they are not really
  related, except for dependencies].

Misc fixes: add minimal ethtool support, silly typo fixes, and
dwelve in a set of bad SDIO subdriver's boot-mode interactions with
the hardware timings and ways it managed to corner itself into a
deadlock. 

Please pull from:

  git://git.kernel.org/pub/scm/linux/kernel/git/inaky/wimax.git

Patches follow for ease of review.


Cindy H Kao (4):
  wimax/i2400m: fix the bootmode RX deadlock in SDIO driver
  wimax/iwmc3200: overwrite SDIO IOR timeout value to avoid platform
    hang
  wimax/iwmc3200: don't disable the SDIO function if enable fails
  wimax/iwmc3200: increase wait time before enable retry

Dan Williams (1):
  i2400m: minimal ethtool support

Dirk Brandewie (3):
  wimax/i2400m: Update comments to talk about SDIO reset and not USB.
  wimax/i2400m: Ensure boot mode cmd and ack buffers are alloc'd before
    first message
  wimax/i2400m: Make boot retries a BUS-specific parameter

Inaky Perez-Gonzalez (1):
  wimax: indicate initial SW rfkill state is "blocked"

Oliver Neukum (1):
  wimax/i2400m/usb: remove unnecessary power management primitive in
    i2400m

Roel Kluin (2):
  i2400m: keep index within ms_to_errno[]
  wimax: misplaced parenthesis

 drivers/net/wimax/i2400m/control.c     |    2 +-
 drivers/net/wimax/i2400m/driver.c      |   54 +++++++++++++++++++++++--------
 drivers/net/wimax/i2400m/fw.c          |    2 +-
 drivers/net/wimax/i2400m/i2400m-sdio.h |    5 ++-
 drivers/net/wimax/i2400m/i2400m-usb.h  |    1 +
 drivers/net/wimax/i2400m/i2400m.h      |    5 +--
 drivers/net/wimax/i2400m/netdev.c      |   18 ++++++++++
 drivers/net/wimax/i2400m/sdio-fw.c     |    8 ++--
 drivers/net/wimax/i2400m/sdio-rx.c     |    7 ++++
 drivers/net/wimax/i2400m/sdio.c        |   38 +++++++++++++++++-----
 drivers/net/wimax/i2400m/tx.c          |    2 +-
 drivers/net/wimax/i2400m/usb.c         |   11 +++++-
 net/wimax/op-rfkill.c                  |    1 +
 13 files changed, 118 insertions(+), 36 deletions(-)


^ permalink raw reply

* [PATCH 2.6.33/1 11/12] wimax/iwmc3200: don't disable the SDIO function if enable fails
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax; +Cc: Cindy H Kao
In-Reply-To: <cover.1257370735.git.inaky@linux.intel.com>

From: Cindy H Kao <cindy.h.kao@intel.com>

In the iwmc3200, disabling the WiMAX SDIO function when enable fails
would possibly result in a device reset triggered by the iwmc3200's
top controller since it monitors the bus reset activities from each
SDIO function. In any case, the disable makes no sense; if the enable
fails, it should not be disabled.

Thus we remove the unecessary sdio_disable_func() in
i2400ms_enable_function().

Signed-off-by: Cindy H Kao <cindy.h.kao@intel.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/sdio.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 0d64d16..9d6046f 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -130,7 +130,6 @@ int i2400ms_enable_function(struct sdio_func *func)
 			goto function_enabled;
 		}
 		d_printf(2, dev, "SDIO function failed to enable: %d\n", err);
-		sdio_disable_func(func);
 		sdio_release_host(func);
 		msleep(I2400MS_INIT_SLEEP_INTERVAL);
 	}
-- 
1.6.2.5


^ permalink raw reply related

* [PATCH 2.6.33/1 10/12] wimax/iwmc3200: overwrite SDIO IOR timeout value to avoid platform hang
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax; +Cc: Cindy H Kao
In-Reply-To: <cover.1257370735.git.inaky@linux.intel.com>

From: Cindy H Kao <cindy.h.kao@intel.com>

The default SDIO IOE wait timeout returned from iwmc3200-wimax's CCCR
is not efficient. This inefficiency will actually cause problems on
Moorestown platforms (system hang).

This is a sillicon bug that requires a software patch to by
overwritting func->enable_timeout. The new value I2400MS_IOR_TIMEOUT
is recommended and verified from the system integration results.

Future sillicon releases will have this default value corrected in the
future.

Signed-off-by: Cindy H Kao <cindy.h.kao@intel.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/i2400m-sdio.h |    2 ++
 drivers/net/wimax/i2400m/sdio.c        |    8 ++++++++
 2 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h
index 66884eb..cfaedfa 100644
--- a/drivers/net/wimax/i2400m/i2400m-sdio.h
+++ b/drivers/net/wimax/i2400m/i2400m-sdio.h
@@ -81,6 +81,8 @@ enum {
 	I2400MS_INIT_SLEEP_INTERVAL = 10,
 	/* How long to wait for the device to settle after reset */
 	I2400MS_SETTLE_TIME = 40,
+	/* The number of msec to wait for IOR after sending IOE */
+	IWMC3200_IOR_TIMEOUT = 10,
 };
 
 
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 1429608..0d64d16 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -115,6 +115,14 @@ int i2400ms_enable_function(struct sdio_func *func)
 	err = -ENODEV;
 	while (err != 0 && time_before64(get_jiffies_64(), timeout)) {
 		sdio_claim_host(func);
+		/*
+		 * There is a sillicon bug on the IWMC3200, where the
+		 * IOE timeout will cause problems on Moorestown
+		 * platforms (system hang). We explicitly overwrite
+		 * func->enable_timeout here to work around the issue.
+		 */
+		if (func->device == SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX)
+			func->enable_timeout = IWMC3200_IOR_TIMEOUT;
 		err = sdio_enable_func(func);
 		if (0 == err) {
 			sdio_release_host(func);
-- 
1.6.2.5


^ permalink raw reply related

* [PATCH 2.6.33/1 12/12] wimax/iwmc3200: increase wait time before enable retry
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax; +Cc: Cindy H Kao
In-Reply-To: <cover.1257370735.git.inaky@linux.intel.com>

From: Cindy H Kao <cindy.h.kao@intel.com>

When trying to enable the iwmc3200 WiMAX SDIO function, we loop
waiting for the top controller to be up and running (at which point we
can succesfully enable the function). Between each try we wait for
I2400MS_INIT_SLEEP_INTERVAL ms.

Integration tests have found the current value of 10ms to be too
short; it was upped to 100ms to give more time to the top controller
to be ready.

Signed-off-by: Cindy H Kao <cindy.h.kao@intel.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/i2400m-sdio.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h
index cfaedfa..18218a2 100644
--- a/drivers/net/wimax/i2400m/i2400m-sdio.h
+++ b/drivers/net/wimax/i2400m/i2400m-sdio.h
@@ -78,7 +78,7 @@ enum {
 	I2400MS_INTR_GET_SIZE_ADDR = 0x2C,
 	/* The number of ticks to wait for the device to signal that
 	 * it is ready */
-	I2400MS_INIT_SLEEP_INTERVAL = 10,
+	I2400MS_INIT_SLEEP_INTERVAL = 100,
 	/* How long to wait for the device to settle after reset */
 	I2400MS_SETTLE_TIME = 40,
 	/* The number of msec to wait for IOR after sending IOE */
-- 
1.6.2.5


^ permalink raw reply related

* [PATCH 2.6.33/1 04/12] i2400m: keep index within ms_to_errno[]
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax; +Cc: Roel Kluin
In-Reply-To: <cover.1257370735.git.inaky@linux.intel.com>

From: Roel Kluin <roel.kluin@gmail.com>

Ensure that index `status' remains within ms_to_errno[]

Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/control.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index 0730868..8fe70e7 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -263,7 +263,7 @@ int i2400m_msg_check_status(const struct i2400m_l3l4_hdr *l3l4_hdr,
 
 	if (status == 0)
 		return 0;
-	if (status > ARRAY_SIZE(ms_to_errno)) {
+	if (status >= ARRAY_SIZE(ms_to_errno)) {
 		str = "unknown status code";
 		result = -EBADR;
 	} else {
-- 
1.6.2.5


^ permalink raw reply related

* [PATCH 2.6.33/1 03/12] wimax: indicate initial SW rfkill state is "blocked"
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax
In-Reply-To: <cover.1257370735.git.inaky@linux.intel.com>

The WiMAX stack assumes that all WiMAX devices are SW OFF when they
are initialized. The recent changes in the RFKILL stack thus cause an
initial call after rfkill_register(), because by default, rfkill
considers devices to be SW ON upon registration.

So call rfkill_init_sw_state() to set it to SW OFF so
rfkill_register() doesn't do that unnecessary step.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 net/wimax/op-rfkill.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/net/wimax/op-rfkill.c b/net/wimax/op-rfkill.c
index 70ef4df..40e1210 100644
--- a/net/wimax/op-rfkill.c
+++ b/net/wimax/op-rfkill.c
@@ -355,6 +355,7 @@ int wimax_rfkill_add(struct wimax_dev *wimax_dev)
 
 	wimax_dev->rfkill = rfkill;
 
+	rfkill_init_sw_state(rfkill, 1);
 	result = rfkill_register(wimax_dev->rfkill);
 	if (result < 0)
 		goto error_rfkill_register;
-- 
1.6.2.5


^ permalink raw reply related

* [PATCH 2.6.33/1 06/12] i2400m: minimal ethtool support
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax; +Cc: Dan Williams
In-Reply-To: <cover.1257370735.git.inaky@linux.intel.com>

From: Dan Williams <dcbw@redhat.com>

Add minimal ethtool support for carrier detection.

Signed-off-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/netdev.c |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
index 796396c..960fb54 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -74,6 +74,7 @@
  */
 #include <linux/if_arp.h>
 #include <linux/netdevice.h>
+#include <linux/ethtool.h>
 #include "i2400m.h"
 
 
@@ -559,6 +560,22 @@ static const struct net_device_ops i2400m_netdev_ops = {
 	.ndo_change_mtu = i2400m_change_mtu,
 };
 
+static void i2400m_get_drvinfo(struct net_device *net_dev,
+			       struct ethtool_drvinfo *info)
+{
+	struct i2400m *i2400m = net_dev_to_i2400m(net_dev);
+
+	strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver) - 1);
+	strncpy(info->fw_version, i2400m->fw_name, sizeof(info->fw_version) - 1);
+	if (net_dev->dev.parent)
+		strncpy(info->bus_info, dev_name(net_dev->dev.parent),
+			sizeof(info->bus_info) - 1);
+}
+
+static const struct ethtool_ops i2400m_ethtool_ops = {
+	.get_drvinfo = i2400m_get_drvinfo,
+	.get_link = ethtool_op_get_link,
+};
 
 /**
  * i2400m_netdev_setup - Setup setup @net_dev's i2400m private data
@@ -580,6 +597,7 @@ void i2400m_netdev_setup(struct net_device *net_dev)
 		   & ~IFF_MULTICAST);
 	net_dev->watchdog_timeo = I2400M_TX_TIMEOUT;
 	net_dev->netdev_ops = &i2400m_netdev_ops;
+	net_dev->ethtool_ops = &i2400m_ethtool_ops;
 	d_fnend(3, NULL, "(net_dev %p) = void\n", net_dev);
 }
 EXPORT_SYMBOL_GPL(i2400m_netdev_setup);
-- 
1.6.2.5


^ permalink raw reply related

* [PATCH 2.6.33/1 07/12] wimax/i2400m: Update comments to talk about SDIO reset and not USB.
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax; +Cc: Dirk Brandewie
In-Reply-To: <cover.1257370735.git.inaky@linux.intel.com>

From: Dirk Brandewie <dirk.j.brandewie@intel.com>

Fixing comments from original cut and paste error

Signed-off-by: Dirk Brandewie <dirk.j.brandewie@intel.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/sdio.c |   13 ++++++-------
 1 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 2981e21..c67b026 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -233,18 +233,17 @@ error_kzalloc:
  * Warm reset:
  *
  * The device will be fully reset internally, but won't be
- * disconnected from the USB bus (so no reenumeration will
+ * disconnected from the bus (so no reenumeration will
  * happen). Firmware upload will be neccessary.
  *
- * The device will send a reboot barker in the notification endpoint
- * that will trigger the driver to reinitialize the state
- * automatically from notif.c:i2400m_notification_grok() into
- * i2400m_dev_bootstrap_delayed().
+ * The device will send a reboot barker that will trigger the driver
+ * to reinitialize the state via __i2400m_dev_reset_handle.
  *
- * Cold and bus (USB) reset:
+ *
+ * Cold and bus reset:
  *
  * The device will be fully reset internally, disconnected from the
- * USB bus an a reenumeration will happen. Firmware upload will be
+ * bus an a reenumeration will happen. Firmware upload will be
  * neccessary. Thus, we don't do any locking or struct
  * reinitialization, as we are going to be fully disconnected and
  * reenumerated.
-- 
1.6.2.5


^ permalink raw reply related

* [PATCH 2.6.33/2 03/15] wimax/i2400m: be smarter about copying command buffer to bm_cmd_buf
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax
In-Reply-To: <cover.1257370736.git.inaky@linux.intel.com>

Because some underlying bus APIs (like USB) don't like data buffers in
the stack or vmalloced areas, the i2400m driver provides a scratch
buffer (i2400m->bm_cmd_buf) for said low-level drivers to copy command
data to before passing it to said API. This is only used during boot
mode.

However, at some the code was copying the buffer even when the command
was already specified in said buffer. This is ok, but it needs to be
more careful. As thus, change so that:

(a) the copy happens only if command buffer is not the scratch buffer

(b) use memmove() in case there is overlapping

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

diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index 55bd69e..0018cdb 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -343,7 +343,6 @@ ssize_t i2400m_bm_cmd(struct i2400m *i2400m,
 	BUG_ON(i2400m->boot_mode == 0);
 
 	if (cmd != NULL) {		/* send the command */
-		memcpy(i2400m->bm_cmd_buf, cmd, cmd_size);
 		result = i2400m->bus_bm_cmd_send(i2400m, cmd, cmd_size, flags);
 		if (result < 0)
 			goto error_cmd_send;
diff --git a/drivers/net/wimax/i2400m/sdio-fw.c b/drivers/net/wimax/i2400m/sdio-fw.c
index c8dc538..8e02541 100644
--- a/drivers/net/wimax/i2400m/sdio-fw.c
+++ b/drivers/net/wimax/i2400m/sdio-fw.c
@@ -118,7 +118,8 @@ ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *i2400m,
 	if (cmd_size > I2400M_BM_CMD_BUF_SIZE)
 		goto error_too_big;
 
-	memcpy(i2400m->bm_cmd_buf, _cmd, cmd_size);	/* Prep command */
+	if (_cmd != i2400m->bm_cmd_buf)
+		memmove(i2400m->bm_cmd_buf, _cmd, cmd_size);
 	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);
diff --git a/drivers/net/wimax/i2400m/usb-fw.c b/drivers/net/wimax/i2400m/usb-fw.c
index a2250e4..f162c81 100644
--- a/drivers/net/wimax/i2400m/usb-fw.c
+++ b/drivers/net/wimax/i2400m/usb-fw.c
@@ -172,7 +172,8 @@ ssize_t i2400mu_bus_bm_cmd_send(struct i2400m *i2400m,
 	result = -E2BIG;
 	if (cmd_size > I2400M_BM_CMD_BUF_SIZE)
 		goto error_too_big;
-	memcpy(i2400m->bm_cmd_buf, _cmd, cmd_size);
+	if (_cmd != i2400m->bm_cmd_buf)
+		memmove(i2400m->bm_cmd_buf, _cmd, cmd_size);
 	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);
-- 
1.6.2.5


^ permalink raw reply related

* [PATCH 2.6.33/2 01/15] wimax/i2400m: USB driver uses a configurable endpoint map
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax; +Cc: Dirk Brandewie
In-Reply-To: <cover.1257370736.git.inaky@linux.intel.com>

From: Dirk Brandewie <dirk.j.brandewie@intel.com>

Newer generations of the i2400m USB WiMAX device use a different
endpoint map; in order to make it easy to support it, we make the
endpoint-to-function mapeable instead of static.

Signed-off-by: Dirk Brandewie <dirk.j.brandewie@intel.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/i2400m-usb.h |   14 ++++++++------
 drivers/net/wimax/i2400m/usb-fw.c     |    5 +++--
 drivers/net/wimax/i2400m/usb-notif.c  |    3 ++-
 drivers/net/wimax/i2400m/usb-rx.c     |    2 +-
 drivers/net/wimax/i2400m/usb-tx.c     |    2 +-
 drivers/net/wimax/i2400m/usb.c        |   20 ++++++++++++++------
 6 files changed, 29 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wimax/i2400m/i2400m-usb.h b/drivers/net/wimax/i2400m/i2400m-usb.h
index 79c3753..f73a067 100644
--- a/drivers/net/wimax/i2400m/i2400m-usb.h
+++ b/drivers/net/wimax/i2400m/i2400m-usb.h
@@ -88,6 +88,13 @@ struct edc {
 	u16 errorcount;
 };
 
+struct i2400m_endpoint_cfg {
+	unsigned char bulk_out;
+	unsigned char notification;
+	unsigned char reset_cold;
+	unsigned char bulk_in;
+};
+
 static inline void edc_init(struct edc *edc)
 {
 	edc->timestart = jiffies;
@@ -141,12 +148,6 @@ enum {
 	I2400MU_MAX_NOTIFICATION_LEN = 256,
 	I2400MU_BLK_SIZE = 16,
 	I2400MU_PL_SIZE_MAX = 0x3EFF,
-
-	/* Endpoints */
-	I2400MU_EP_BULK_OUT = 0,
-	I2400MU_EP_NOTIFICATION,
-	I2400MU_EP_RESET_COLD,
-	I2400MU_EP_BULK_IN,
 };
 
 
@@ -216,6 +217,7 @@ struct i2400mu {
 	struct usb_device *usb_dev;
 	struct usb_interface *usb_iface;
 	struct edc urb_edc;		/* Error density counter */
+	struct i2400m_endpoint_cfg endpoint_cfg;
 
 	struct urb *notif_urb;
 	struct task_struct *tx_kthread;
diff --git a/drivers/net/wimax/i2400m/usb-fw.c b/drivers/net/wimax/i2400m/usb-fw.c
index 5ad287c..a2250e4 100644
--- a/drivers/net/wimax/i2400m/usb-fw.c
+++ b/drivers/net/wimax/i2400m/usb-fw.c
@@ -99,7 +99,7 @@ ssize_t i2400mu_tx_bulk_out(struct i2400mu *i2400mu, void *buf, size_t buf_size)
 		dev_err(dev, "BM-CMD: can't get autopm: %d\n", result);
 		do_autopm = 0;
 	}
-	epd = usb_get_epd(i2400mu->usb_iface, I2400MU_EP_BULK_OUT);
+	epd = usb_get_epd(i2400mu->usb_iface, i2400mu->endpoint_cfg.bulk_out);
 	pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
 retry:
 	result = usb_bulk_msg(i2400mu->usb_dev, pipe, buf, buf_size, &len, HZ);
@@ -226,7 +226,8 @@ int i2400mu_notif_submit(struct i2400mu *i2400mu, struct urb *urb,
 	struct usb_endpoint_descriptor *epd;
 	int pipe;
 
-	epd = usb_get_epd(i2400mu->usb_iface, I2400MU_EP_NOTIFICATION);
+	epd = usb_get_epd(i2400mu->usb_iface,
+			  i2400mu->endpoint_cfg.notification);
 	pipe = usb_rcvintpipe(i2400mu->usb_dev, epd->bEndpointAddress);
 	usb_fill_int_urb(urb, i2400mu->usb_dev, pipe,
 			 i2400m->bm_ack_buf, I2400M_BM_ACK_BUF_SIZE,
diff --git a/drivers/net/wimax/i2400m/usb-notif.c b/drivers/net/wimax/i2400m/usb-notif.c
index 6add27c..3e11e35 100644
--- a/drivers/net/wimax/i2400m/usb-notif.c
+++ b/drivers/net/wimax/i2400m/usb-notif.c
@@ -220,7 +220,8 @@ int i2400mu_notification_setup(struct i2400mu *i2400mu)
 		dev_err(dev, "notification: cannot allocate URB\n");
 		goto error_alloc_urb;
 	}
-	epd = usb_get_epd(i2400mu->usb_iface, I2400MU_EP_NOTIFICATION);
+	epd = usb_get_epd(i2400mu->usb_iface,
+			  i2400mu->endpoint_cfg.notification);
 	usb_pipe = usb_rcvintpipe(i2400mu->usb_dev, epd->bEndpointAddress);
 	usb_fill_int_urb(i2400mu->notif_urb, i2400mu->usb_dev, usb_pipe,
 			 buf, I2400MU_MAX_NOTIFICATION_LEN,
diff --git a/drivers/net/wimax/i2400m/usb-rx.c b/drivers/net/wimax/i2400m/usb-rx.c
index a314799..e494e37 100644
--- a/drivers/net/wimax/i2400m/usb-rx.c
+++ b/drivers/net/wimax/i2400m/usb-rx.c
@@ -204,7 +204,7 @@ struct sk_buff *i2400mu_rx(struct i2400mu *i2400mu, struct sk_buff *rx_skb)
 		dev_err(dev, "RX: can't get autopm: %d\n", result);
 		do_autopm = 0;
 	}
-	epd = usb_get_epd(i2400mu->usb_iface, I2400MU_EP_BULK_IN);
+	epd = usb_get_epd(i2400mu->usb_iface, i2400mu->endpoint_cfg.bulk_in);
 	usb_pipe = usb_rcvbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
 retry:
 	rx_size = skb_end_pointer(rx_skb) - rx_skb->data - rx_skb->len;
diff --git a/drivers/net/wimax/i2400m/usb-tx.c b/drivers/net/wimax/i2400m/usb-tx.c
index dfd8933..90dfff1 100644
--- a/drivers/net/wimax/i2400m/usb-tx.c
+++ b/drivers/net/wimax/i2400m/usb-tx.c
@@ -101,7 +101,7 @@ int i2400mu_tx(struct i2400mu *i2400mu, struct i2400m_msg_hdr *tx_msg,
 		dev_err(dev, "TX: can't get autopm: %d\n", result);
 		do_autopm = 0;
 	}
-	epd = usb_get_epd(i2400mu->usb_iface, I2400MU_EP_BULK_OUT);
+	epd = usb_get_epd(i2400mu->usb_iface, i2400mu->endpoint_cfg.bulk_out);
 	usb_pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
 retry:
 	result = usb_bulk_msg(i2400mu->usb_dev, usb_pipe,
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 8f7b16a..a5879e2 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -232,13 +232,15 @@ int i2400mu_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
 
 	d_fnstart(3, dev, "(i2400m %p rt %u)\n", i2400m, rt);
 	if (rt == I2400M_RT_WARM)
-		result = __i2400mu_send_barker(i2400mu, i2400m_WARM_BOOT_BARKER,
-					       sizeof(i2400m_WARM_BOOT_BARKER),
-					       I2400MU_EP_BULK_OUT);
+		result = __i2400mu_send_barker(
+			i2400mu, i2400m_WARM_BOOT_BARKER,
+			sizeof(i2400m_WARM_BOOT_BARKER),
+			i2400mu->endpoint_cfg.bulk_out);
 	else if (rt == I2400M_RT_COLD)
-		result = __i2400mu_send_barker(i2400mu, i2400m_COLD_BOOT_BARKER,
-					       sizeof(i2400m_COLD_BOOT_BARKER),
-					       I2400MU_EP_RESET_COLD);
+		result = __i2400mu_send_barker(
+			i2400mu, i2400m_COLD_BOOT_BARKER,
+			sizeof(i2400m_COLD_BOOT_BARKER),
+			i2400mu->endpoint_cfg.reset_cold);
 	else if (rt == I2400M_RT_BUS) {
 do_bus_reset:
 		result = usb_reset_device(i2400mu->usb_dev);
@@ -412,6 +414,12 @@ int i2400mu_probe(struct usb_interface *iface,
 	i2400m->bus_fw_names = i2400mu_bus_fw_names;
 	i2400m->bus_bm_mac_addr_impaired = 0;
 
+	{
+		i2400mu->endpoint_cfg.bulk_out = 0;
+		i2400mu->endpoint_cfg.notification = 1;
+		i2400mu->endpoint_cfg.reset_cold = 2;
+		i2400mu->endpoint_cfg.bulk_in = 3;
+	}
 #ifdef CONFIG_PM
 	iface->needs_remote_wakeup = 1;		/* autosuspend (15s delay) */
 	device_init_wakeup(dev, 1);
-- 
1.6.2.5


^ permalink raw reply related

* [PATCH 2.6.33/2 02/15] wimax/i2400m/sdio: clear the INTR status bit after reading size
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax; +Cc: Cindy H Kao
In-Reply-To: <cover.1257370736.git.inaky@linux.intel.com>

From: Cindy H Kao <cindy.h.kao@intel.com>

In order to avoid issues during high-load traffic, the interrupt
status register has to be cleared ONLY after the RX size is read.

Signed-off-by: Cindy H Kao <cindy.h.kao@intel.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/sdio-rx.c |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wimax/i2400m/sdio-rx.c b/drivers/net/wimax/i2400m/sdio-rx.c
index f6ca51a..1c90469 100644
--- a/drivers/net/wimax/i2400m/sdio-rx.c
+++ b/drivers/net/wimax/i2400m/sdio-rx.c
@@ -138,6 +138,11 @@ void i2400ms_rx(struct i2400ms *i2400ms)
 		ret = rx_size;
 		goto error_get_size;
 	}
+	/*
+	 * Hardware quirk: make sure to clear the INTR status register
+	 * AFTER getting the data transfer size.
+	 */
+	sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret);
 
 	ret = -ENOMEM;
 	skb = alloc_skb(rx_size, GFP_ATOMIC);
@@ -209,7 +214,6 @@ void i2400ms_irq(struct sdio_func *func)
 		dev_err(dev, "RX: BUG? got IRQ but no interrupt ready?\n");
 		goto error_no_irq;
 	}
-	sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret);
 	i2400ms_rx(i2400ms);
 error_no_irq:
 	d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms);
-- 
1.6.2.5


^ permalink raw reply related

* [PATCH 2.6.33/2 07/15] wimax: allow specifying debug levels as command line option
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax
In-Reply-To: <cover.1257370736.git.inaky@linux.intel.com>

Add "debug" module options to all the wimax modules (including
drivers) so that the debug levels can be set upon kernel boot or
module load time.

This is needed as currently there was a limitation where the debug
levels could only be set when a device was succesfully
enumerated. This made it difficult to debug issues that made a device
not probe properly.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/driver.c |   10 +++++
 drivers/net/wimax/i2400m/sdio.c   |   10 +++++
 drivers/net/wimax/i2400m/usb.c    |    9 +++++
 include/linux/wimax/debug.h       |   72 +++++++++++++++++++++++++++++++++++++
 net/wimax/stack.c                 |   11 ++++++
 5 files changed, 112 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 7ba00de..e3b2c24 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -90,6 +90,14 @@ MODULE_PARM_DESC(power_save_disabled,
 		 "False by default (so the device is told to do power "
 		 "saving).");
 
+static char i2400m_debug_params[128];
+module_param_string(debug, i2400m_debug_params, sizeof(i2400m_debug_params),
+		    0644);
+MODULE_PARM_DESC(debug,
+		 "String of space-separated NAME:VALUE pairs, where NAMEs "
+		 "are the different debug submodules and VALUE are the "
+		 "initial debug value to set.");
+
 /**
  * i2400m_queue_work - schedule work on a i2400m's queue
  *
@@ -794,6 +802,8 @@ size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL);
 static
 int __init i2400m_driver_init(void)
 {
+	d_parse_params(D_LEVEL, D_LEVEL_SIZE, i2400m_debug_params,
+		       "i2400m.debug");
 	return 0;
 }
 module_init(i2400m_driver_init);
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 7c1b843..2d2cc5a 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -71,6 +71,14 @@
 static int ioe_timeout = 2;
 module_param(ioe_timeout, int, 0);
 
+static char i2400ms_debug_params[128];
+module_param_string(debug, i2400ms_debug_params, sizeof(i2400ms_debug_params),
+		    0644);
+MODULE_PARM_DESC(debug,
+		 "String of space-separated NAME:VALUE pairs, where NAMEs "
+		 "are the different debug submodules and VALUE are the "
+		 "initial debug value to set.");
+
 /* Our firmware file name list */
 static const char *i2400ms_bus_fw_names[] = {
 #define I2400MS_FW_FILE_NAME "i2400m-fw-sdio-1.3.sbcf"
@@ -559,6 +567,8 @@ struct sdio_driver i2400m_sdio_driver = {
 static
 int __init i2400ms_driver_init(void)
 {
+	d_parse_params(D_LEVEL, D_LEVEL_SIZE, i2400ms_debug_params,
+		       "i2400m_sdio.debug");
 	return sdio_register_driver(&i2400m_sdio_driver);
 }
 module_init(i2400ms_driver_init);
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index a5879e2..0634222 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -71,6 +71,13 @@
 #define D_SUBMODULE usb
 #include "usb-debug-levels.h"
 
+static char i2400mu_debug_params[128];
+module_param_string(debug, i2400mu_debug_params, sizeof(i2400mu_debug_params),
+		    0644);
+MODULE_PARM_DESC(debug,
+		 "String of space-separated NAME:VALUE pairs, where NAMEs "
+		 "are the different debug submodules and VALUE are the "
+		 "initial debug value to set.");
 
 /* Our firmware file name */
 static const char *i2400mu_bus_fw_names[] = {
@@ -633,6 +640,8 @@ struct usb_driver i2400mu_driver = {
 static
 int __init i2400mu_driver_init(void)
 {
+	d_parse_params(D_LEVEL, D_LEVEL_SIZE, i2400mu_debug_params,
+		       "i2400m_usb.debug");
 	return usb_register(&i2400mu_driver);
 }
 module_init(i2400mu_driver_init);
diff --git a/include/linux/wimax/debug.h b/include/linux/wimax/debug.h
index c703e03..db8096e 100644
--- a/include/linux/wimax/debug.h
+++ b/include/linux/wimax/debug.h
@@ -450,4 +450,76 @@ do {							\
 })
 
 
+static inline
+void d_submodule_set(struct d_level *d_level, size_t d_level_size,
+		     const char *submodule, u8 level, const char *tag)
+{
+	struct d_level *itr, *top;
+	int index = -1;
+
+	for (itr = d_level, top = itr + d_level_size; itr < top; itr++) {
+		index++;
+		if (itr->name == NULL) {
+			printk(KERN_ERR "%s: itr->name NULL?? (%p, #%d)\n",
+			       tag, itr, index);
+			continue;
+		}
+		if (!strcmp(itr->name, submodule)) {
+			itr->level = level;
+			return;
+		}
+	}
+	printk(KERN_ERR "%s: unknown submodule %s\n", tag, submodule);
+}
+
+
+/**
+ * d_parse_params - Parse a string with debug parameters from the
+ * command line
+ *
+ * @d_level: level structure (D_LEVEL)
+ * @d_level_size: number of items in the level structure
+ *     (D_LEVEL_SIZE).
+ * @_params: string with the parameters; this is a space (not tab!)
+ *     separated list of NAME:VALUE, where value is the debug level
+ *     and NAME is the name of the submodule.
+ * @tag: string for error messages (example: MODULE.ARGNAME).
+ */
+static inline
+void d_parse_params(struct d_level *d_level, size_t d_level_size,
+		    const char *_params, const char *tag)
+{
+	char submodule[130], *params, *params_orig, *token, *colon;
+	unsigned level, tokens;
+
+	if (_params == NULL)
+		return;
+	params_orig = kstrdup(_params, GFP_KERNEL);
+	params = params_orig;
+	while (1) {
+		token = strsep(&params, " ");
+		if (token == NULL)
+			break;
+		if (*token == '\0')	/* eat joint spaces */
+			continue;
+		/* kernel's sscanf %s eats until whitespace, so we
+		 * replace : by \n so it doesn't get eaten later by
+		 * strsep */
+		colon = strchr(token, ':');
+		if (colon != NULL)
+			*colon = '\n';
+		tokens = sscanf(token, "%s\n%u", submodule, &level);
+		if (colon != NULL)
+			*colon = ':';	/* set back, for error messages */
+		if (tokens == 2)
+			d_submodule_set(d_level, d_level_size,
+					submodule, level, tag);
+		else
+			printk(KERN_ERR "%s: can't parse '%s' as a "
+			       "SUBMODULE:LEVEL (%d tokens)\n",
+			       tag, token, tokens);
+	}
+	kfree(params_orig);
+}
+
 #endif /* #ifndef __debug__h__ */
diff --git a/net/wimax/stack.c b/net/wimax/stack.c
index 79fb7d7..c886641 100644
--- a/net/wimax/stack.c
+++ b/net/wimax/stack.c
@@ -60,6 +60,14 @@
 #define D_SUBMODULE stack
 #include "debug-levels.h"
 
+static char wimax_debug_params[128];
+module_param_string(debug, wimax_debug_params, sizeof(wimax_debug_params),
+		    0644);
+MODULE_PARM_DESC(debug,
+		 "String of space-separated NAME:VALUE pairs, where NAMEs "
+		 "are the different debug submodules and VALUE are the "
+		 "initial debug value to set.");
+
 /*
  * Authoritative source for the RE_STATE_CHANGE attribute policy
  *
@@ -562,6 +570,9 @@ int __init wimax_subsys_init(void)
 	int result, cnt;
 
 	d_fnstart(4, NULL, "()\n");
+	d_parse_params(D_LEVEL, D_LEVEL_SIZE, wimax_debug_params,
+		       "wimax.debug");
+
 	snprintf(wimax_gnl_family.name, sizeof(wimax_gnl_family.name),
 		 "WiMAX");
 	result = genl_register_family(&wimax_gnl_family);
-- 
1.6.2.5


^ permalink raw reply related

* [PATCH 2.6.33/2 06/15] wimax/i2400m: add missing debug submodule definition
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax
In-Reply-To: <cover.1257370736.git.inaky@linux.intel.com>

The i2400m driver was missing the definition for the sysfs debug
level, which is declared in debug-levels.h.

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

diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 20d574c..7ba00de 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -785,6 +785,7 @@ struct d_level D_LEVEL[] = {
 	D_SUBMODULE_DEFINE(netdev),
 	D_SUBMODULE_DEFINE(rfkill),
 	D_SUBMODULE_DEFINE(rx),
+	D_SUBMODULE_DEFINE(sysfs),
 	D_SUBMODULE_DEFINE(tx),
 };
 size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL);
-- 
1.6.2.5


^ permalink raw reply related

* [PATCH 2.6.33/2 05/15] wimax/i2400m: during probe, call sdio_disable at most once
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax
In-Reply-To: <cover.1257370736.git.inaky@linux.intel.com>

In the Intel Wireless Multicomm 3200, the initialization is
orchestrated by a component called Top. This component also monitors
how many times a function is reset (via sdio_disable) to detect
possible issues and will reset the whole multifunction device if any
function triggers a maximum reset level.

During WiMAX's probe, the driver needs to wait for Top to come up
before it can enable the WiMAX function. If it cannot, it will return
-ENODEV and the Top driver will rescan the SDIO bus once done
loading.

Currently, the WiMAX SDIO probe routine was trying a few times before
returning -ENODEV, and this was triggering Top's too-many-resets
detector. This is, in any case, unnecessary because the Top driver will
force the bus rescan when the functions can be probed successfully.

Added then a maxtries argument to i2400ms_enable_func() and set it to
1 when calling from probe. We want to reuse this function instead of
flat calling out sdio_enable_func() to take advantage of hardware
quirk workarounds.

Reported-by: Cindy H Kao <cindy.h.kao@intel.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/sdio.c |   16 +++++++++++++---
 1 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 9d6046f..7c1b843 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -95,17 +95,23 @@ static const struct i2400m_poke_table i2400ms_pokes[] = {
  * when we ask it to explicitly doing). Tries until a timeout is
  * reached.
  *
+ * The @maxtries argument indicates how many times (at most) it should
+ * be tried to enable the function. 0 means forever. This acts along
+ * with the timeout (ie: it'll stop trying as soon as the maximum
+ * number of tries is reached _or_ as soon as the timeout is reached).
+ *
  * The reverse of this is...sdio_disable_function()
  *
  * Returns: 0 if the SDIO function was enabled, < 0 errno code on
  *     error (-ENODEV when it was unable to enable the function).
  */
 static
-int i2400ms_enable_function(struct sdio_func *func)
+int i2400ms_enable_function(struct sdio_func *func, unsigned maxtries)
 {
 	u64 timeout;
 	int err;
 	struct device *dev = &func->dev;
+	unsigned tries = 0;
 
 	d_fnstart(3, dev, "(func %p)\n", func);
 	/* Setup timeout (FIXME: This needs to read the CIS table to
@@ -131,6 +137,10 @@ int i2400ms_enable_function(struct sdio_func *func)
 		}
 		d_printf(2, dev, "SDIO function failed to enable: %d\n", err);
 		sdio_release_host(func);
+		if (maxtries > 0 && ++tries >= maxtries) {
+			err = -ETIME;
+			break;
+		}
 		msleep(I2400MS_INIT_SLEEP_INTERVAL);
 	}
 	/* If timed out, device is not there yet -- get -ENODEV so
@@ -305,7 +315,7 @@ do_bus_reset:
 		/* Wait for the device to settle */
 		msleep(40);
 
-		result = i2400ms_enable_function(i2400ms->func);
+		result = i2400ms_enable_function(i2400ms->func, 0);
 		if (result >= 0)
 			i2400ms_rx_setup(i2400ms);
 	} else
@@ -452,7 +462,7 @@ int i2400ms_probe(struct sdio_func *func,
 		goto error_set_blk_size;
 	}
 
-	result = i2400ms_enable_function(i2400ms->func);
+	result = i2400ms_enable_function(i2400ms->func, 1);
 	if (result < 0) {
 		dev_err(dev, "Cannot enable SDIO function: %d\n", result);
 		goto error_func_enable;
-- 
1.6.2.5


^ permalink raw reply related

* [PATCH 2.6.33/2 04/15] wimax/i2400m: don't write to memory allocated by request_firmware()
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax; +Cc: Cindy H Kao
In-Reply-To: <cover.1257370736.git.inaky@linux.intel.com>

From: Cindy H Kao <cindy.h.kao@intel.com>

In kernel 2.6.31, the firmware requested to ram could be marked
with read only attribute, and we can't write any thing directly
to the memory when setting up the last JUMP brh cmd.

Changed so that the scratch buffer is used.

Signed-off-by: Cindy H Kao <cindy.h.kao@intel.com>
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/fw.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index 0018cdb..92d4d60 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -533,6 +533,10 @@ int i2400m_dnload_finalize(struct i2400m *i2400m,
 		struct i2400m_bootrom_header jump_ack;
 		d_printf(1, dev, "unsecure 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));
+		cmd = &cmd_buf->cmd;
+		/* now cmd points to the actual bootrom_header in cmd_buf */
 		i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP);
 		cmd->data_size = 0;
 		ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
-- 
1.6.2.5


^ permalink raw reply related

* [PATCH 2.6.33/2 09/15] wimax/i2400m: decide properly if using signed vs non-signed firmware loading
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax
In-Reply-To: <cover.1257370736.git.inaky@linux.intel.com>

The i2400m based devices can boot two main types of firmware images:
signed and non-signed. Signed images have signature data included that
must match that of a certificate stored in the device.

Currently the code is making the decission on what type of firmware
load (signed vs non-signed) is going to be loaded based on a hardcoded
decission in __i2400m_ack_verify(), based on the barker the device
sent upon boot.

This is not flexible enough as future hardware will emit more barkers;
thus the bit has to be set in a place where there is better knowledge
of what is going on. This will be done in follow-up commits -- however
this patch paves the way for it.

So the querying of the mode is packed into i2400m_boot_is_signed();
the main changes are just using i2400m_boot_is_signed() to determine
the method to follow and setting i2400m->sboot in
i2400m_is_boot_barker(). The modifications in i2400m_dnload_init() and
i2400m_dnload_finalize() are just reorganizing the order of the if
blocks and thus look larger than they really are.

Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
 drivers/net/wimax/i2400m/fw.c |   35 +++++++++++++++++++++--------------
 include/linux/wimax/i2400m.h  |   10 ----------
 2 files changed, 21 insertions(+), 24 deletions(-)

diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index 92d4d60..c962a8d 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -509,6 +509,17 @@ error_send:
 
 
 /*
+ * Indicate if the device emitted a reboot barker that indicates
+ * "signed boot"
+ */
+static
+unsigned i2400m_boot_is_signed(struct i2400m *i2400m)
+{
+	return likely(i2400m->sboot);
+}
+
+
+/*
  * Do the final steps of uploading firmware
  *
  * Depending on the boot mode (signed vs non-signed), different
@@ -529,7 +540,7 @@ int i2400m_dnload_finalize(struct i2400m *i2400m,
 
 	d_fnstart(3, dev, "offset %zu\n", offset);
 	cmd = (void *) bcf + offset;
-	if (i2400m->sboot == 0) {
+	if (i2400m_boot_is_signed(i2400m) == 0) {
 		struct i2400m_bootrom_header jump_ack;
 		d_printf(1, dev, "unsecure boot, jumping to 0x%08x\n",
 			le32_to_cpu(cmd->target_addr));
@@ -846,28 +857,24 @@ int i2400m_dnload_init(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf)
 {
 	int result;
 	struct device *dev = i2400m_dev(i2400m);
-	u32 module_id = le32_to_cpu(bcf->module_id);
 
-	if (i2400m->sboot == 0
-	    && (module_id & I2400M_BCF_MOD_ID_POKES) == 0) {
-		/* non-signed boot process without pokes */
-		result = i2400m_dnload_init_nonsigned(i2400m);
+	if (i2400m_boot_is_signed(i2400m)) {
+		d_printf(1, dev, "signed boot\n");
+		result = i2400m_dnload_init_signed(i2400m, bcf);
 		if (result == -ERESTARTSYS)
 			return result;
 		if (result < 0)
-			dev_err(dev, "fw %s: non-signed download "
+			dev_err(dev, "firmware %s: signed boot download "
 				"initialization failed: %d\n",
 				i2400m->fw_name, result);
-	} else if (i2400m->sboot == 0
-		 && (module_id & I2400M_BCF_MOD_ID_POKES)) {
-		/* non-signed boot process with pokes, nothing to do */
-		result = 0;
-	} else {		 /* signed boot process */
-		result = i2400m_dnload_init_signed(i2400m, bcf);
+	} else {
+		/* non-signed boot process without pokes */
+		d_printf(1, dev, "non-signed boot\n");
+		result = i2400m_dnload_init_nonsigned(i2400m);
 		if (result == -ERESTARTSYS)
 			return result;
 		if (result < 0)
-			dev_err(dev, "fw %s: signed boot download "
+			dev_err(dev, "firmware %s: non-signed download "
 				"initialization failed: %d\n",
 				i2400m->fw_name, result);
 	}
diff --git a/include/linux/wimax/i2400m.h b/include/linux/wimax/i2400m.h
index 433693e..d6e2a35 100644
--- a/include/linux/wimax/i2400m.h
+++ b/include/linux/wimax/i2400m.h
@@ -168,16 +168,6 @@ enum i2400m_brh {
 };
 
 
-/* Constants for bcf->module_id */
-enum i2400m_bcf_mod_id {
-	/* Firmware file carries its own pokes -- pokes are a set of
-	 * magical values that have to be written in certain memory
-	 * addresses to get the device up and ready for firmware
-	 * download when it is in non-signed boot mode. */
-	I2400M_BCF_MOD_ID_POKES = 0x000000001,
-};
-
-
 /**
  * i2400m_bootrom_header - Header for a boot-mode command
  *
-- 
1.6.2.5


^ permalink raw reply related

* [PATCH 2.6.33/2 08/15] wimax/i2400m: workaround not-so-working %zd printf format
From: Inaky Perez-Gonzalez @ 2009-11-04 21:39 UTC (permalink / raw)
  To: netdev, wimax
In-Reply-To: <cover.1257370736.git.inaky@linux.intel.com>

The kernel's %zd modifier does not really work. Use %ld (has to cast
ssize_t to long).

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

diff --git a/drivers/net/wimax/i2400m/usb-fw.c b/drivers/net/wimax/i2400m/usb-fw.c
index f162c81..b59aee0 100644
--- a/drivers/net/wimax/i2400m/usb-fw.c
+++ b/drivers/net/wimax/i2400m/usb-fw.c
@@ -330,8 +330,8 @@ error_dev_gone:
 out:
 	if (do_autopm)
 		usb_autopm_put_interface(i2400mu->usb_iface);
-	d_fnend(8, dev, "(i2400m %p ack %p size %zu) = %zd\n",
-		i2400m, ack, ack_size, result);
+	d_fnend(8, dev, "(i2400m %p ack %p size %zu) = %ld\n",
+		i2400m, ack, ack_size, (long) result);
 	return result;
 
 error_exceeded:
-- 
1.6.2.5


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox