diff for duplicates of <42261B8A.9070409@acm.org> diff --git a/a/1.txt b/N1/1.txt index 0673ec8..a2cc655 100644 --- a/a/1.txt +++ b/N1/1.txt @@ -1,201 +1 @@ See part 1 for details on what this does... - --------------- next part -------------- -This patch adds handling of the op q to the I2C main code -in preparation for the non-blocking changes. - -Signed-off-by: Corey Minyard <minyard@acm.org> - -Index: linux-2.6.11-rc5-mm1/drivers/i2c/i2c-core.c -=================================--- linux-2.6.11-rc5-mm1.orig/drivers/i2c/i2c-core.c -+++ linux-2.6.11-rc5-mm1/drivers/i2c/i2c-core.c -@@ -85,6 +85,8 @@ - complete(&adap->dev_released); - } - -+#define entry_completed(e) (atomic_read(&(e)->completed) <= 0) -+ - static struct device_driver i2c_adapter_driver = { - .name = "i2c_adapter", - .bus = &i2c_bus_type, -@@ -165,6 +167,8 @@ - } - - adap->nr = id & MAX_ID_MASK; -+ spin_lock_init(&adap->q_lock); -+ INIT_LIST_HEAD(&adap->q); - init_MUTEX(&adap->bus_lock); - init_MUTEX(&adap->clist_lock); - list_add_tail(&adap->list,&adapters); -@@ -587,6 +591,7 @@ - { - entry->xfer_type = I2C_OP_I2C; - entry->complete = NULL; -+ kref_init(&entry->usecount); - if (adap->algo->master_xfer) { - dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", - entry->i2c.num); -@@ -1284,6 +1289,7 @@ - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return -ENOMEM; -+ kref_init(&entry->usecount); - - entry->xfer_type = I2C_OP_SMBUS; - entry->smbus.addr = addr; -@@ -1335,6 +1341,91 @@ - return (func & adap_func) = func; - } - -+/* ---------------------------------------------------- -+ * Entry handling -+ * ---------------------------------------------------- -+ */ -+ -+/* Get the first entry off the head of the queue and lock it there. -+ The entry is guaranteed to remain first in the list and the handler -+ not be called until i2c_entry_put() is called. */ -+static struct i2c_op_q_entry *_i2c_entry_get(struct i2c_adapter * adap) -+{ -+ struct i2c_op_q_entry * entry = NULL; -+ -+ if (!list_empty(&adap->q)) { -+ struct list_head * link = adap->q.next; -+ entry = list_entry(link, struct i2c_op_q_entry, link); -+ if (entry_completed(entry)) -+ entry = NULL; -+ else -+ kref_get(&entry->usecount); -+ } -+ pr_debug("_i2c_entry_get %p %p\n", adap, entry); -+ return entry; -+} -+ -+struct i2c_op_q_entry *i2c_entry_get(struct i2c_adapter * adap) -+{ -+ unsigned long flags; -+ struct i2c_op_q_entry * entry; -+ -+ spin_lock_irqsave(&adap->q_lock, flags); -+ entry = _i2c_entry_get(adap); -+ spin_unlock_irqrestore(&adap->q_lock, flags); -+ return entry; -+} -+ -+static void i2c_op_release(struct kref *ref) -+{ -+ /* Nothing to do here, all handling is from the kref_put return -+ code. */ -+} -+ -+void i2c_entry_put(struct i2c_adapter * adap, -+ struct i2c_op_q_entry * entry) -+{ -+ unsigned long flags; -+ struct i2c_op_q_entry * new_entry; -+ -+ restart: -+ pr_debug("i2c_put %p %p\n", adap, entry); -+ -+ spin_lock_irqsave(&adap->q_lock, flags); -+ if (kref_put(&entry->usecount, i2c_op_release)) { -+ list_del(&entry->link); -+ -+ /* Get the next entry to start. */ -+ new_entry = _i2c_entry_get(adap); -+ spin_unlock_irqrestore(&adap->q_lock, flags); -+ -+ entry->handler(entry); -+ -+ if (new_entry) { -+ /* start entry will go here. */ -+ if (new_entry->start) -+ complete(new_entry->start); -+ /* Do tail recursion ourself. */ -+ entry = new_entry; -+ goto restart; -+ } -+ } else -+ spin_unlock_irqrestore(&adap->q_lock, flags); -+} -+ -+void i2c_op_done(struct i2c_adapter *adap, struct i2c_op_q_entry *e) -+{ -+ pr_debug("i2c_op_done: %p %p\n", adap, e); -+ if (atomic_dec_and_test(&e->completed)) { -+ /* We are the lucky winner! We get to clean up the -+ entry. */ -+ if (e->complete) -+ e->complete(adap, e); -+ } -+ -+ i2c_entry_put(adap, e); -+} -+ - EXPORT_SYMBOL(i2c_add_adapter); - EXPORT_SYMBOL(i2c_del_adapter); - EXPORT_SYMBOL(i2c_add_driver); -@@ -1346,6 +1437,7 @@ - EXPORT_SYMBOL(i2c_clients_command); - EXPORT_SYMBOL(i2c_check_addr); - -+EXPORT_SYMBOL(i2c_op_done); - EXPORT_SYMBOL(i2c_master_send); - EXPORT_SYMBOL(i2c_master_recv); - EXPORT_SYMBOL(i2c_control); -Index: linux-2.6.11-rc5-mm1/include/linux/i2c.h -=================================--- linux-2.6.11-rc5-mm1.orig/include/linux/i2c.h -+++ linux-2.6.11-rc5-mm1/include/linux/i2c.h -@@ -34,6 +34,8 @@ - #include <linux/device.h> /* for struct device */ - #include <linux/completion.h> - #include <linux/kref.h> -+#include <linux/list.h> -+#include <linux/spinlock.h> - #include <asm/semaphore.h> - #include <asm/atomic.h> - -@@ -182,6 +184,33 @@ - } - - /* -+ * About locking and the non-blocking interface. -+ * -+ * The poll operations are called single-threaded (along with the -+ * xxx_start operations), so if the driver is only polled then there -+ * is no need to do any locking. If you are using interrupts, then -+ * the timer operations and interrupts can race and you need to lock -+ * appropriately. -+ * -+ * i2c_op_done() can be called multiple times on the same entry (as -+ * long as each one has a get operation). This handles poll and -+ * interrupt races calling i2c_op_done(). It will do the right thing. -+ */ -+ -+/* Called from an non-blocking interface to get the current working -+ entry. Returns NULL if there is none. This is primarily for -+ interrupt handlers to determine what they should be working on. -+ Note that if you call i2c_entry_get() and get a non-null entry, you -+ must call i2c_entry_put() on it. */ -+struct i2c_op_q_entry *i2c_entry_get(struct i2c_adapter * adap); -+void i2c_entry_put(struct i2c_adapter * adap, -+ struct i2c_op_q_entry * entry); -+ -+/* Called from an non-blocking interface to report that an operation -+ has completed. Can be called from interrupt context. */ -+void i2c_op_done(struct i2c_adapter *adap, struct i2c_op_q_entry *entry); -+ -+/* - * The following structs are for those who like to implement new bus drivers: - * i2c_algorithm is the interface to a class of hardware solutions which can - * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584 -@@ -229,6 +258,9 @@ - int (*client_unregister)(struct i2c_client *); - - /* data fields that are valid for all devices */ -+ struct list_head q; -+ spinlock_t q_lock; -+ - struct semaphore bus_lock; - - int timeout; diff --git a/N1/2.hdr b/N1/2.hdr new file mode 100644 index 0000000..3468fa9 --- /dev/null +++ b/N1/2.hdr @@ -0,0 +1,5 @@ +Content-Type: text/plain; + name="i2c_opq_handling.diff" +Content-Transfer-Encoding: 7bit +Content-Disposition: inline; + filename="i2c_opq_handling.diff" diff --git a/N1/2.txt b/N1/2.txt new file mode 100644 index 0000000..e0190f4 --- /dev/null +++ b/N1/2.txt @@ -0,0 +1,200 @@ +This patch adds handling of the op q to the I2C main code +in preparation for the non-blocking changes. + +Signed-off-by: Corey Minyard <minyard@acm.org> + +Index: linux-2.6.11-rc5-mm1/drivers/i2c/i2c-core.c +=================================================================== +--- linux-2.6.11-rc5-mm1.orig/drivers/i2c/i2c-core.c ++++ linux-2.6.11-rc5-mm1/drivers/i2c/i2c-core.c +@@ -85,6 +85,8 @@ + complete(&adap->dev_released); + } + ++#define entry_completed(e) (atomic_read(&(e)->completed) <= 0) ++ + static struct device_driver i2c_adapter_driver = { + .name = "i2c_adapter", + .bus = &i2c_bus_type, +@@ -165,6 +167,8 @@ + } + + adap->nr = id & MAX_ID_MASK; ++ spin_lock_init(&adap->q_lock); ++ INIT_LIST_HEAD(&adap->q); + init_MUTEX(&adap->bus_lock); + init_MUTEX(&adap->clist_lock); + list_add_tail(&adap->list,&adapters); +@@ -587,6 +591,7 @@ + { + entry->xfer_type = I2C_OP_I2C; + entry->complete = NULL; ++ kref_init(&entry->usecount); + if (adap->algo->master_xfer) { + dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", + entry->i2c.num); +@@ -1284,6 +1289,7 @@ + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; ++ kref_init(&entry->usecount); + + entry->xfer_type = I2C_OP_SMBUS; + entry->smbus.addr = addr; +@@ -1335,6 +1341,91 @@ + return (func & adap_func) == func; + } + ++/* ---------------------------------------------------- ++ * Entry handling ++ * ---------------------------------------------------- ++ */ ++ ++/* Get the first entry off the head of the queue and lock it there. ++ The entry is guaranteed to remain first in the list and the handler ++ not be called until i2c_entry_put() is called. */ ++static struct i2c_op_q_entry *_i2c_entry_get(struct i2c_adapter * adap) ++{ ++ struct i2c_op_q_entry * entry = NULL; ++ ++ if (!list_empty(&adap->q)) { ++ struct list_head * link = adap->q.next; ++ entry = list_entry(link, struct i2c_op_q_entry, link); ++ if (entry_completed(entry)) ++ entry = NULL; ++ else ++ kref_get(&entry->usecount); ++ } ++ pr_debug("_i2c_entry_get %p %p\n", adap, entry); ++ return entry; ++} ++ ++struct i2c_op_q_entry *i2c_entry_get(struct i2c_adapter * adap) ++{ ++ unsigned long flags; ++ struct i2c_op_q_entry * entry; ++ ++ spin_lock_irqsave(&adap->q_lock, flags); ++ entry = _i2c_entry_get(adap); ++ spin_unlock_irqrestore(&adap->q_lock, flags); ++ return entry; ++} ++ ++static void i2c_op_release(struct kref *ref) ++{ ++ /* Nothing to do here, all handling is from the kref_put return ++ code. */ ++} ++ ++void i2c_entry_put(struct i2c_adapter * adap, ++ struct i2c_op_q_entry * entry) ++{ ++ unsigned long flags; ++ struct i2c_op_q_entry * new_entry; ++ ++ restart: ++ pr_debug("i2c_put %p %p\n", adap, entry); ++ ++ spin_lock_irqsave(&adap->q_lock, flags); ++ if (kref_put(&entry->usecount, i2c_op_release)) { ++ list_del(&entry->link); ++ ++ /* Get the next entry to start. */ ++ new_entry = _i2c_entry_get(adap); ++ spin_unlock_irqrestore(&adap->q_lock, flags); ++ ++ entry->handler(entry); ++ ++ if (new_entry) { ++ /* start entry will go here. */ ++ if (new_entry->start) ++ complete(new_entry->start); ++ /* Do tail recursion ourself. */ ++ entry = new_entry; ++ goto restart; ++ } ++ } else ++ spin_unlock_irqrestore(&adap->q_lock, flags); ++} ++ ++void i2c_op_done(struct i2c_adapter *adap, struct i2c_op_q_entry *e) ++{ ++ pr_debug("i2c_op_done: %p %p\n", adap, e); ++ if (atomic_dec_and_test(&e->completed)) { ++ /* We are the lucky winner! We get to clean up the ++ entry. */ ++ if (e->complete) ++ e->complete(adap, e); ++ } ++ ++ i2c_entry_put(adap, e); ++} ++ + EXPORT_SYMBOL(i2c_add_adapter); + EXPORT_SYMBOL(i2c_del_adapter); + EXPORT_SYMBOL(i2c_add_driver); +@@ -1346,6 +1437,7 @@ + EXPORT_SYMBOL(i2c_clients_command); + EXPORT_SYMBOL(i2c_check_addr); + ++EXPORT_SYMBOL(i2c_op_done); + EXPORT_SYMBOL(i2c_master_send); + EXPORT_SYMBOL(i2c_master_recv); + EXPORT_SYMBOL(i2c_control); +Index: linux-2.6.11-rc5-mm1/include/linux/i2c.h +=================================================================== +--- linux-2.6.11-rc5-mm1.orig/include/linux/i2c.h ++++ linux-2.6.11-rc5-mm1/include/linux/i2c.h +@@ -34,6 +34,8 @@ + #include <linux/device.h> /* for struct device */ + #include <linux/completion.h> + #include <linux/kref.h> ++#include <linux/list.h> ++#include <linux/spinlock.h> + #include <asm/semaphore.h> + #include <asm/atomic.h> + +@@ -182,6 +184,33 @@ + } + + /* ++ * About locking and the non-blocking interface. ++ * ++ * The poll operations are called single-threaded (along with the ++ * xxx_start operations), so if the driver is only polled then there ++ * is no need to do any locking. If you are using interrupts, then ++ * the timer operations and interrupts can race and you need to lock ++ * appropriately. ++ * ++ * i2c_op_done() can be called multiple times on the same entry (as ++ * long as each one has a get operation). This handles poll and ++ * interrupt races calling i2c_op_done(). It will do the right thing. ++ */ ++ ++/* Called from an non-blocking interface to get the current working ++ entry. Returns NULL if there is none. This is primarily for ++ interrupt handlers to determine what they should be working on. ++ Note that if you call i2c_entry_get() and get a non-null entry, you ++ must call i2c_entry_put() on it. */ ++struct i2c_op_q_entry *i2c_entry_get(struct i2c_adapter * adap); ++void i2c_entry_put(struct i2c_adapter * adap, ++ struct i2c_op_q_entry * entry); ++ ++/* Called from an non-blocking interface to report that an operation ++ has completed. Can be called from interrupt context. */ ++void i2c_op_done(struct i2c_adapter *adap, struct i2c_op_q_entry *entry); ++ ++/* + * The following structs are for those who like to implement new bus drivers: + * i2c_algorithm is the interface to a class of hardware solutions which can + * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584 +@@ -229,6 +258,9 @@ + int (*client_unregister)(struct i2c_client *); + + /* data fields that are valid for all devices */ ++ struct list_head q; ++ spinlock_t q_lock; ++ + struct semaphore bus_lock; + + int timeout; diff --git a/a/content_digest b/N1/content_digest index a8f0b55..d7d331d 100644 --- a/a/content_digest +++ b/N1/content_digest @@ -1,22 +1,23 @@ - "ref\042261AFB.40001@acm.org\0" - "From\0minyard@acm.org (Corey Minyard)\0" + "From\0Corey Minyard <minyard@acm.org>\0" "Subject\0[PATCH] Add a non-blocking interface to the I2C code, part3\0" - "Date\0Thu, 19 May 2005 06:25:40 +0000\0" + "Date\0Wed, 02 Mar 2005 14:01:14 -0600\0" "To\0Greg KH <greg@kroah.com>" lkml <linux-kernel@vger.kernel.org> " Sensors <sensors@stimpy.netroedge.com>\0" - "\00:1\0" + "\01:1\0" + "b\0" + See part 1 for details on what this does... + "\01:2\0" + "fn\0i2c_opq_handling.diff\0" "b\0" - "See part 1 for details on what this does...\n" - "\n" - "-------------- next part --------------\n" "This patch adds handling of the op q to the I2C main code\n" "in preparation for the non-blocking changes.\n" "\n" "Signed-off-by: Corey Minyard <minyard@acm.org>\n" "\n" "Index: linux-2.6.11-rc5-mm1/drivers/i2c/i2c-core.c\n" - "=================================--- linux-2.6.11-rc5-mm1.orig/drivers/i2c/i2c-core.c\n" + "===================================================================\n" + "--- linux-2.6.11-rc5-mm1.orig/drivers/i2c/i2c-core.c\n" "+++ linux-2.6.11-rc5-mm1/drivers/i2c/i2c-core.c\n" "@@ -85,6 +85,8 @@\n" " \tcomplete(&adap->dev_released);\n" @@ -53,7 +54,7 @@ " \tentry->xfer_type = I2C_OP_SMBUS;\n" " \tentry->smbus.addr = addr;\n" "@@ -1335,6 +1341,91 @@\n" - " \treturn (func & adap_func) = func;\n" + " \treturn (func & adap_func) == func;\n" " }\n" " \n" "+/* ----------------------------------------------------\n" @@ -153,7 +154,8 @@ " EXPORT_SYMBOL(i2c_master_recv);\n" " EXPORT_SYMBOL(i2c_control);\n" "Index: linux-2.6.11-rc5-mm1/include/linux/i2c.h\n" - "=================================--- linux-2.6.11-rc5-mm1.orig/include/linux/i2c.h\n" + "===================================================================\n" + "--- linux-2.6.11-rc5-mm1.orig/include/linux/i2c.h\n" "+++ linux-2.6.11-rc5-mm1/include/linux/i2c.h\n" "@@ -34,6 +34,8 @@\n" " #include <linux/device.h>\t/* for struct device */\n" @@ -209,4 +211,4 @@ " \n" " \tint timeout;" -21144afd872d5be8005dee5b7df5b773efb4dcf9fede0aee6b7b2932e4f6c32a +8ebf6ffa606e1267aaed21279a2051dc10cee1af0ccab7a9022ab55a9773663f
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.