* [PATCH] ide: use lock bitops for ports serialization (v2)
@ 2008-12-21 20:56 ` Bartlomiej Zolnierkiewicz
0 siblings, 0 replies; 2+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2008-12-21 20:56 UTC (permalink / raw)
To: linux-ide; +Cc: linux-kernel
during more testing it turned out that v1 was too optimistic w.r.t.
devices serialization, v2 fixes it (so the patch can be finally merged
into pata-2.6 tree)
From: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Subject: [PATCH] ide: use lock bitops for ports serialization (v2)
* Add ->host_busy field to struct ide_host and use it's first bit
together with lock bitops to provide new ports serialization method.
* Convert core IDE code to use new ide_[un]lock_host() helpers.
This removes the need for taking hwgroup->lock if host is already
busy on serialized hosts and makes it possible to merge ide_hwgroup_t
into ide_hwif_t (done in the later patch).
* Remove no longer needed ide_hwgroup_t.busy and ide_[un]lock_hwgroup().
* Update do_ide_request() documentation.
v2:
* ide_release_lock() should be called inside IDE_HFLAG_SERIALIZE check.
* Add ide_hwif_t.busy flag and ide_[un]lock_port() for serializing
devices on a port.
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
---
drivers/ide/ide-io.c | 105 ++++++++++++++++++++++++++++++---------------------
include/linux/ide.h | 35 ++---------------
2 files changed, 69 insertions(+), 71 deletions(-)
Index: b/drivers/ide/ide-io.c
===================================================================
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -666,45 +666,54 @@ void ide_stall_queue (ide_drive_t *drive
}
EXPORT_SYMBOL(ide_stall_queue);
+static inline int ide_lock_port(ide_hwif_t *hwif)
+{
+ if (hwif->busy)
+ return 1;
+
+ hwif->busy = 1;
+
+ return 0;
+}
+
+static inline void ide_unlock_port(ide_hwif_t *hwif)
+{
+ hwif->busy = 0;
+}
+
+static inline int ide_lock_host(struct ide_host *host, ide_hwif_t *hwif)
+{
+ int rc = 0;
+
+ if (host->host_flags & IDE_HFLAG_SERIALIZE) {
+ rc = test_and_set_bit_lock(IDE_HOST_BUSY, &host->host_busy);
+ if (rc == 0) {
+ /* for atari only */
+ ide_get_lock(ide_intr, hwif);
+ }
+ }
+ return rc;
+}
+
+static inline void ide_unlock_host(struct ide_host *host)
+{
+ if (host->host_flags & IDE_HFLAG_SERIALIZE) {
+ /* for atari only */
+ ide_release_lock();
+ clear_bit_unlock(IDE_HOST_BUSY, &host->host_busy);
+ }
+}
+
/*
* Issue a new request to a drive from hwgroup
- *
- * A hwgroup is a serialized group of IDE interfaces. Usually there is
- * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
- * may have both interfaces in a single hwgroup to "serialize" access.
- * Or possibly multiple ISA interfaces can share a common IRQ by being grouped
- * together into one hwgroup for serialized access.
- *
- * Note also that several hwgroups can end up sharing a single IRQ,
- * possibly along with many other devices. This is especially common in
- * PCI-based systems with off-board IDE controller cards.
- *
- * The IDE driver uses a per-hwgroup lock to protect the hwgroup->busy flag.
- *
- * The first thread into the driver for a particular hwgroup sets the
- * hwgroup->busy flag to indicate that this hwgroup is now active,
- * and then initiates processing of the top request from the request queue.
- *
- * Other threads attempting entry notice the busy setting, and will simply
- * queue their new requests and exit immediately. Note that hwgroup->busy
- * remains set even when the driver is merely awaiting the next interrupt.
- * Thus, the meaning is "this hwgroup is busy processing a request".
- *
- * When processing of a request completes, the completing thread or IRQ-handler
- * will start the next request from the queue. If no more work remains,
- * the driver will clear the hwgroup->busy flag and exit.
- *
- * The per-hwgroup spinlock is used to protect all access to the
- * hwgroup->busy flag, but is otherwise not needed for most processing in
- * the driver. This makes the driver much more friendlier to shared IRQs
- * than previous designs, while remaining 100% (?) SMP safe and capable.
*/
void do_ide_request(struct request_queue *q)
{
ide_drive_t *drive = q->queuedata;
ide_hwif_t *hwif = drive->hwif;
+ struct ide_host *host = hwif->host;
ide_hwgroup_t *hwgroup = hwif->hwgroup;
- struct request *rq;
+ struct request *rq = NULL;
ide_startstop_t startstop;
/*
@@ -721,9 +730,13 @@ void do_ide_request(struct request_queue
blk_remove_plug(q);
spin_unlock_irq(q->queue_lock);
+
+ if (ide_lock_host(host, hwif))
+ goto plug_device_2;
+
spin_lock_irq(&hwgroup->lock);
- if (!ide_lock_hwgroup(hwgroup, hwif)) {
+ if (!ide_lock_port(hwif)) {
ide_hwif_t *prev_port;
repeat:
prev_port = hwif->host->cur_port;
@@ -731,7 +744,7 @@ repeat:
if (drive->dev_flags & IDE_DFLAG_SLEEPING) {
if (time_before(drive->sleep, jiffies)) {
- ide_unlock_hwgroup(hwgroup);
+ ide_unlock_port(hwif);
goto plug_device;
}
}
@@ -761,7 +774,7 @@ repeat:
spin_lock_irq(&hwgroup->lock);
if (!rq) {
- ide_unlock_hwgroup(hwgroup);
+ ide_unlock_port(hwif);
goto out;
}
@@ -782,7 +795,7 @@ repeat:
blk_pm_request(rq) == 0 &&
(rq->cmd_flags & REQ_PREEMPT) == 0) {
/* there should be no pending command at this point */
- ide_unlock_hwgroup(hwgroup);
+ ide_unlock_port(hwif);
goto plug_device;
}
@@ -798,11 +811,15 @@ repeat:
goto plug_device;
out:
spin_unlock_irq(&hwgroup->lock);
+ if (rq == NULL)
+ ide_unlock_host(host);
spin_lock_irq(q->queue_lock);
return;
plug_device:
spin_unlock_irq(&hwgroup->lock);
+ ide_unlock_host(host);
+plug_device_2:
spin_lock_irq(q->queue_lock);
if (!elv_queue_empty(q))
@@ -844,9 +861,9 @@ static ide_startstop_t ide_dma_timeout_r
ide_dma_off_quietly(drive);
/*
- * un-busy drive etc (hwgroup->busy is cleared on return) and
- * make sure request is sane
+ * un-busy drive etc and make sure request is sane
*/
+
rq = HWGROUP(drive)->rq;
if (!rq)
@@ -895,6 +912,7 @@ static void ide_plug_device(ide_drive_t
void ide_timer_expiry (unsigned long data)
{
ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;
+ ide_hwif_t *uninitialized_var(hwif);
ide_drive_t *uninitialized_var(drive);
ide_handler_t *handler;
ide_expiry_t *expiry;
@@ -918,7 +936,6 @@ void ide_timer_expiry (unsigned long dat
printk(KERN_ERR "%s: ->cur_dev was NULL\n", __func__);
hwgroup->handler = NULL;
} else {
- ide_hwif_t *hwif;
ide_startstop_t startstop = ide_stopped;
if ((expiry = hwgroup->expiry) != NULL) {
@@ -964,15 +981,17 @@ void ide_timer_expiry (unsigned long dat
spin_lock_irq(&hwgroup->lock);
enable_irq(hwif->irq);
if (startstop == ide_stopped) {
- ide_unlock_hwgroup(hwgroup);
+ ide_unlock_port(hwif);
plug_device = 1;
}
}
}
spin_unlock_irqrestore(&hwgroup->lock, flags);
- if (plug_device)
+ if (plug_device) {
+ ide_unlock_host(hwif->host);
ide_plug_device(drive);
+ }
}
/**
@@ -1150,7 +1169,7 @@ irqreturn_t ide_intr (int irq, void *dev
*/
if (startstop == ide_stopped) {
if (hwgroup->handler == NULL) { /* paranoia */
- ide_unlock_hwgroup(hwgroup);
+ ide_unlock_port(hwif);
plug_device = 1;
} else
printk(KERN_ERR "%s: %s: huh? expected NULL handler "
@@ -1161,8 +1180,10 @@ out_handled:
out:
spin_unlock_irqrestore(&hwgroup->lock, flags);
out_early:
- if (plug_device)
+ if (plug_device) {
+ ide_unlock_host(hwif->host);
ide_plug_device(drive);
+ }
return irq_ret;
}
Index: b/include/linux/ide.h
===================================================================
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -828,6 +828,7 @@ typedef struct hwif_s {
unsigned present : 1; /* this interface exists */
unsigned sg_mapped : 1; /* sg_table and sg_nents are ready */
+ unsigned busy : 1; /* serializes devices on a port */
struct device gendev;
struct device *portdev;
@@ -851,8 +852,13 @@ struct ide_host {
unsigned long host_flags;
void *host_priv;
ide_hwif_t *cur_port; /* for hosts requiring serialization */
+
+ /* used for hosts requiring serialization */
+ volatile long host_busy;
};
+#define IDE_HOST_BUSY 0
+
/*
* internal ide interrupt handler type
*/
@@ -866,8 +872,6 @@ typedef struct hwgroup_s {
/* irq handler, if active */
ide_startstop_t (*handler)(ide_drive_t *);
- /* BOOL: protects all fields below */
- volatile int busy;
/* BOOL: polling active & poll_timeout field valid */
unsigned int polling : 1;
@@ -1271,26 +1275,6 @@ extern void ide_stall_queue(ide_drive_t
extern void ide_timer_expiry(unsigned long);
extern irqreturn_t ide_intr(int irq, void *dev_id);
-
-static inline int ide_lock_hwgroup(ide_hwgroup_t *hwgroup, ide_hwif_t *hwif)
-{
- if (hwgroup->busy)
- return 1;
-
- hwgroup->busy = 1;
- /* for atari only */
- ide_get_lock(ide_intr, hwif);
-
- return 0;
-}
-
-static inline void ide_unlock_hwgroup(ide_hwgroup_t *hwgroup)
-{
- /* for atari only */
- ide_release_lock();
- hwgroup->busy = 0;
-}
-
extern void do_ide_request(struct request_queue *);
void ide_init_disk(struct gendisk *, ide_drive_t *);
@@ -1617,13 +1601,6 @@ static inline void ide_set_max_pio(ide_d
extern spinlock_t ide_lock;
extern struct mutex ide_cfg_mtx;
-/*
- * Structure locking:
- *
- * ide_hwgroup_t->busy: hwgroup->lock
- * ide_hwif_t->{hwgroup,mate}: constant, no locking
- * ide_drive_t->hwif: constant, no locking
- */
#define local_irq_set(flags) do { local_save_flags((flags)); local_irq_enable_in_hardirq(); } while (0)
\0
^ permalink raw reply [flat|nested] 2+ messages in thread* [PATCH] ide: use lock bitops for ports serialization (v2)
@ 2008-12-21 20:56 ` Bartlomiej Zolnierkiewicz
0 siblings, 0 replies; 2+ messages in thread
From: Bartlomiej Zolnierkiewicz @ 2008-12-21 20:56 UTC (permalink / raw)
To: linux-ide; +Cc: linux-kernel
during more testing it turned out that v1 was too optimistic w.r.t.devices serialization, v2 fixes it (so the patch can be finally mergedinto pata-2.6 tree)
From: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>Subject: [PATCH] ide: use lock bitops for ports serialization (v2)
* Add ->host_busy field to struct ide_host and use it's first bit together with lock bitops to provide new ports serialization method.
* Convert core IDE code to use new ide_[un]lock_host() helpers.
This removes the need for taking hwgroup->lock if host is already busy on serialized hosts and makes it possible to merge ide_hwgroup_t into ide_hwif_t (done in the later patch).
* Remove no longer needed ide_hwgroup_t.busy and ide_[un]lock_hwgroup().
* Update do_ide_request() documentation.
v2:* ide_release_lock() should be called inside IDE_HFLAG_SERIALIZE check.
* Add ide_hwif_t.busy flag and ide_[un]lock_port() for serializing devices on a port.
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>--- drivers/ide/ide-io.c | 105 ++++++++++++++++++++++++++++++--------------------- include/linux/ide.h | 35 ++--------------- 2 files changed, 69 insertions(+), 71 deletions(-)
Index: b/drivers/ide/ide-io.c===================================================================--- a/drivers/ide/ide-io.c+++ b/drivers/ide/ide-io.c@@ -666,45 +666,54 @@ void ide_stall_queue (ide_drive_t *drive } EXPORT_SYMBOL(ide_stall_queue); +static inline int ide_lock_port(ide_hwif_t *hwif)+{+ if (hwif->busy)+ return 1;++ hwif->busy = 1;++ return 0;+}++static inline void ide_unlock_port(ide_hwif_t *hwif)+{+ hwif->busy = 0;+}++static inline int ide_lock_host(struct ide_host *host, ide_hwif_t *hwif)+{+ int rc = 0;++ if (host->host_flags & IDE_HFLAG_SERIALIZE) {+ rc = test_and_set_bit_lock(IDE_HOST_BUSY, &host->host_busy);+ if (rc == 0) {+ /* for atari only */+ ide_get_lock(ide_intr, hwif);+ }+ }+ return rc;+}++static inline void ide_unlock_host(struct ide_host *host)+{+ if (host->host_flags & IDE_HFLAG_SERIALIZE) {+ /* for atari only */+ ide_release_lock();+ clear_bit_unlock(IDE_HOST_BUSY, &host->host_busy);+ }+}+ /* * Issue a new request to a drive from hwgroup- *- * A hwgroup is a serialized group of IDE interfaces. Usually there is- * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)- * may have both interfaces in a single hwgroup to "serialize" access.- * Or possibly multiple ISA interfaces can share a common IRQ by being grouped- * together into one hwgroup for serialized access.- *- * Note also that several hwgroups can end up sharing a single IRQ,- * possibly along with many other devices. This is especially common in- * PCI-based systems with off-board IDE controller cards.- *- * The IDE driver uses a per-hwgroup lock to protect the hwgroup->busy flag.- *- * The first thread into the driver for a particular hwgroup sets the- * hwgroup->busy flag to indicate that this hwgroup is now active,- * and then initiates processing of the top request from the request queue.- *- * Other threads attempting entry notice the busy setting, and will simply- * queue their new requests and exit immediately. Note that hwgroup->busy- * remains set even when the driver is merely awaiting the next interrupt.- * Thus, the meaning is "this hwgroup is busy processing a request".- *- * When processing of a request completes, the completing thread or IRQ-handler- * will start the next request from the queue. If no more work remains,- * the driver will clear the hwgroup->busy flag and exit.- *- * The per-hwgroup spinlock is used to protect all access to the- * hwgroup->busy flag, but is otherwise not needed for most processing in- * the driver. This makes the driver much more friendlier to shared IRQs- * than previous designs, while remaining 100% (?) SMP safe and capable. */ void do_ide_request(struct request_queue *q) { ide_drive_t *drive = q->queuedata; ide_hwif_t *hwif = drive->hwif;+ struct ide_host *host = hwif->host; ide_hwgroup_t *hwgroup = hwif->hwgroup;- struct request *rq;+ struct request *rq = NULL; ide_startstop_t startstop; /*@@ -721,9 +730,13 @@ void do_ide_request(struct request_queue blk_remove_plug(q); spin_unlock_irq(q->queue_lock);++ if (ide_lock_host(host, hwif))+ goto plug_device_2;+ spin_lock_irq(&hwgroup->lock); - if (!ide_lock_hwgroup(hwgroup, hwif)) {+ if (!ide_lock_port(hwif)) { ide_hwif_t *prev_port; repeat: prev_port = hwif->host->cur_port;@@ -731,7 +744,7 @@ repeat: if (drive->dev_flags & IDE_DFLAG_SLEEPING) { if (time_before(drive->sleep, jiffies)) {- ide_unlock_hwgroup(hwgroup);+ ide_unlock_port(hwif); goto plug_device; } }@@ -761,7 +774,7 @@ repeat: spin_lock_irq(&hwgroup->lock); if (!rq) {- ide_unlock_hwgroup(hwgroup);+ ide_unlock_port(hwif); goto out; } @@ -782,7 +795,7 @@ repeat: blk_pm_request(rq) == 0 && (rq->cmd_flags & REQ_PREEMPT) == 0) { /* there should be no pending command at this point */- ide_unlock_hwgroup(hwgroup);+ ide_unlock_port(hwif); goto plug_device; } @@ -798,11 +811,15 @@ repeat: goto plug_device; out: spin_unlock_irq(&hwgroup->lock);+ if (rq == NULL)+ ide_unlock_host(host); spin_lock_irq(q->queue_lock); return; plug_device: spin_unlock_irq(&hwgroup->lock);+ ide_unlock_host(host);+plug_device_2: spin_lock_irq(q->queue_lock); if (!elv_queue_empty(q))@@ -844,9 +861,9 @@ static ide_startstop_t ide_dma_timeout_r ide_dma_off_quietly(drive); /*- * un-busy drive etc (hwgroup->busy is cleared on return) and- * make sure request is sane+ * un-busy drive etc and make sure request is sane */+ rq = HWGROUP(drive)->rq; if (!rq)@@ -895,6 +912,7 @@ static void ide_plug_device(ide_drive_t void ide_timer_expiry (unsigned long data) { ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;+ ide_hwif_t *uninitialized_var(hwif); ide_drive_t *uninitialized_var(drive); ide_handler_t *handler; ide_expiry_t *expiry;@@ -918,7 +936,6 @@ void ide_timer_expiry (unsigned long dat printk(KERN_ERR "%s: ->cur_dev was NULL\n", __func__); hwgroup->handler = NULL; } else {- ide_hwif_t *hwif; ide_startstop_t startstop = ide_stopped; if ((expiry = hwgroup->expiry) != NULL) {@@ -964,15 +981,17 @@ void ide_timer_expiry (unsigned long dat spin_lock_irq(&hwgroup->lock); enable_irq(hwif->irq); if (startstop == ide_stopped) {- ide_unlock_hwgroup(hwgroup);+ ide_unlock_port(hwif); plug_device = 1; } } } spin_unlock_irqrestore(&hwgroup->lock, flags); - if (plug_device)+ if (plug_device) {+ ide_unlock_host(hwif->host); ide_plug_device(drive);+ } } /**@@ -1150,7 +1169,7 @@ irqreturn_t ide_intr (int irq, void *dev */ if (startstop == ide_stopped) { if (hwgroup->handler == NULL) { /* paranoia */- ide_unlock_hwgroup(hwgroup);+ ide_unlock_port(hwif); plug_device = 1; } else printk(KERN_ERR "%s: %s: huh? expected NULL handler "@@ -1161,8 +1180,10 @@ out_handled: out: spin_unlock_irqrestore(&hwgroup->lock, flags); out_early:- if (plug_device)+ if (plug_device) {+ ide_unlock_host(hwif->host); ide_plug_device(drive);+ } return irq_ret; }Index: b/include/linux/ide.h===================================================================--- a/include/linux/ide.h+++ b/include/linux/ide.h@@ -828,6 +828,7 @@ typedef struct hwif_s { unsigned present : 1; /* this interface exists */ unsigned sg_mapped : 1; /* sg_table and sg_nents are ready */+ unsigned busy : 1; /* serializes devices on a port */ struct device gendev; struct device *portdev;@@ -851,8 +852,13 @@ struct ide_host { unsigned long host_flags; void *host_priv; ide_hwif_t *cur_port; /* for hosts requiring serialization */++ /* used for hosts requiring serialization */+ volatile long host_busy; }; +#define IDE_HOST_BUSY 0+ /* * internal ide interrupt handler type */@@ -866,8 +872,6 @@ typedef struct hwgroup_s { /* irq handler, if active */ ide_startstop_t (*handler)(ide_drive_t *); - /* BOOL: protects all fields below */- volatile int busy; /* BOOL: polling active & poll_timeout field valid */ unsigned int polling : 1; @@ -1271,26 +1275,6 @@ extern void ide_stall_queue(ide_drive_t extern void ide_timer_expiry(unsigned long); extern irqreturn_t ide_intr(int irq, void *dev_id);--static inline int ide_lock_hwgroup(ide_hwgroup_t *hwgroup, ide_hwif_t *hwif)-{- if (hwgroup->busy)- return 1;-- hwgroup->busy = 1;- /* for atari only */- ide_get_lock(ide_intr, hwif);-- return 0;-}--static inline void ide_unlock_hwgroup(ide_hwgroup_t *hwgroup)-{- /* for atari only */- ide_release_lock();- hwgroup->busy = 0;-}- extern void do_ide_request(struct request_queue *); void ide_init_disk(struct gendisk *, ide_drive_t *);@@ -1617,13 +1601,6 @@ static inline void ide_set_max_pio(ide_d extern spinlock_t ide_lock; extern struct mutex ide_cfg_mtx;-/*- * Structure locking:- *- * ide_hwgroup_t->busy: hwgroup->lock- * ide_hwif_t->{hwgroup,mate}: constant, no locking- * ide_drive_t->hwif: constant, no locking- */ #define local_irq_set(flags) do { local_save_flags((flags)); local_irq_enable_in_hardirq(); } while (0) \0ÿôèº{.nÇ+·®+%Ëÿ±éݶ\x17¥wÿº{.nÇ+·¥{±þG«éÿ{ayº\x1dÊÚë,j\a¢f£¢·hïêÿêçz_è®\x03(éÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?¨èÚ&£ø§~á¶iOæ¬z·vØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?I¥
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2008-12-21 20:58 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-12-21 20:56 [PATCH] ide: use lock bitops for ports serialization (v2) Bartlomiej Zolnierkiewicz
2008-12-21 20:56 ` Bartlomiej Zolnierkiewicz
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.