* [PATCH 2.6.33/4 09/13] wimax/i2400m: move i2400m_init() out of i2400m.h
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370737.git.inaky@linux.intel.com>
Upcoming changes will have to add things to this function that expose
more internals, which would mean more forward declarators.
Frankly, it doesn't need to be an inline, so moved to driver.c, where
the declarations will be taken from the header file.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/driver.c | 30 ++++++++++++++++++++++++++++++
drivers/net/wimax/i2400m/i2400m.h | 31 +------------------------------
2 files changed, 31 insertions(+), 30 deletions(-)
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 10673af..9b78e05 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -849,6 +849,36 @@ void i2400m_bm_buf_free(struct i2400m *i2400m)
/**
+ * i2400m_init - Initialize a 'struct i2400m' from all zeroes
+ *
+ * This is a bus-generic API call.
+ */
+void i2400m_init(struct i2400m *i2400m)
+{
+ wimax_dev_init(&i2400m->wimax_dev);
+
+ i2400m->boot_mode = 1;
+ i2400m->rx_reorder = 1;
+ init_waitqueue_head(&i2400m->state_wq);
+
+ spin_lock_init(&i2400m->tx_lock);
+ i2400m->tx_pl_min = UINT_MAX;
+ i2400m->tx_size_min = UINT_MAX;
+
+ spin_lock_init(&i2400m->rx_lock);
+ i2400m->rx_pl_min = UINT_MAX;
+ i2400m->rx_size_min = UINT_MAX;
+
+ mutex_init(&i2400m->msg_mutex);
+ init_completion(&i2400m->msg_completion);
+
+ mutex_init(&i2400m->init_mutex);
+ /* wake_tx_ws is initialized in i2400m_tx_setup() */
+}
+EXPORT_SYMBOL_GPL(i2400m_init);
+
+
+/**
* i2400m_setup - bus-generic setup function for the i2400m device
*
* @i2400m: device descriptor (bus-specific parts have been initialized)
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index f5ed7d5..4f8815d 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -576,36 +576,6 @@ struct i2400m {
/*
- * Initialize a 'struct i2400m' from all zeroes
- *
- * This is a bus-generic API call.
- */
-static inline
-void i2400m_init(struct i2400m *i2400m)
-{
- wimax_dev_init(&i2400m->wimax_dev);
-
- i2400m->boot_mode = 1;
- i2400m->rx_reorder = 1;
- init_waitqueue_head(&i2400m->state_wq);
-
- spin_lock_init(&i2400m->tx_lock);
- i2400m->tx_pl_min = UINT_MAX;
- i2400m->tx_size_min = UINT_MAX;
-
- spin_lock_init(&i2400m->rx_lock);
- i2400m->rx_pl_min = UINT_MAX;
- i2400m->rx_size_min = UINT_MAX;
-
- mutex_init(&i2400m->msg_mutex);
- init_completion(&i2400m->msg_completion);
-
- mutex_init(&i2400m->init_mutex);
- /* wake_tx_ws is initialized in i2400m_tx_setup() */
-}
-
-
-/*
* Bus-generic internal APIs
* -------------------------
*/
@@ -737,6 +707,7 @@ unsigned i2400m_brh_get_signature(const struct i2400m_bootrom_header *hdr)
/*
* Driver / device setup and internal functions
*/
+extern void i2400m_init(struct i2400m *);
extern void i2400m_netdev_setup(struct net_device *net_dev);
extern int i2400m_sysfs_setup(struct device_driver *);
extern void i2400m_sysfs_release(struct device_driver *);
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/4 10/13] wimax/i2400m: queue device's report until the driver is ready for them
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370737.git.inaky@linux.intel.com>
The i2400m might start sending reports to the driver before it is done
setting up all the infrastructure needed for handling them.
Currently we were just dropping them when the driver wasn't ready and
that is bad in certain situations, as the sync between the driver's
idea of the device's state and the device's state dissapears.
This changes that by implementing a queue for handling
reports. Incoming reports are appended to it and a workstruct is woken
to process the list of queued reports.
When the device is not yet ready to handle them, the workstruct is not
woken, but at soon as the device becomes ready again, the queue is
processed.
As a consequence of this, i2400m_queue_work() is no longer used, and
thus removed.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/driver.c | 74 +------------------
drivers/net/wimax/i2400m/i2400m.h | 14 +++-
drivers/net/wimax/i2400m/rx.c | 142 +++++++++++++++++++++++++++++--------
3 files changed, 128 insertions(+), 102 deletions(-)
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 9b78e05..42102eb 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -128,76 +128,6 @@ struct i2400m_work *__i2400m_work_setup(
}
-/**
- * i2400m_queue_work - schedule work on a i2400m's queue
- *
- * @i2400m: device descriptor
- *
- * @fn: function to run to execute work. It gets passed a 'struct
- * work_struct' that is wrapped in a 'struct i2400m_work'. Once
- * done, you have to (1) i2400m_put(i2400m_work->i2400m) and then
- * (2) kfree(i2400m_work).
- *
- * @gfp_flags: GFP flags for memory allocation.
- *
- * @pl: pointer to a payload buffer that you want to pass to the _work
- * function. Use this to pack (for example) a struct with extra
- * arguments.
- *
- * @pl_size: size of the payload buffer.
- *
- * We do this quite often, so this just saves typing; allocate a
- * wrapper for a i2400m, get a ref to it, pack arguments and launch
- * the work.
- *
- * A usual workflow is:
- *
- * struct my_work_args {
- * void *something;
- * int whatever;
- * };
- * ...
- *
- * struct my_work_args my_args = {
- * .something = FOO,
- * .whaetever = BLAH
- * };
- * i2400m_queue_work(i2400m, 1, my_work_function, GFP_KERNEL,
- * &args, sizeof(args))
- *
- * And now the work function can unpack the arguments and call the
- * real function (or do the job itself):
- *
- * static
- * void my_work_fn((struct work_struct *ws)
- * {
- * struct i2400m_work *iw =
- * container_of(ws, struct i2400m_work, ws);
- * struct my_work_args *my_args = (void *) iw->pl;
- *
- * my_work(iw->i2400m, my_args->something, my_args->whatevert);
- * }
- */
-int i2400m_queue_work(struct i2400m *i2400m,
- void (*fn)(struct work_struct *), gfp_t gfp_flags,
- const void *pl, size_t pl_size)
-{
- int result;
- struct i2400m_work *iw;
-
- BUG_ON(i2400m->work_queue == NULL);
- result = -ENOMEM;
- iw = __i2400m_work_setup(i2400m, fn, gfp_flags, pl, pl_size);
- if (iw != NULL) {
- result = queue_work(i2400m->work_queue, &iw->ws);
- if (WARN_ON(result == 0))
- result = -ENXIO;
- }
- return result;
-}
-EXPORT_SYMBOL_GPL(i2400m_queue_work);
-
-
/*
* Schedule i2400m's specific work on the system's queue.
*
@@ -459,6 +389,8 @@ retry:
goto error_bus_dev_start;
i2400m->ready = 1;
wmb(); /* see i2400m->ready's documentation */
+ /* process pending reports from the device */
+ queue_work(i2400m->work_queue, &i2400m->rx_report_ws);
result = i2400m_firmware_check(i2400m); /* fw versions ok? */
if (result < 0)
goto error_fw_check;
@@ -868,6 +800,8 @@ void i2400m_init(struct i2400m *i2400m)
spin_lock_init(&i2400m->rx_lock);
i2400m->rx_pl_min = UINT_MAX;
i2400m->rx_size_min = UINT_MAX;
+ INIT_LIST_HEAD(&i2400m->rx_reports);
+ INIT_WORK(&i2400m->rx_report_ws, i2400m_report_hook_work);
mutex_init(&i2400m->msg_mutex);
init_completion(&i2400m->msg_completion);
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 4f8815d..55bca43 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -421,6 +421,13 @@ struct i2400m_barker_db;
* delivered. Then the driver can release them to the host. See
* drivers/net/i2400m/rx.c for details.
*
+ * @rx_reports: reports received from the device that couldn't be
+ * processed because the driver wasn't still ready; when ready,
+ * they are pulled from here and chewed.
+ *
+ * @rx_reports_ws: Work struct used to kick a scan of the RX reports
+ * list and to process each.
+ *
* @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().
@@ -548,6 +555,8 @@ struct i2400m {
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 list_head rx_reports; /* under rx_lock! */
+ struct work_struct rx_report_ws;
struct mutex msg_mutex; /* serialize command execution */
struct completion msg_completion;
@@ -830,9 +839,7 @@ struct i2400m_work {
size_t pl_size;
u8 pl[0];
};
-extern int i2400m_queue_work(struct i2400m *,
- void (*)(struct work_struct *), gfp_t,
- const void *, size_t);
+
extern int i2400m_schedule_work(struct i2400m *,
void (*)(struct work_struct *), gfp_t,
const void *, size_t);
@@ -847,6 +854,7 @@ extern void i2400m_msg_ack_hook(struct i2400m *,
const struct i2400m_l3l4_hdr *, size_t);
extern void i2400m_report_hook(struct i2400m *,
const struct i2400m_l3l4_hdr *, size_t);
+extern void i2400m_report_hook_work(struct work_struct *);
extern int i2400m_cmd_enter_powersave(struct i2400m *);
extern int i2400m_cmd_get_state(struct i2400m *);
extern int i2400m_cmd_exit_idle(struct i2400m *);
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
index 82c200a..64a44ca 100644
--- a/drivers/net/wimax/i2400m/rx.c
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -158,29 +158,104 @@ struct i2400m_report_hook_args {
struct sk_buff *skb_rx;
const struct i2400m_l3l4_hdr *l3l4_hdr;
size_t size;
+ struct list_head list_node;
};
/*
* Execute i2400m_report_hook in a workqueue
*
- * Unpacks arguments from the deferred call, executes it and then
- * drops the references.
+ * Goes over the list of queued reports in i2400m->rx_reports and
+ * processes them.
*
- * Obvious NOTE: References are needed because we are a separate
- * thread; otherwise the buffer changes under us because it is
- * released by the original caller.
+ * NOTE: refcounts on i2400m are not needed because we flush the
+ * workqueue this runs on (i2400m->work_queue) before destroying
+ * i2400m.
*/
-static
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);
- kfree_skb(args->skb_rx);
- i2400m_put(iw->i2400m);
- kfree(iw);
+ struct i2400m *i2400m = container_of(ws, struct i2400m, rx_report_ws);
+ struct device *dev = i2400m_dev(i2400m);
+ struct i2400m_report_hook_args *args, *args_next;
+ LIST_HEAD(list);
+ unsigned long flags;
+
+ while (1) {
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
+ list_splice_init(&i2400m->rx_reports, &list);
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+ if (list_empty(&list))
+ break;
+ else
+ d_printf(1, dev, "processing queued reports\n");
+ list_for_each_entry_safe(args, args_next, &list, list_node) {
+ d_printf(2, dev, "processing queued report %p\n", args);
+ i2400m_report_hook(i2400m, args->l3l4_hdr, args->size);
+ kfree_skb(args->skb_rx);
+ list_del(&args->list_node);
+ kfree(args);
+ }
+ }
+}
+
+
+/*
+ * Flush the list of queued reports
+ */
+static
+void i2400m_report_hook_flush(struct i2400m *i2400m)
+{
+ struct device *dev = i2400m_dev(i2400m);
+ struct i2400m_report_hook_args *args, *args_next;
+ LIST_HEAD(list);
+ unsigned long flags;
+
+ d_printf(1, dev, "flushing queued reports\n");
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
+ list_splice_init(&i2400m->rx_reports, &list);
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+ list_for_each_entry_safe(args, args_next, &list, list_node) {
+ d_printf(2, dev, "flushing queued report %p\n", args);
+ kfree_skb(args->skb_rx);
+ list_del(&args->list_node);
+ kfree(args);
+ }
+}
+
+
+/*
+ * Queue a report for later processing
+ *
+ * @i2400m: device descriptor
+ * @skb_rx: skb that contains the payload (for reference counting)
+ * @l3l4_hdr: pointer to the control
+ * @size: size of the message
+ */
+static
+void i2400m_report_hook_queue(struct i2400m *i2400m, struct sk_buff *skb_rx,
+ const void *l3l4_hdr, size_t size)
+{
+ struct device *dev = i2400m_dev(i2400m);
+ unsigned long flags;
+ struct i2400m_report_hook_args *args;
+
+ args = kzalloc(sizeof(*args), GFP_NOIO);
+ if (args) {
+ args->skb_rx = skb_get(skb_rx);
+ args->l3l4_hdr = l3l4_hdr;
+ args->size = size;
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
+ list_add_tail(&args->list_node, &i2400m->rx_reports);
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+ d_printf(2, dev, "queued report %p\n", args);
+ rmb(); /* see i2400m->ready's documentation */
+ if (likely(i2400m->ready)) /* only send if up */
+ queue_work(i2400m->work_queue, &i2400m->rx_report_ws);
+ } else {
+ if (printk_ratelimit())
+ dev_err(dev, "%s:%u: Can't allocate %zu B\n",
+ __func__, __LINE__, sizeof(*args));
+ }
}
@@ -294,22 +369,29 @@ void i2400m_rx_ctl(struct i2400m *i2400m, struct sk_buff *skb_rx,
msg_type, size);
d_dump(2, dev, l3l4_hdr, size);
if (msg_type & I2400M_MT_REPORT_MASK) {
- /* These hooks have to be ran serialized; as well, the
- * handling might force the execution of commands, and
- * that might cause reentrancy issues with
- * bus-specific subdrivers and workqueues. So we run
- * it in a separate workqueue. */
- struct i2400m_report_hook_args args = {
- .skb_rx = skb_rx,
- .l3l4_hdr = l3l4_hdr,
- .size = size
- };
- rmb(); /* see i2400m->ready's documentation */
- if (likely(i2400m->ready)) { /* only send if up */
- skb_get(skb_rx);
- i2400m_queue_work(i2400m, i2400m_report_hook_work,
- GFP_KERNEL, &args, sizeof(args));
- }
+ /*
+ * Process each report
+ *
+ * - has to be ran serialized as well
+ *
+ * - the handling might force the execution of
+ * commands. That might cause reentrancy issues with
+ * bus-specific subdrivers and workqueues, so the we
+ * run it in a separate workqueue.
+ *
+ * - when the driver is not yet ready to handle them,
+ * they are queued and at some point the queue is
+ * restarted [NOTE: we can't queue SKBs directly, as
+ * this might be a piece of a SKB, not the whole
+ * thing, and this is cheaper than cloning the
+ * SKB].
+ *
+ * Note we don't do refcounting for the device
+ * structure; this is because before destroying
+ * 'i2400m', we make sure to flush the
+ * i2400m->work_queue, so there are no issues.
+ */
+ i2400m_report_hook_queue(i2400m, skb_rx, l3l4_hdr, size);
if (unlikely(i2400m->trace_msg_from_user))
wimax_msg(&i2400m->wimax_dev, "echo",
l3l4_hdr, size, GFP_KERNEL);
@@ -1281,4 +1363,6 @@ void i2400m_rx_release(struct i2400m *i2400m)
kfree(i2400m->rx_roq[0].log);
kfree(i2400m->rx_roq);
}
+ /* at this point, nothing can be received... */
+ i2400m_report_hook_flush(i2400m);
}
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/4 08/13] wimax/i2400m: fix deadlock: don't do BUS reset under i2400m->init_mutex
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370737.git.inaky@linux.intel.com>
Since the addition of the pre/post reset handlers, it became clear
that we cannot do a I2400M-RT-BUS type reset while holding the
init_mutex, as in the case of USB, it will deadlock when trying to
call i2400m_pre_reset().
Thus, the following changes:
- clarify the fact that calling bus_reset() w/ I2400M_RT_BUS while
holding init_mutex is a no-no.
- i2400m_dev_reset_handle() will do a BUS reset to recover a gone
device after unlocking init_mutex.
- in the USB reset implementation, when cold and warm reset fails,
fallback to QUEUING a usb reset, not executing a USB reset, so it
happens from another context and does not deadlock.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/driver.c | 10 +++++++---
drivers/net/wimax/i2400m/i2400m.h | 3 +++
drivers/net/wimax/i2400m/usb.c | 14 ++++++++++----
3 files changed, 20 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 810eda7..10673af 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -765,9 +765,7 @@ void __i2400m_dev_reset_handle(struct work_struct *ws)
wmb(); /* see i2400m->updown's documentation */
dev_err(dev, "%s: cannot start the device: %d\n",
reason, result);
- result = i2400m->bus_reset(i2400m, I2400M_RT_BUS);
- if (result >= 0)
- result = -ENODEV;
+ result = -EUCLEAN;
}
out_unlock:
if (i2400m->reset_ctx) {
@@ -775,6 +773,12 @@ out_unlock:
complete(&ctx->completion);
}
mutex_unlock(&i2400m->init_mutex);
+ if (result == -EUCLEAN) {
+ /* ops, need to clean up [w/ init_mutex not held] */
+ result = i2400m->bus_reset(i2400m, I2400M_RT_BUS);
+ if (result >= 0)
+ result = -ENODEV;
+ }
out:
i2400m_put(i2400m);
kfree(iw);
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 8fc8a0c..f5ed7d5 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -281,6 +281,9 @@ struct i2400m_barker_db;
* process, so it cannot rely on common infrastructure being laid
* out.
*
+ * IMPORTANT: don't call reset on RT_BUS with i2400m->init_mutex
+ * held, as the .pre/.post reset handlers will deadlock.
+ *
* @bus_bm_retries: [fill] How many times shall a firmware upload /
* device initialization be retried? Different models of the same
* device might need different values, hence it is set by the
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 8b246cc..418db12 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -254,7 +254,6 @@ int i2400mu_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
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);
switch (result) {
case 0:
@@ -262,7 +261,7 @@ do_bus_reset:
case -ENODEV:
case -ENOENT:
case -ESHUTDOWN:
- result = rt == I2400M_RT_WARM ? -ENODEV : 0;
+ result = 0;
break; /* We assume the device is disconnected */
default:
dev_err(dev, "USB reset failed (%d), giving up!\n",
@@ -275,10 +274,17 @@ do_bus_reset:
if (result < 0
&& result != -EINVAL /* device is gone */
&& rt != I2400M_RT_BUS) {
+ /*
+ * Things failed -- resort to lower level reset, that
+ * we queue in another context; the reason for this is
+ * that the pre and post reset functionality requires
+ * the i2400m->init_mutex; RT_WARM and RT_COLD can
+ * come from areas where i2400m->init_mutex is taken.
+ */
dev_err(dev, "%s reset failed (%d); trying USB reset\n",
rt == I2400M_RT_WARM ? "warm" : "cold", result);
- rt = I2400M_RT_BUS;
- goto do_bus_reset;
+ usb_queue_reset_device(i2400mu->usb_iface);
+ result = -ENODEV;
}
d_fnend(3, dev, "(i2400m %p rt %u) = %d\n", i2400m, rt, result);
return result;
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/4 12/13] wimax/i2400m: Let device's status reports change the device state
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370737.git.inaky@linux.intel.com>
Currently __i2400m_dev_start was forcing, after uploading firmware and
doing a few checks to WIMAX_ST_UNINITIALIZED.
This can be overriding state changes that the device might have caused
by sending reports; thus it makes more sense to remove it and let the
device update the status on its own by sending reports.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/driver.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 42102eb..cc900b9 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -398,7 +398,6 @@ retry:
result = i2400m_check_mac_addr(i2400m);
if (result < 0)
goto error_check_mac_addr;
- wimax_state_change(wimax_dev, WIMAX_ST_UNINITIALIZED);
result = i2400m_dev_initialize(i2400m);
if (result < 0)
goto error_dev_initialize;
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/4 11/13] wimax/i2400m: fix oops in TX when tearing down the device
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370737.git.inaky@linux.intel.com>
All the entry points into the TX module should check if the device has
been torn down. Otherwise, when the device resets or shuts down, there
are windows when a call to i2400m_tx*() will oops the system.
For that, make i2400m_tx_release() set i2400m->tx_buf to NULL under
the tx_lock. Then, any entry point [i2400m_tx(), _tx_msg_sent(),
_tx_msg_get()] will check for i2400m->tx_buf to be NULL and exit
gracefully.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/sdio-tx.c | 5 ++++-
drivers/net/wimax/i2400m/tx.c | 18 +++++++++++++++++-
2 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wimax/i2400m/sdio-tx.c b/drivers/net/wimax/i2400m/sdio-tx.c
index 5105a5e..de66d06 100644
--- a/drivers/net/wimax/i2400m/sdio-tx.c
+++ b/drivers/net/wimax/i2400m/sdio-tx.c
@@ -149,5 +149,8 @@ int i2400ms_tx_setup(struct i2400ms *i2400ms)
void i2400ms_tx_release(struct i2400ms *i2400ms)
{
- destroy_workqueue(i2400ms->tx_workqueue);
+ if (i2400ms->tx_workqueue) {
+ destroy_workqueue(i2400ms->tx_workqueue);
+ i2400ms->tx_workqueue = NULL;
+ }
}
diff --git a/drivers/net/wimax/i2400m/tx.c b/drivers/net/wimax/i2400m/tx.c
index 8c20802..54480e8 100644
--- a/drivers/net/wimax/i2400m/tx.c
+++ b/drivers/net/wimax/i2400m/tx.c
@@ -642,6 +642,9 @@ int i2400m_tx(struct i2400m *i2400m, const void *buf, size_t buf_len,
* current one is out of payload slots or we have a singleton,
* close it and start a new one */
spin_lock_irqsave(&i2400m->tx_lock, flags);
+ result = -ESHUTDOWN;
+ if (i2400m->tx_buf == NULL)
+ goto error_tx_new;
try_new:
if (unlikely(i2400m->tx_msg == NULL))
i2400m_tx_new(i2400m);
@@ -697,7 +700,10 @@ try_new:
}
error_tx_new:
spin_unlock_irqrestore(&i2400m->tx_lock, flags);
- i2400m->bus_tx_kick(i2400m); /* always kick, might free up space */
+ /* kick in most cases, except when the TX subsys is down, as
+ * it might free space */
+ if (likely(result != -ESHUTDOWN))
+ i2400m->bus_tx_kick(i2400m);
d_fnend(3, dev, "(i2400m %p skb %p [%zu bytes] pt %u) = %d\n",
i2400m, buf, buf_len, pl_type, result);
return result;
@@ -740,6 +746,9 @@ struct i2400m_msg_hdr *i2400m_tx_msg_get(struct i2400m *i2400m,
d_fnstart(3, dev, "(i2400m %p bus_size %p)\n", i2400m, bus_size);
spin_lock_irqsave(&i2400m->tx_lock, flags);
+ tx_msg_moved = NULL;
+ if (i2400m->tx_buf == NULL)
+ goto out_unlock;
skip:
tx_msg_moved = NULL;
if (i2400m->tx_in == i2400m->tx_out) { /* Empty FIFO? */
@@ -829,6 +838,8 @@ void i2400m_tx_msg_sent(struct i2400m *i2400m)
d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
spin_lock_irqsave(&i2400m->tx_lock, flags);
+ if (i2400m->tx_buf == NULL)
+ goto out_unlock;
i2400m->tx_out += i2400m->tx_msg_size;
d_printf(2, dev, "TX: sent %zu b\n", (size_t) i2400m->tx_msg_size);
i2400m->tx_msg_size = 0;
@@ -837,6 +848,7 @@ void i2400m_tx_msg_sent(struct i2400m *i2400m)
n = i2400m->tx_out / I2400M_TX_BUF_SIZE;
i2400m->tx_out %= I2400M_TX_BUF_SIZE;
i2400m->tx_in -= n * I2400M_TX_BUF_SIZE;
+out_unlock:
spin_unlock_irqrestore(&i2400m->tx_lock, flags);
d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
}
@@ -876,5 +888,9 @@ int i2400m_tx_setup(struct i2400m *i2400m)
*/
void i2400m_tx_release(struct i2400m *i2400m)
{
+ unsigned long flags;
+ spin_lock_irqsave(&i2400m->tx_lock, flags);
kfree(i2400m->tx_buf);
+ i2400m->tx_buf = NULL;
+ spin_unlock_irqrestore(&i2400m->tx_lock, flags);
}
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/4 13/13] wimax/i2400m: fix oops caused by race condition when exiting USB kthreads
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370737.git.inaky@linux.intel.com>
Current i2400m USB code had to threads (one for processing RX, one for
TX). When calling i2400m_{tx,rx}_release(), it would crash if the
thread had exited already due to an error.
So changed the code to have the thread fill in/out
i2400mu->{tx,rx}_kthread under a spinlock; then the _release()
function will call kthread_stop() only if {rx,tx}_kthread is still
set.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/usb-rx.c | 35 +++++++++++++++++++++++++++++------
drivers/net/wimax/i2400m/usb-tx.c | 35 ++++++++++++++++++++++++++++++-----
2 files changed, 59 insertions(+), 11 deletions(-)
diff --git a/drivers/net/wimax/i2400m/usb-rx.c b/drivers/net/wimax/i2400m/usb-rx.c
index e494e37..245587f 100644
--- a/drivers/net/wimax/i2400m/usb-rx.c
+++ b/drivers/net/wimax/i2400m/usb-rx.c
@@ -316,10 +316,15 @@ int i2400mu_rxd(void *_i2400mu)
size_t pending;
int rx_size;
struct sk_buff *rx_skb;
+ unsigned long flags;
d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu);
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
+ BUG_ON(i2400mu->rx_kthread != NULL);
+ i2400mu->rx_kthread = current;
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
while (1) {
- d_printf(2, dev, "TX: waiting for messages\n");
+ d_printf(2, dev, "RX: waiting for messages\n");
pending = 0;
wait_event_interruptible(
i2400mu->rx_wq,
@@ -367,6 +372,9 @@ int i2400mu_rxd(void *_i2400mu)
}
result = 0;
out:
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
+ i2400mu->rx_kthread = NULL;
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
d_fnend(4, dev, "(i2400mu %p) = %d\n", i2400mu, result);
return result;
@@ -403,18 +411,33 @@ int i2400mu_rx_setup(struct i2400mu *i2400mu)
struct i2400m *i2400m = &i2400mu->i2400m;
struct device *dev = &i2400mu->usb_iface->dev;
struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
+ struct task_struct *kthread;
- i2400mu->rx_kthread = kthread_run(i2400mu_rxd, i2400mu, "%s-rx",
- wimax_dev->name);
- if (IS_ERR(i2400mu->rx_kthread)) {
- result = PTR_ERR(i2400mu->rx_kthread);
+ kthread = kthread_run(i2400mu_rxd, i2400mu, "%s-rx",
+ wimax_dev->name);
+ /* the kthread function sets i2400mu->rx_thread */
+ if (IS_ERR(kthread)) {
+ result = PTR_ERR(kthread);
dev_err(dev, "RX: cannot start thread: %d\n", result);
}
return result;
}
+
void i2400mu_rx_release(struct i2400mu *i2400mu)
{
- kthread_stop(i2400mu->rx_kthread);
+ unsigned long flags;
+ struct i2400m *i2400m = &i2400mu->i2400m;
+ struct device *dev = i2400m_dev(i2400m);
+ struct task_struct *kthread;
+
+ spin_lock_irqsave(&i2400m->rx_lock, flags);
+ kthread = i2400mu->rx_kthread;
+ i2400mu->rx_kthread = NULL;
+ spin_unlock_irqrestore(&i2400m->rx_lock, flags);
+ if (kthread)
+ kthread_stop(kthread);
+ else
+ d_printf(1, dev, "RX: kthread had already exited\n");
}
diff --git a/drivers/net/wimax/i2400m/usb-tx.c b/drivers/net/wimax/i2400m/usb-tx.c
index 90dfff1..a3c46e9 100644
--- a/drivers/net/wimax/i2400m/usb-tx.c
+++ b/drivers/net/wimax/i2400m/usb-tx.c
@@ -161,9 +161,15 @@ int i2400mu_txd(void *_i2400mu)
struct device *dev = &i2400mu->usb_iface->dev;
struct i2400m_msg_hdr *tx_msg;
size_t tx_msg_size;
+ unsigned long flags;
d_fnstart(4, dev, "(i2400mu %p)\n", i2400mu);
+ spin_lock_irqsave(&i2400m->tx_lock, flags);
+ BUG_ON(i2400mu->tx_kthread != NULL);
+ i2400mu->tx_kthread = current;
+ spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+
while (1) {
d_printf(2, dev, "TX: waiting for messages\n");
tx_msg = NULL;
@@ -183,6 +189,11 @@ int i2400mu_txd(void *_i2400mu)
if (result < 0)
break;
}
+
+ spin_lock_irqsave(&i2400m->tx_lock, flags);
+ i2400mu->tx_kthread = NULL;
+ spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+
d_fnend(4, dev, "(i2400mu %p) = %d\n", i2400mu, result);
return result;
}
@@ -213,11 +224,13 @@ int i2400mu_tx_setup(struct i2400mu *i2400mu)
struct i2400m *i2400m = &i2400mu->i2400m;
struct device *dev = &i2400mu->usb_iface->dev;
struct wimax_dev *wimax_dev = &i2400m->wimax_dev;
+ struct task_struct *kthread;
- i2400mu->tx_kthread = kthread_run(i2400mu_txd, i2400mu, "%s-tx",
- wimax_dev->name);
- if (IS_ERR(i2400mu->tx_kthread)) {
- result = PTR_ERR(i2400mu->tx_kthread);
+ kthread = kthread_run(i2400mu_txd, i2400mu, "%s-tx",
+ wimax_dev->name);
+ /* the kthread function sets i2400mu->tx_thread */
+ if (IS_ERR(kthread)) {
+ result = PTR_ERR(kthread);
dev_err(dev, "TX: cannot start thread: %d\n", result);
}
return result;
@@ -225,5 +238,17 @@ int i2400mu_tx_setup(struct i2400mu *i2400mu)
void i2400mu_tx_release(struct i2400mu *i2400mu)
{
- kthread_stop(i2400mu->tx_kthread);
+ unsigned long flags;
+ struct i2400m *i2400m = &i2400mu->i2400m;
+ struct device *dev = i2400m_dev(i2400m);
+ struct task_struct *kthread;
+
+ spin_lock_irqsave(&i2400m->tx_lock, flags);
+ kthread = i2400mu->tx_kthread;
+ i2400mu->tx_kthread = NULL;
+ spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+ if (kthread)
+ kthread_stop(kthread);
+ else
+ d_printf(1, dev, "TX: kthread had already exited\n");
}
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/5 00/12] WiMAX pull request
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
The following changes since commit 4a78fd9a736db4c871bc8b583d66b61c38abd299:
Inaky Perez-Gonzalez (1):
wimax/i2400m: fix oops caused by race condition when exiting USB kthreads
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/inaky/wimax.git linux-2.6.33.y
Patches follow for reviewing convenience.
Inaky Perez-Gonzalez (12):
wimax/i2400m: make i2400m->bus_dev_{stop,start}() optional
wimax/i2400m: SDIO: fix oops on reset when TXing on uninitialized data
wimax/i2400m: implement passive mode as a module option
wimax/i2400m: introduce i2400m_reset(), stopping TX and carrier
wimax/i2400m: fix device getting stuck in IDLE mode
wimax/i2400m: Fix USB timeout specifications (to ms from HZ)
wimax/i2400m: correctly identify all iwmc3200-based SKUs
wimax/i2400m: don't retry SDIO enable in probe() paths
wimax/i2400m: handle USB stalls
wimax/i2400m: fix bad assignment of return value in i2400mu_tx_bulk_out
wimax/i2400m: fix SDIO debugfs dentry name
wimax/i2400m: fix inverted value in i2400ms_bus_setup()
drivers/net/wimax/i2400m/control.c | 14 +++++-
drivers/net/wimax/i2400m/debugfs.c | 2 +-
drivers/net/wimax/i2400m/driver.c | 36 +++++++++++---
drivers/net/wimax/i2400m/fw.c | 4 +-
drivers/net/wimax/i2400m/i2400m-sdio.h | 11 ++++
drivers/net/wimax/i2400m/i2400m.h | 15 +++---
drivers/net/wimax/i2400m/netdev.c | 25 +++++++--
drivers/net/wimax/i2400m/rx.c | 4 +-
drivers/net/wimax/i2400m/sdio.c | 81 ++++++++++++++------------------
drivers/net/wimax/i2400m/usb-fw.c | 25 +++++++++-
drivers/net/wimax/i2400m/usb-rx.c | 23 +++++++++-
drivers/net/wimax/i2400m/usb-tx.c | 24 +++++++++-
drivers/net/wimax/i2400m/usb.c | 61 +++++++++++++++++++++---
13 files changed, 240 insertions(+), 85 deletions(-)
^ permalink raw reply
* [PATCH 2.6.33/5 03/12] wimax/i2400m: implement passive mode as a module option
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370738.git.inaky@linux.intel.com>
Some versions of the user space Intel WiMAX daemon need to have full
control over the device initialization sequence. By setting the module
option i2400.passive_mode to 1, the driver defers all device
configuration and initialization to user space.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/control.c | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index 8fe70e7..b69fd88 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -82,6 +82,13 @@
#define D_SUBMODULE control
#include "debug-levels.h"
+int i2400m_passive_mode; /* 0 (passive mode disabled) by default */
+module_param_named(passive_mode, i2400m_passive_mode, int, 0644);
+MODULE_PARM_DESC(passive_mode,
+ "If true, the driver will not do any device setup "
+ "and leave it up to user space, who must be properly "
+ "setup.");
+
/*
* Return if a TLV is of a give type and size
@@ -1335,6 +1342,8 @@ int i2400m_dev_initialize(struct i2400m *i2400m)
unsigned argc = 0;
d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
+ if (i2400m_passive_mode)
+ goto out_passive;
/* Disable idle mode? (enabled by default) */
if (i2400m_idle_mode_disabled) {
if (i2400m_le_v1_3(i2400m)) {
@@ -1377,6 +1386,7 @@ int i2400m_dev_initialize(struct i2400m *i2400m)
result = i2400m_set_init_config(i2400m, args, argc);
if (result < 0)
goto error;
+out_passive:
/*
* Update state: Here it just calls a get state; parsing the
* result (System State TLV and RF Status TLV [done in the rx
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/5 02/12] wimax/i2400m: SDIO: fix oops on reset when TXing on uninitialized data
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370738.git.inaky@linux.intel.com>
Currently the SDIO part of the TX resources were initialized/released
with bus_dev_{start,stop}.
The generic code's TX subsystem is destroyed afterwards, so there is a
window from the bus-TX destruction to the generic-TX destruction where
the generic-TX code might call into bus-TX to do transactions.
The SDIO code cannot really cope with this (whereas in USB, how it is
laid out, it correctly ignores it). In any case, it made no sense for
the SDIO TX code to be in i2400m->bus_dev_start/stop(), so moved to
i2400m->bus_setup/release(), which also takes care of the oops.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/sdio.c | 43 ++++++++------------------------------
1 files changed, 9 insertions(+), 34 deletions(-)
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 14e66f0..ec17892 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -46,15 +46,6 @@
* i2400ms_bus_reset() Called by i2400m->bus_reset
* __i2400ms_reset()
* __i2400ms_send_barker()
- *
- * i2400ms_bus_dev_start() Called by i2400m_dev_start() [who is
- * i2400ms_tx_setup() called by i2400m_setup()]
- * i2400ms_rx_setup()
- *
- * i2400ms_bus_dev_stop() Called by i2400m_dev_stop() [who is
- * i2400ms_rx_release() is called by i2400m_release()]
- * i2400ms_tx_release()
- *
*/
#include <linux/debugfs.h>
@@ -191,12 +182,17 @@ int i2400ms_bus_setup(struct i2400m *i2400m)
goto error_func_enable;
}
+ result = i2400ms_tx_setup(i2400ms);
+ if (result < 0)
+ goto error_tx_setup;
result = i2400ms_rx_setup(i2400ms);
if (result < 0)
goto error_rx_setup;
return 0;
error_rx_setup:
+ i2400ms_tx_release(i2400ms);
+error_tx_setup:
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
@@ -218,6 +214,7 @@ void i2400ms_bus_release(struct i2400m *i2400m)
struct sdio_func *func = i2400ms->func;
i2400ms_rx_release(i2400ms);
+ i2400ms_tx_release(i2400ms);
sdio_claim_host(func);
sdio_disable_func(func);
sdio_release_host(func);
@@ -235,36 +232,14 @@ void i2400ms_bus_release(struct i2400m *i2400m)
static
int i2400ms_bus_dev_start(struct i2400m *i2400m)
{
- int result;
struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
struct sdio_func *func = i2400ms->func;
struct device *dev = &func->dev;
d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
msleep(200);
- result = i2400ms_tx_setup(i2400ms);
- if (result < 0)
- goto error_tx_setup;
- d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
- return result;
-
-error_tx_setup:
- i2400ms_tx_release(i2400ms);
- d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
- return result;
-}
-
-
-static
-void i2400ms_bus_dev_stop(struct i2400m *i2400m)
-{
- struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
- struct sdio_func *func = i2400ms->func;
- struct device *dev = &func->dev;
-
- d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
- i2400ms_tx_release(i2400ms);
- d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
+ d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, 0);
+ return 0;
}
@@ -506,7 +481,7 @@ int i2400ms_probe(struct sdio_func *func,
i2400m->bus_pl_size_max = I2400MS_PL_SIZE_MAX;
i2400m->bus_setup = i2400ms_bus_setup;
i2400m->bus_dev_start = i2400ms_bus_dev_start;
- i2400m->bus_dev_stop = i2400ms_bus_dev_stop;
+ i2400m->bus_dev_stop = NULL;
i2400m->bus_release = i2400ms_bus_release;
i2400m->bus_tx_kick = i2400ms_bus_tx_kick;
i2400m->bus_reset = i2400ms_bus_reset;
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/5 01/12] wimax/i2400m: make i2400m->bus_dev_{stop,start}() optional
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370738.git.inaky@linux.intel.com>
In coming commits, the i2400m SDIO driver will not use
i2400m->bus_dev_stop().
Thus changed to check before calling, as an empty stub has more
overhead than a call to check if the function pointer is non-NULL.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/driver.c | 14 +++++++++-----
drivers/net/wimax/i2400m/i2400m.h | 14 +++++++-------
2 files changed, 16 insertions(+), 12 deletions(-)
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index cc900b9..cc58a86 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -384,9 +384,11 @@ retry:
dev_err(dev, "cannot create workqueue\n");
goto error_create_workqueue;
}
- result = i2400m->bus_dev_start(i2400m);
- if (result < 0)
- goto error_bus_dev_start;
+ if (i2400m->bus_dev_start) {
+ result = i2400m->bus_dev_start(i2400m);
+ if (result < 0)
+ goto error_bus_dev_start;
+ }
i2400m->ready = 1;
wmb(); /* see i2400m->ready's documentation */
/* process pending reports from the device */
@@ -413,7 +415,8 @@ error_check_mac_addr:
wmb(); /* see i2400m->ready's documentation */
flush_workqueue(i2400m->work_queue);
error_fw_check:
- i2400m->bus_dev_stop(i2400m);
+ if (i2400m->bus_dev_stop)
+ i2400m->bus_dev_stop(i2400m);
error_bus_dev_start:
destroy_workqueue(i2400m->work_queue);
error_create_workqueue:
@@ -480,7 +483,8 @@ void __i2400m_dev_stop(struct i2400m *i2400m)
wmb(); /* see i2400m->ready's documentation */
flush_workqueue(i2400m->work_queue);
- i2400m->bus_dev_stop(i2400m);
+ if (i2400m->bus_dev_stop)
+ i2400m->bus_dev_stop(i2400m);
destroy_workqueue(i2400m->work_queue);
i2400m_rx_release(i2400m);
i2400m_tx_release(i2400m);
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 55bca43..5eee985 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -245,19 +245,19 @@ struct i2400m_barker_db;
* all the host resources created to handle communication with
* the device.
*
- * @bus_dev_start: [fill] Function called by the bus-generic code
- * [i2400m_dev_start()] to setup the bus-specific communications
- * to the the device. See LIFE CYCLE above.
+ * @bus_dev_start: [optional fill] Function called by the bus-generic
+ * code [i2400m_dev_start()] to do things needed to start the
+ * device. See LIFE CYCLE above.
*
* NOTE: Doesn't need to upload the firmware, as that is taken
* care of by the bus-generic code.
*
- * @bus_dev_stop: [fill] Function called by the bus-generic code
- * [i2400m_dev_stop()] to shutdown the bus-specific communications
- * to the the device. See LIFE CYCLE above.
+ * @bus_dev_stop: [optional fill] Function called by the bus-generic
+ * code [i2400m_dev_stop()] to do things needed for stopping the
+ * device. See LIFE CYCLE above.
*
* This function does not need to reset the device, just tear down
- * all the host resources created to handle communication with
+ * all the host resources created to handle communication with
* the device.
*
* @bus_tx_kick: [fill] Function called by the bus-generic code to let
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/5 04/12] wimax/i2400m: introduce i2400m_reset(), stopping TX and carrier
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370738.git.inaky@linux.intel.com>
Currently the i2400m driver was resetting by just calling
i2400m->bus_reset(). However, this was missing stopping the TX queue
and downing the carrier. This was causing, for the corner case of the
driver reseting a device that refuses to go out of idle mode, that a
few packets would be queued and more than one reset would go through,
making the recovery a wee bit messy.
To avoid introducing the same cleanup in all the bus-specific driver,
introduced a i2400m_reset() function that takes care of house cleaning
and then calling the bus-level reset implementation.
The bulk of the changes in all files are just to rename the call from
i2400m->bus_reset() to i2400m_reset().
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/control.c | 4 ++--
drivers/net/wimax/i2400m/debugfs.c | 2 +-
drivers/net/wimax/i2400m/driver.c | 22 ++++++++++++++++++++--
drivers/net/wimax/i2400m/fw.c | 4 ++--
drivers/net/wimax/i2400m/i2400m.h | 1 +
drivers/net/wimax/i2400m/netdev.c | 8 +++++---
drivers/net/wimax/i2400m/rx.c | 4 ++--
drivers/net/wimax/i2400m/sdio.c | 9 +--------
drivers/net/wimax/i2400m/usb.c | 2 +-
9 files changed, 35 insertions(+), 21 deletions(-)
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index b69fd88..9449455 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -54,7 +54,7 @@
* i2400m_set_init_config()
* i2400m_cmd_get_state()
* i2400m_dev_shutdown() Called by i2400m_dev_stop()
- * i2400m->bus_reset()
+ * i2400m_reset()
*
* i2400m_{cmd,get,set}_*()
* i2400m_msg_to_dev()
@@ -343,7 +343,7 @@ void i2400m_report_tlv_system_state(struct i2400m *i2400m,
/* Huh? just in case, shut it down */
dev_err(dev, "HW BUG? unknown state %u: shutting down\n",
i2400m_state);
- i2400m->bus_reset(i2400m, I2400M_RT_WARM);
+ i2400m_reset(i2400m, I2400M_RT_WARM);
break;
};
d_fnend(3, dev, "(i2400m %p ss %p [%u]) = void\n",
diff --git a/drivers/net/wimax/i2400m/debugfs.c b/drivers/net/wimax/i2400m/debugfs.c
index 9b81af3..b1aec3e 100644
--- a/drivers/net/wimax/i2400m/debugfs.c
+++ b/drivers/net/wimax/i2400m/debugfs.c
@@ -214,7 +214,7 @@ int debugfs_i2400m_reset_set(void *data, u64 val)
case I2400M_RT_WARM:
case I2400M_RT_COLD:
case I2400M_RT_BUS:
- result = i2400m->bus_reset(i2400m, rt);
+ result = i2400m_reset(i2400m, rt);
if (result >= 0)
result = 0;
default:
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index cc58a86..96a615f 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -255,7 +255,7 @@ int i2400m_op_reset(struct wimax_dev *wimax_dev)
mutex_lock(&i2400m->init_mutex);
i2400m->reset_ctx = &ctx;
mutex_unlock(&i2400m->init_mutex);
- result = i2400m->bus_reset(i2400m, I2400M_RT_WARM);
+ result = i2400m_reset(i2400m, I2400M_RT_WARM);
if (result < 0)
goto out;
result = wait_for_completion_timeout(&ctx.completion, 4*HZ);
@@ -710,7 +710,7 @@ out_unlock:
mutex_unlock(&i2400m->init_mutex);
if (result == -EUCLEAN) {
/* ops, need to clean up [w/ init_mutex not held] */
- result = i2400m->bus_reset(i2400m, I2400M_RT_BUS);
+ result = i2400m_reset(i2400m, I2400M_RT_BUS);
if (result >= 0)
result = -ENODEV;
}
@@ -815,6 +815,24 @@ void i2400m_init(struct i2400m *i2400m)
EXPORT_SYMBOL_GPL(i2400m_init);
+int i2400m_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
+{
+ struct net_device *net_dev = i2400m->wimax_dev.net_dev;
+
+ /*
+ * Make sure we stop TXs and down the carrier before
+ * resetting; this is needed to avoid things like
+ * i2400m_wake_tx() scheduling stuff in parallel.
+ */
+ if (net_dev->reg_state == NETREG_REGISTERED) {
+ netif_tx_disable(net_dev);
+ netif_carrier_off(net_dev);
+ }
+ return i2400m->bus_reset(i2400m, rt);
+}
+EXPORT_SYMBOL_GPL(i2400m_reset);
+
+
/**
* i2400m_setup - bus-generic setup function for the i2400m device
*
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index fda54bf..64cdfeb 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -130,7 +130,7 @@
* i2400m_fw_dnload
* i2400m_bootrom_init
* i2400m_bm_cmd
- * i2400m->bus_reset
+ * i2400m_reset
* i2400m_dnload_init
* i2400m_dnload_init_signed
* i2400m_dnload_init_nonsigned
@@ -902,7 +902,7 @@ do_reboot:
d_printf(4, dev, "device reboot: reboot command [%d # left]\n",
count);
if ((flags & I2400M_BRI_NO_REBOOT) == 0)
- i2400m->bus_reset(i2400m, I2400M_RT_WARM);
+ i2400m_reset(i2400m, I2400M_RT_WARM);
result = i2400m_bm_cmd(i2400m, NULL, 0, &ack, sizeof(ack),
I2400M_BM_CMD_RAW);
flags &= ~I2400M_BRI_NO_REBOOT;
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 5eee985..04df9bb 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -717,6 +717,7 @@ unsigned i2400m_brh_get_signature(const struct i2400m_bootrom_header *hdr)
* Driver / device setup and internal functions
*/
extern void i2400m_init(struct i2400m *);
+extern int i2400m_reset(struct i2400m *, enum i2400m_reset_type);
extern void i2400m_netdev_setup(struct net_device *net_dev);
extern int i2400m_sysfs_setup(struct device_driver *);
extern void i2400m_sysfs_release(struct device_driver *);
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
index e7d1a51..f67af42 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -171,8 +171,9 @@ void i2400m_wake_tx_work(struct work_struct *ws)
result = 0;
if (result < 0) {
dev_err(dev, "WAKE&TX: device didn't get out of idle: "
- "%d\n", result);
- goto error;
+ "%d - resetting\n", result);
+ i2400m_reset(i2400m, I2400M_RT_BUS);
+ goto error;
}
result = wait_event_timeout(i2400m->state_wq,
i2400m->state != I2400M_SS_IDLE, 5 * HZ);
@@ -180,7 +181,8 @@ void i2400m_wake_tx_work(struct work_struct *ws)
result = -ETIMEDOUT;
if (result < 0) {
dev_err(dev, "WAKE&TX: error waiting for device to exit IDLE: "
- "%d\n", result);
+ "%d - resetting\n", result);
+ i2400m_reset(i2400m, I2400M_RT_BUS);
goto error;
}
msleep(20); /* device still needs some time or it drops it */
diff --git a/drivers/net/wimax/i2400m/rx.c b/drivers/net/wimax/i2400m/rx.c
index 64a44ca..e3d2a9d 100644
--- a/drivers/net/wimax/i2400m/rx.c
+++ b/drivers/net/wimax/i2400m/rx.c
@@ -828,7 +828,7 @@ void i2400m_roq_queue(struct i2400m *i2400m, struct i2400m_roq *roq,
dev_err(dev, "SW BUG? queue nsn %d (lbn %u ws %u)\n",
nsn, lbn, roq->ws);
i2400m_roq_log_dump(i2400m, roq);
- i2400m->bus_reset(i2400m, I2400M_RT_WARM);
+ i2400m_reset(i2400m, I2400M_RT_WARM);
} else {
__i2400m_roq_queue(i2400m, roq, skb, lbn, nsn);
i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_PACKET,
@@ -894,7 +894,7 @@ void i2400m_roq_queue_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq,
dev_err(dev, "SW BUG? queue_update_ws nsn %u (sn %u ws %u)\n",
nsn, sn, roq->ws);
i2400m_roq_log_dump(i2400m, roq);
- i2400m->bus_reset(i2400m, I2400M_RT_WARM);
+ i2400m_reset(i2400m, I2400M_RT_WARM);
} else {
/* if the queue is empty, don't bother as we'd queue
* it and inmediately unqueue it -- just deliver it */
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index ec17892..20ab22e 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -43,7 +43,7 @@
* i2400m_release()
* free_netdev(net_dev)
*
- * i2400ms_bus_reset() Called by i2400m->bus_reset
+ * i2400ms_bus_reset() Called by i2400m_reset
* __i2400ms_reset()
* __i2400ms_send_barker()
*/
@@ -342,13 +342,6 @@ int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt)
sizeof(i2400m_COLD_BOOT_BARKER));
else if (rt == I2400M_RT_BUS) {
do_bus_reset:
- /* call netif_tx_disable() before sending IOE disable,
- * so that all the tx from network layer are stopped
- * while IOE is being reset. Make sure it is called
- * only after register_netdev() was issued.
- */
- if (i2400m->wimax_dev.net_dev->reg_state == NETREG_REGISTERED)
- netif_tx_disable(i2400m->wimax_dev.net_dev);
i2400ms_bus_release(i2400m);
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 418db12..5e07940 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -58,7 +58,7 @@
* i2400mu_rx_release()
* i2400mu_tx_release()
*
- * i2400mu_bus_reset() Called by i2400m->bus_reset
+ * i2400mu_bus_reset() Called by i2400m_reset
* __i2400mu_reset()
* __i2400mu_send_barker()
* usb_reset_device()
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/5 05/12] wimax/i2400m: fix device getting stuck in IDLE mode
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370738.git.inaky@linux.intel.com>
The i2400m, when conected, will negotiate with the WiMAX basestation
to put the link in IDLE mode when it is not being used. Upon RX/TX
traffic, the link has to be restablished and that might require some
crypto handshakes and maybe a DHCP renew.
This process might take up to 20 (!) seconds and in some cases we were
seeing network watchdog warnings that weren't needed.
So the network watchdog timeout is updated to be slightly above that
20s threshold. As well, the driver itself will double check if the
device is stuck in IDLE mode -- if that happens, the device will be
reset (in this case the queue is also woken up to remove bogus--once
the device is reset--warnings).
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/netdev.c | 17 ++++++++++++++---
1 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
index f67af42..599aa4e 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -89,7 +89,10 @@ enum {
* The MTU is 1400 or less
*/
I2400M_MAX_MTU = 1400,
- I2400M_TX_TIMEOUT = HZ,
+ /* 20 secs? yep, this is the maximum timeout that the device
+ * might take to get out of IDLE / negotiate it with the base
+ * station. We add 1sec for good measure. */
+ I2400M_TX_TIMEOUT = 21 * HZ,
I2400M_TX_QLEN = 5,
};
@@ -151,6 +154,7 @@ void i2400m_wake_tx_work(struct work_struct *ws)
{
int result;
struct i2400m *i2400m = container_of(ws, struct i2400m, wake_tx_ws);
+ struct net_device *net_dev = i2400m->wimax_dev.net_dev;
struct device *dev = i2400m_dev(i2400m);
struct sk_buff *skb = i2400m->wake_tx_skb;
unsigned long flags;
@@ -166,6 +170,11 @@ void i2400m_wake_tx_work(struct work_struct *ws)
dev_err(dev, "WAKE&TX: skb dissapeared!\n");
goto out_put;
}
+ /* If we have, somehow, lost the connection after this was
+ * queued, don't do anything; this might be the device got
+ * reset or just disconnected. */
+ if (unlikely(!netif_carrier_ok(net_dev)))
+ goto out_kfree;
result = i2400m_cmd_exit_idle(i2400m);
if (result == -EILSEQ)
result = 0;
@@ -176,7 +185,8 @@ void i2400m_wake_tx_work(struct work_struct *ws)
goto error;
}
result = wait_event_timeout(i2400m->state_wq,
- i2400m->state != I2400M_SS_IDLE, 5 * HZ);
+ i2400m->state != I2400M_SS_IDLE,
+ net_dev->watchdog_timeo - HZ/2);
if (result == 0)
result = -ETIMEDOUT;
if (result < 0) {
@@ -187,8 +197,9 @@ void i2400m_wake_tx_work(struct work_struct *ws)
}
msleep(20); /* device still needs some time or it drops it */
result = i2400m_tx(i2400m, skb->data, skb->len, I2400M_PT_DATA);
- netif_wake_queue(i2400m->wimax_dev.net_dev);
error:
+ netif_wake_queue(net_dev);
+out_kfree:
kfree_skb(skb); /* refcount transferred by _hard_start_xmit() */
out_put:
i2400m_put(i2400m);
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/5 07/12] wimax/i2400m: correctly identify all iwmc3200-based SKUs
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370738.git.inaky@linux.intel.com>
Different paths of the i2400m SDIO driver need to take care of a few
SKU-specific quirks. For the ones that are common to to all the
iwmc3200 based devices, introduce i2400ms->iwmc3200 [set in
i2400ms_probe()], so it doesn't have to check against the list of
iwmc3200 SKU IDs on each quirk site.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/i2400m-sdio.h | 3 +++
drivers/net/wimax/i2400m/sdio.c | 16 +++++++++++++---
2 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h
index 18218a2..fba482c 100644
--- a/drivers/net/wimax/i2400m/i2400m-sdio.h
+++ b/drivers/net/wimax/i2400m/i2400m-sdio.h
@@ -114,6 +114,9 @@ struct i2400ms {
wait_queue_head_t bm_wfa_wq;
int bm_wait_result;
size_t bm_ack_size;
+
+ /* Device is any of the iwmc3200 SKUs */
+ unsigned iwmc3200:1;
};
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 20ab22e..079f900 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -105,8 +105,9 @@ static const struct i2400m_poke_table i2400ms_pokes[] = {
* error (-ENODEV when it was unable to enable the function).
*/
static
-int i2400ms_enable_function(struct sdio_func *func, unsigned maxtries)
+int i2400ms_enable_function(struct i2400ms *i2400ms, unsigned maxtries)
{
+ struct sdio_func *func = i2400ms->func;
u64 timeout;
int err;
struct device *dev = &func->dev;
@@ -126,7 +127,7 @@ int i2400ms_enable_function(struct sdio_func *func, unsigned maxtries)
* platforms (system hang). We explicitly overwrite
* func->enable_timeout here to work around the issue.
*/
- if (func->device == SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX)
+ if (i2400ms->iwmc3200)
func->enable_timeout = IWMC3200_IOR_TIMEOUT;
err = sdio_enable_func(func);
if (0 == err) {
@@ -176,7 +177,7 @@ int i2400ms_bus_setup(struct i2400m *i2400m)
goto error_set_blk_size;
}
- result = i2400ms_enable_function(func, 1);
+ result = i2400ms_enable_function(i2400ms, 1);
if (result < 0) {
dev_err(dev, "Cannot enable SDIO function: %d\n", result);
goto error_func_enable;
@@ -487,6 +488,15 @@ int i2400ms_probe(struct sdio_func *func,
i2400m->bus_bm_mac_addr_impaired = 1;
i2400m->bus_bm_pokes_table = &i2400ms_pokes[0];
+ switch (func->device) {
+ case SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX:
+ case SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX_2G5:
+ i2400ms->iwmc3200 = 1;
+ break;
+ default:
+ i2400ms->iwmc3200 = 0;
+ }
+
result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT);
if (result < 0) {
dev_err(dev, "cannot setup device: %d\n", result);
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/5 10/12] wimax/i2400m: fix bad assignment of return value in i2400mu_tx_bulk_out
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370738.git.inaky@linux.intel.com>
The function was always setting the return value to the amount of
bytes transferred, overwriting the error code in error paths.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/usb-fw.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wimax/i2400m/usb-fw.c b/drivers/net/wimax/i2400m/usb-fw.c
index d8f6ce2..ce6b993 100644
--- a/drivers/net/wimax/i2400m/usb-fw.c
+++ b/drivers/net/wimax/i2400m/usb-fw.c
@@ -157,7 +157,6 @@ retry:
result);
goto retry;
}
- result = len;
if (do_autopm)
usb_autopm_put_interface(i2400mu->usb_iface);
return result;
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/5 06/12] wimax/i2400m: Fix USB timeout specifications (to ms from HZ)
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370738.git.inaky@linux.intel.com>
The USB code was incorrectly specifiying timeouts to be in jiffies vs
msecs. On top of that, lower it to 200ms, as 1s is really too long
(doesn't allow the watchdog to trip a reset if the device timesout too
often).
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/usb-fw.c | 2 +-
drivers/net/wimax/i2400m/usb-rx.c | 2 +-
drivers/net/wimax/i2400m/usb-tx.c | 2 +-
drivers/net/wimax/i2400m/usb.c | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wimax/i2400m/usb-fw.c b/drivers/net/wimax/i2400m/usb-fw.c
index b59aee0..8ec8b6d 100644
--- a/drivers/net/wimax/i2400m/usb-fw.c
+++ b/drivers/net/wimax/i2400m/usb-fw.c
@@ -102,7 +102,7 @@ ssize_t i2400mu_tx_bulk_out(struct i2400mu *i2400mu, void *buf, size_t buf_size)
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);
+ result = usb_bulk_msg(i2400mu->usb_dev, pipe, buf, buf_size, &len, 200);
switch (result) {
case 0:
if (len != buf_size) {
diff --git a/drivers/net/wimax/i2400m/usb-rx.c b/drivers/net/wimax/i2400m/usb-rx.c
index 245587f..22d127b 100644
--- a/drivers/net/wimax/i2400m/usb-rx.c
+++ b/drivers/net/wimax/i2400m/usb-rx.c
@@ -214,7 +214,7 @@ retry:
}
result = usb_bulk_msg(
i2400mu->usb_dev, usb_pipe, rx_skb->data + rx_skb->len,
- rx_size, &read_size, HZ);
+ rx_size, &read_size, 200);
usb_mark_last_busy(i2400mu->usb_dev);
switch (result) {
case 0:
diff --git a/drivers/net/wimax/i2400m/usb-tx.c b/drivers/net/wimax/i2400m/usb-tx.c
index a3c46e9..6cdf003 100644
--- a/drivers/net/wimax/i2400m/usb-tx.c
+++ b/drivers/net/wimax/i2400m/usb-tx.c
@@ -105,7 +105,7 @@ int i2400mu_tx(struct i2400mu *i2400mu, struct i2400m_msg_hdr *tx_msg,
usb_pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
retry:
result = usb_bulk_msg(i2400mu->usb_dev, usb_pipe,
- tx_msg, tx_msg_size, &sent_size, HZ);
+ tx_msg, tx_msg_size, &sent_size, 200);
usb_mark_last_busy(i2400mu->usb_dev);
switch (result) {
case 0:
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 5e07940..34df090 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -173,7 +173,7 @@ int __i2400mu_send_barker(struct i2400mu *i2400mu,
pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
memcpy(buffer, barker, barker_size);
ret = usb_bulk_msg(i2400mu->usb_dev, pipe, buffer, barker_size,
- &actual_len, HZ);
+ &actual_len, 200);
if (ret < 0) {
if (ret != -EINVAL)
dev_err(dev, "E: barker error: %d\n", ret);
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/5 08/12] wimax/i2400m: don't retry SDIO enable in probe() paths
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370738.git.inaky@linux.intel.com>
The iwmc3200 has a quirk where retrying SDIO enable during the probe()
path causes bad interactions with the TOP function controller that
causes a reset storm. The workaround is simply not to retry an SDIO
enable in said path (and still do in the reset / reinitialization
paths).
The driver does so by checking i2400ms->debugfs_dentry to see if it
has been initialized; if not, it is in the probe() path. Document said
fact in i2400ms->debugfs_entry.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/i2400m-sdio.h | 8 ++++++++
drivers/net/wimax/i2400m/sdio.c | 13 ++++++++++++-
2 files changed, 20 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h
index fba482c..b9c4bed 100644
--- a/drivers/net/wimax/i2400m/i2400m-sdio.h
+++ b/drivers/net/wimax/i2400m/i2400m-sdio.h
@@ -100,6 +100,14 @@ enum {
* @tx_workqueue: workqeueue used for data TX; we don't use the
* system's workqueue as that might cause deadlocks with code in
* the bus-generic driver.
+ *
+ * @debugfs_dentry: dentry for the SDIO specific debugfs files
+ *
+ * Note this value is set to NULL upon destruction; this is
+ * because some routinges use it to determine if we are inside the
+ * probe() path or some other path. When debugfs is disabled,
+ * creation sets the dentry to '(void*) -ENODEV', which is valid
+ * for the test.
*/
struct i2400ms {
struct i2400m i2400m; /* FIRST! See doc */
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index 079f900..e8ad85c 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -159,6 +159,10 @@ function_enabled:
/*
* Setup minimal device communication infrastructure needed to at
* least be able to update the firmware.
+ *
+ * Note the ugly trick: if we are in the probe path
+ * (i2400ms->debugfs_dentry == NULL), we only retry function
+ * enablement one, to avoid racing with the iwmc3200 top controller.
*/
static
int i2400ms_bus_setup(struct i2400m *i2400m)
@@ -168,6 +172,7 @@ int i2400ms_bus_setup(struct i2400m *i2400m)
container_of(i2400m, struct i2400ms, i2400m);
struct device *dev = i2400m_dev(i2400m);
struct sdio_func *func = i2400ms->func;
+ int retries;
sdio_claim_host(func);
result = sdio_set_block_size(func, I2400MS_BLK_SIZE);
@@ -177,7 +182,11 @@ int i2400ms_bus_setup(struct i2400m *i2400m)
goto error_set_blk_size;
}
- result = i2400ms_enable_function(i2400ms, 1);
+ if (i2400ms->iwmc3200 && i2400ms->debugfs_dentry == NULL)
+ retries = 0;
+ else
+ retries = 1;
+ result = i2400ms_enable_function(i2400ms, retries);
if (result < 0) {
dev_err(dev, "Cannot enable SDIO function: %d\n", result);
goto error_func_enable;
@@ -415,6 +424,7 @@ int i2400ms_debugfs_add(struct i2400ms *i2400ms)
error:
debugfs_remove_recursive(i2400ms->debugfs_dentry);
+ i2400ms->debugfs_dentry = NULL;
return result;
}
@@ -531,6 +541,7 @@ void i2400ms_remove(struct sdio_func *func)
d_fnstart(3, dev, "SDIO func %p\n", func);
debugfs_remove_recursive(i2400ms->debugfs_dentry);
+ i2400ms->debugfs_dentry = NULL;
i2400m_release(i2400m);
sdio_set_drvdata(func, NULL);
free_netdev(net_dev);
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/5 09/12] wimax/i2400m: handle USB stalls
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370738.git.inaky@linux.intel.com>
When the device stalls, clear it and retry; if it keeps failing too
often, reset the device.
This specially happens when running on virtual machines; the real
hardware doesn't seem to trip on stalls too much, except for a few
reports in the mailing list (still to be confirmed this is the cause,
although it seems likely.
NOTE: it is not clear if the URB has to be resubmitted fully or start
only at the offset of the first transaction sent. Can't find
documentation to clarify one end or the other.
Tests that just resubmit the whole URB seemed to work in my
environment.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/usb-fw.c | 22 ++++++++++++++
drivers/net/wimax/i2400m/usb-rx.c | 21 +++++++++++++
drivers/net/wimax/i2400m/usb-tx.c | 22 ++++++++++++++
drivers/net/wimax/i2400m/usb.c | 57 +++++++++++++++++++++++++++++++++----
4 files changed, 116 insertions(+), 6 deletions(-)
diff --git a/drivers/net/wimax/i2400m/usb-fw.c b/drivers/net/wimax/i2400m/usb-fw.c
index 8ec8b6d..d8f6ce2 100644
--- a/drivers/net/wimax/i2400m/usb-fw.c
+++ b/drivers/net/wimax/i2400m/usb-fw.c
@@ -113,6 +113,28 @@ retry:
}
result = len;
break;
+ case -EPIPE:
+ /*
+ * Stall -- maybe the device is choking with our
+ * requests. Clear it and give it some time. If they
+ * happen to often, it might be another symptom, so we
+ * reset.
+ *
+ * No error handling for usb_clear_halt(0; if it
+ * works, the retry works; if it fails, this switch
+ * does the error handling for us.
+ */
+ if (edc_inc(&i2400mu->urb_edc,
+ 10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "BM-CMD: too many stalls in "
+ "URB; resetting device\n");
+ usb_queue_reset_device(i2400mu->usb_iface);
+ /* fallthrough */
+ } else {
+ usb_clear_halt(i2400mu->usb_dev, pipe);
+ msleep(10); /* give the device some time */
+ goto retry;
+ }
case -EINVAL: /* while removing driver */
case -ENODEV: /* dev disconnect ... */
case -ENOENT: /* just ignore it */
diff --git a/drivers/net/wimax/i2400m/usb-rx.c b/drivers/net/wimax/i2400m/usb-rx.c
index 22d127b..ba1b023 100644
--- a/drivers/net/wimax/i2400m/usb-rx.c
+++ b/drivers/net/wimax/i2400m/usb-rx.c
@@ -222,6 +222,26 @@ retry:
goto retry; /* ZLP, just resubmit */
skb_put(rx_skb, read_size);
break;
+ case -EPIPE:
+ /*
+ * Stall -- maybe the device is choking with our
+ * requests. Clear it and give it some time. If they
+ * happen to often, it might be another symptom, so we
+ * reset.
+ *
+ * No error handling for usb_clear_halt(0; if it
+ * works, the retry works; if it fails, this switch
+ * does the error handling for us.
+ */
+ if (edc_inc(&i2400mu->urb_edc,
+ 10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "BM-CMD: too many stalls in "
+ "URB; resetting device\n");
+ goto do_reset;
+ }
+ usb_clear_halt(i2400mu->usb_dev, usb_pipe);
+ msleep(10); /* give the device some time */
+ goto retry;
case -EINVAL: /* while removing driver */
case -ENODEV: /* dev disconnect ... */
case -ENOENT: /* just ignore it */
@@ -283,6 +303,7 @@ out:
error_reset:
dev_err(dev, "RX: maximum errors in URB exceeded; "
"resetting device\n");
+do_reset:
usb_queue_reset_device(i2400mu->usb_iface);
rx_skb = ERR_PTR(result);
goto out;
diff --git a/drivers/net/wimax/i2400m/usb-tx.c b/drivers/net/wimax/i2400m/usb-tx.c
index 6cdf003..c65b997 100644
--- a/drivers/net/wimax/i2400m/usb-tx.c
+++ b/drivers/net/wimax/i2400m/usb-tx.c
@@ -115,6 +115,28 @@ retry:
result = -EIO;
}
break;
+ case -EPIPE:
+ /*
+ * Stall -- maybe the device is choking with our
+ * requests. Clear it and give it some time. If they
+ * happen to often, it might be another symptom, so we
+ * reset.
+ *
+ * No error handling for usb_clear_halt(0; if it
+ * works, the retry works; if it fails, this switch
+ * does the error handling for us.
+ */
+ if (edc_inc(&i2400mu->urb_edc,
+ 10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "BM-CMD: too many stalls in "
+ "URB; resetting device\n");
+ usb_queue_reset_device(i2400mu->usb_iface);
+ /* fallthrough */
+ } else {
+ usb_clear_halt(i2400mu->usb_dev, usb_pipe);
+ msleep(10); /* give the device some time */
+ goto retry;
+ }
case -EINVAL: /* while removing driver */
case -ENODEV: /* dev disconnect ... */
case -ENOENT: /* just ignore it */
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c
index 34df090..47e84ef 100644
--- a/drivers/net/wimax/i2400m/usb.c
+++ b/drivers/net/wimax/i2400m/usb.c
@@ -172,14 +172,59 @@ int __i2400mu_send_barker(struct i2400mu *i2400mu,
epd = usb_get_epd(i2400mu->usb_iface, endpoint);
pipe = usb_sndbulkpipe(i2400mu->usb_dev, epd->bEndpointAddress);
memcpy(buffer, barker, barker_size);
+retry:
ret = usb_bulk_msg(i2400mu->usb_dev, pipe, buffer, barker_size,
&actual_len, 200);
- if (ret < 0) {
- if (ret != -EINVAL)
- dev_err(dev, "E: barker error: %d\n", ret);
- } else if (actual_len != barker_size) {
- dev_err(dev, "E: only %d bytes transmitted\n", actual_len);
- ret = -EIO;
+ switch (ret) {
+ case 0:
+ if (actual_len != barker_size) { /* Too short? drop it */
+ dev_err(dev, "E: %s: short write (%d B vs %zu "
+ "expected)\n",
+ __func__, actual_len, barker_size);
+ ret = -EIO;
+ }
+ break;
+ case -EPIPE:
+ /*
+ * Stall -- maybe the device is choking with our
+ * requests. Clear it and give it some time. If they
+ * happen to often, it might be another symptom, so we
+ * reset.
+ *
+ * No error handling for usb_clear_halt(0; if it
+ * works, the retry works; if it fails, this switch
+ * does the error handling for us.
+ */
+ if (edc_inc(&i2400mu->urb_edc,
+ 10 * EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "E: %s: too many stalls in "
+ "URB; resetting device\n", __func__);
+ usb_queue_reset_device(i2400mu->usb_iface);
+ /* fallthrough */
+ } else {
+ usb_clear_halt(i2400mu->usb_dev, pipe);
+ msleep(10); /* give the device some time */
+ goto retry;
+ }
+ case -EINVAL: /* while removing driver */
+ case -ENODEV: /* dev disconnect ... */
+ case -ENOENT: /* just ignore it */
+ case -ESHUTDOWN: /* and exit */
+ case -ECONNRESET:
+ ret = -ESHUTDOWN;
+ break;
+ default: /* Some error? */
+ if (edc_inc(&i2400mu->urb_edc,
+ EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) {
+ dev_err(dev, "E: %s: maximum errors in URB "
+ "exceeded; resetting device\n",
+ __func__);
+ usb_queue_reset_device(i2400mu->usb_iface);
+ } else {
+ dev_warn(dev, "W: %s: cannot send URB: %d\n",
+ __func__, ret);
+ goto retry;
+ }
}
kfree(buffer);
error_kzalloc:
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/5 11/12] wimax/i2400m: fix SDIO debugfs dentry name
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370738.git.inaky@linux.intel.com>
The SDIO specific debugfs dentry was being misnamed "i2400m-usb"
instead of "i2400m-sdio".
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/sdio.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index e8ad85c..b06d526 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -407,7 +407,7 @@ int i2400ms_debugfs_add(struct i2400ms *i2400ms)
int result;
struct dentry *dentry = i2400ms->i2400m.wimax_dev.debugfs_dentry;
- dentry = debugfs_create_dir("i2400m-usb", dentry);
+ dentry = debugfs_create_dir("i2400m-sdio", dentry);
result = PTR_ERR(dentry);
if (IS_ERR(dentry)) {
if (result == -ENODEV)
--
1.6.2.5
^ permalink raw reply related
* [PATCH 2.6.33/5 12/12] wimax/i2400m: fix inverted value in i2400ms_bus_setup()
From: Inaky Perez-Gonzalez @ 2009-11-04 21:40 UTC (permalink / raw)
To: netdev, wimax
In-Reply-To: <cover.1257370738.git.inaky@linux.intel.com>
Fix inverted setting of 'retries'; when we are in the probe() path, we
should retry to enable the function only once; otherwise until it
times out.
Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
---
drivers/net/wimax/i2400m/sdio.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c
index b06d526..76a50ac 100644
--- a/drivers/net/wimax/i2400m/sdio.c
+++ b/drivers/net/wimax/i2400m/sdio.c
@@ -183,9 +183,9 @@ int i2400ms_bus_setup(struct i2400m *i2400m)
}
if (i2400ms->iwmc3200 && i2400ms->debugfs_dentry == NULL)
- retries = 0;
- else
retries = 1;
+ else
+ retries = 0;
result = i2400ms_enable_function(i2400ms, retries);
if (result < 0) {
dev_err(dev, "Cannot enable SDIO function: %d\n", result);
--
1.6.2.5
^ permalink raw reply related
* Re: [PATCH 3/3] net: check kern before calling security subsystem
From: James Morris @ 2009-11-04 21:42 UTC (permalink / raw)
To: Eric Paris; +Cc: netdev, nhorman, acme, dwalsh, davem, linux-security-module
In-Reply-To: <20091104163224.27133.88570.stgit@paris.rdu.redhat.com>
On Wed, 4 Nov 2009, Eric Paris wrote:
> - if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW))
> + if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
> return -EPERM;
> - if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW))
> + if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
> goto out_rcu_unlock;
> - if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW))
> + if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
> goto out_rcu_unlock;
Perhaps make this a static inline.
--
James Morris
<jmorris@namei.org>
^ permalink raw reply
* Re: REGRESSION: On 2.6.32-rc5 the firmware hangs, and the nic is unusable.
From: Eric W. Biederman @ 2009-11-04 21:43 UTC (permalink / raw)
To: Dhananjay Phadke; +Cc: netdev@vger.kernel.org, Ameen Rahman, Amit Salecha
In-Reply-To: <4AF1D2C6.20002@qlogic.com>
Dhananjay Phadke <dhananjay.phadke@qlogic.com> writes:
> Eric W. Biederman wrote:
>> On 2.6.31.5 I get:
>> ethtool -i eth0
>> driver: netxen_nic
>> version: 4.0.30
>> firmware-version: 4.0.305
>> bus-info: 0000:06:00.0
>>
>
> Agree, 2.6.31 window missed bonding (mac addr setup) fixes.
>
>> And everything works except bonding.
>>
>> On 2.6.32-rc5 I dhcp I get an IP
>> there is a sanity test ping.
>
>>
>> Then the driver reports a firmware hang and
>> the interface goes down and I am dead in the water.
>>
>
>> I'm a bit frustrated with this as it seems with each kernel release
>> the driver gets a little bit less usable.
>>
>> Have I given you enough information to track this down?
>
> This can be fixed in next rc patch of 2.6.32, if I get enough info to debug.
>
> Could you provide full dmesg, so that I can see what's going on around firmware
> hang message? Also provide your test details (bonding / whatever configured).
I will dig up that dmesg in a bit. Working on a machine when the network is
down is a pain.
There was no bonding configured. Essentially just:
ifup eth0 finally get a dhcp response firmware hangs..
Eric
^ permalink raw reply
* Re: [net-next-2.6 PATCH RFC] TCPCT part 1d: generate Responder Cookie
From: Paul E. McKenney @ 2009-11-04 21:48 UTC (permalink / raw)
To: William Allen Simpson
Cc: Eric Dumazet, Linux Kernel Developers,
Linux Kernel Network Developers
In-Reply-To: <4AF0B0D2.4030905@gmail.com>
On Tue, Nov 03, 2009 at 05:38:10PM -0500, William Allen Simpson wrote:
> Eric Dumazet wrote:
>> This patch looks fine, but I dont see how this new function is used.
>> Some points :
>> 1) We are working hard to remove rwlocks from network stack, so please
>> dont
>> add a new one. You probably can use a seqlock or RCU, or a server handling
>> 10.000 connections request per second on many NIC will hit this rwlock.
> This is my attempt at using RCU, as seqlock didn't seem to apply (and is
> missing any Documentation.)
>
> After the discussion about context, one question that I have is the need
> for the _bh suffix?
>
> + rcu_read_lock_bh();
> + memcpy(&xvp->cookie_bakery[0],
> + &rcu_dereference(tcp_secret_generating)->secrets[0],
> + sizeof(tcp_secret_generating->secrets));
> + rcu_read_unlock_bh();
>
>
> Documentation/RCU/checklist.txt #7 says:
>
> One exception to this rule: rcu_read_lock() and rcu_read_unlock()
> may be substituted for rcu_read_lock_bh() and rcu_read_unlock_bh()
> in cases where local bottom halves are already known to be
> disabled, for example, in irq or softirq context. Commenting
> such cases is a must, of course! And the jury is still out on
> whether the increased speed is worth it.
I strongly suggest using the matching primitives unless you have a
really strong reason not to.
> diff --git a/include/linux/cryptohash.h b/include/linux/cryptohash.h
> index c118b2a..ec78a4b 100644
> --- a/include/linux/cryptohash.h
> +++ b/include/linux/cryptohash.h
[ . . . ]
> + if (unlikely(tcp_secret_primary->expires ==
> + tcp_secret_secondary->expires)) {
> + struct timespec tv;
> +
> + getnstimeofday(&tv);
> + secrets[COOKIE_DIGEST_WORDS+0] ^= (u32)tv.tv_nsec;
> + tcp_secret_secondary->expires = jiffy
> + + TCP_SECRET_1MSL;
> + } else {
> + tcp_secret_secondary->expires = jiffy
> + + TCP_SECRET_LIFE;
> + tcp_secret_primary->expires = jiffy
> + + TCP_SECRET_2MSL;
> + }
> + memcpy(&tcp_secret_secondary->secrets[0],
> + &secrets[0],
> + sizeof(secrets));
> +
> + rcu_assign_pointer(tcp_secret_generating,
> + tcp_secret_secondary);
> + rcu_assign_pointer(tcp_secret_retiring,
> + tcp_secret_primary);
> + spin_unlock(&tcp_secret_locker);
> + /* call_rcu() or synchronize_rcu() not needed. */
Would you be willing to say why? Are you relying on a time delay for a
given item to pass through tcp_secret_secondary and tcp_secret_retiring
or some such? If so, how do you know that this time delay will always
be long enough?
Or are you just shuffling the data structures around, without ever
freeing them? If so, is it really OK for a given reader to keep a
reference to a given item through the full range of shuffling, especially
given that it might be accesssing this concurrently with the ->expires
assignments above?
Either way, could you please expand the comment to give at least some
hint to the poor guy reading your code? ;-)
Thanx, Paul
^ permalink raw reply
* Re: [announce] new rt2800 drivers for Ralink wireless & project tree
From: Ivo van Doorn @ 2009-11-04 21:51 UTC (permalink / raw)
To: Ingo Molnar
Cc: Bartlomiej Zolnierkiewicz, linux-wireless, linux-kernel, netdev,
Randy Dunlap, Luis Correia, John W. Linville, Johannes Berg,
Jarek Poplawski, Pekka Enberg, David Miller
In-Reply-To: <20091104083737.GA16978@elte.hu>
On Wednesday 04 November 2009, Ingo Molnar wrote:
>
> * Ivo van Doorn <ivdoorn@gmail.com> wrote:
>
> > > MAINTAINERS: add rt2800 entry
> >
> > I see you decided to take over the maintainership? Doesn't that need
> > the current maintainer to move away, or was this part of the "going
> > over other peoples head" plan?
> >
> > [...]
> >
> > These are too much (and too big) patches for me to review at once,
> > I'll look at them later.
>
> Frankly, having read through the recent discussions related to the
> rt2800pci/usb drivers, the subtle (and largely undeserved) group
> violence and abuse you are inflicting on Bart is stomach-turning.
>
> The non-working rt2800pci driver has been pending in your private tree
> for how long, 1.5 _years_?
Something like that.
> Look at the diffstat of Bart's driver:
>
> 15 files changed, 4036 insertions(+), 7158 deletions(-)
>
> He reduced your 5.2 KLOC non-working driver into a 1.8 KLOC _working_
> driver.
Bullshit, read the mails again.
I have acked a portion of fixes because those were small and obviously
correct. There are some minor bugfixes in them but none of them would
magically make the card work for everybody. So the number of lines is
decreased but the status of the driver is the same.
Some people actually require sleep during the night, perhaps that you don't need
that and can hence review 41 patches which changes thousands of lines on the
same day the patches were submitted.
> And _still_ your complaint about Bart's series is that he updated the
> MAINTAINERS entry and added an entry for rt2800? Heck _sure_ he should
> update it, he is the one doing the hard work of trying to bring it to
> users, trying to clean up a messy driver space, trying to turn crap into
> gold.
So if I want to focus on something different in the kernel, I just send 1 patch,
and a second to claim the maintainership of it even though there is an active
maintainer available?
> The thing is, if you dont have the time or interest to listen to and act
> upon review feedback, be constructive about it and fix (obvious)
> structural problems in your rt2800 code, you should just step aside and
> let Bart maintain what he is apparently more capable of maintaining than
> you are.
>
> What you are doing here is a thinly veiled land-grab: you did a minimal
> token driver for rt2800 that doesnt work, kept it in your private tree
> for _1.5 years_, and the moment someone _else_ came along and did
> something better and more functional in drivers/staging/, you discovered
> your sudden interest for it and moved the crappy driver upstream at
> lightning's speed (it is already in net-next AFAICS, despite negative
> test and review feedback) - ignoring and throwing away all the work that
> Bart has done.
Get your facts straight, the bullshit level in your mail is staggering.
You have no fucking clue who wrote the rt2800 driver which is in drivers/staging/,
you have no clue why it was added, and you don't even know what the intention
was for that driver from day 1 (which was clearly communicated!)
You even are missing the point _why_ the rt2x00 driver was 1.5 years in development,
but I'll highlight that part for you:
Because a lot of people prefer looking from the sideline, contributing _nothing_
and then after a year complain that the development is going too slowly and they
could have done better. Apparently that is the style you prefer, but that is most
definately _not_ how I think Open Source should work.
As for "throwing away that work" I ACKED 10 of his patches, and said I would review
the rest later! But like I said, apparently it is a bad habit for people to sleep during
the night.
> Such behavior wouldnt fly in _any_ other Linux subsystem, but apparently
> there is one set of rules for upstream kernel maintainers and then
> there's another, different set of rules for upstream wireless driver
> maintainers.
So non-wireless maintainers don't need to review patches before giving their Ack?
Well that makes the Acked-by and Signed-off rules completely meaningless,
I wonder why everybody is demanding it before patches are merged...
Ivo
^ permalink raw reply
* [PATCH net-next-2.6] ip_frag:
From: Eric Dumazet @ 2009-11-04 21:54 UTC (permalink / raw)
To: David S. Miller; +Cc: Linux Netdev List
When sending fragmentation expiration ICMP V4/V6 messages,
we can avoid touching device refcount, thanks to RCU
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
net/ipv4/ip_fragment.c | 6 +++---
net/ipv6/reassembly.c | 13 ++++++-------
2 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 575f9bd..93e50d0 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -206,10 +206,10 @@ static void ip_expire(unsigned long arg)
struct sk_buff *head = qp->q.fragments;
/* Send an ICMP "Fragment Reassembly Timeout" message. */
- if ((head->dev = dev_get_by_index(net, qp->iif)) != NULL) {
+ rcu_read_lock();
+ if ((head->dev = dev_get_by_index_rcu(net, qp->iif)) != NULL)
icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
- dev_put(head->dev);
- }
+ rcu_read_unlock();
}
out:
spin_unlock(&qp->q.lock);
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index da5bd0e..dce699f 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -208,18 +208,17 @@ static void ip6_frag_expire(unsigned long data)
fq_kill(fq);
net = container_of(fq->q.net, struct net, ipv6.frags);
- dev = dev_get_by_index(net, fq->iif);
+ rcu_read_lock();
+ dev = dev_get_by_index_rcu(net, fq->iif);
if (!dev)
- goto out;
+ goto out_rcu_unlock;
- rcu_read_lock();
IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT);
IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
- rcu_read_unlock();
/* Don't send error if the first segment did not arrive. */
if (!(fq->q.last_in & INET_FRAG_FIRST_IN) || !fq->q.fragments)
- goto out;
+ goto out_rcu_unlock;
/*
But use as source device on which LAST ARRIVED
@@ -228,9 +227,9 @@ static void ip6_frag_expire(unsigned long data)
*/
fq->q.fragments->dev = dev;
icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev);
+out_rcu_unlock:
+ rcu_read_unlock();
out:
- if (dev)
- dev_put(dev);
spin_unlock(&fq->q.lock);
fq_put(fq);
}
^ permalink raw reply related
* Re: pull request: wireless-next-2.6 2009-10-28
From: Pavel Machek @ 2009-11-04 22:00 UTC (permalink / raw)
To: Ivo van Doorn
Cc: Jiri Kosina, Luis Correia, John W. Linville, Ingo Molnar,
Johannes Berg, Jarek Poplawski, Bartlomiej Zolnierkiewicz,
Pekka Enberg, David Miller, linux-wireless, netdev, linux-kernel
In-Reply-To: <200911042217.49144.IvDoorn@gmail.com>
> > But yes, he got flamed for this for some odd reason. I got the impression
> > that the community around rt2x00 doesn't like (or understand) the way how
> > opensource development happens.
>
> Well you mean the open source development where non-contributors
> complain that the contributors work too slowly?
This was the case when non-contributor complained that patch adds
2KLoC of unneccessary code.
> Perhaps
> that is the policy in some companies which try to import it into the
> Open Source world...
Do you really have to attack everyone around?
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox