Skip to content

Commit

Permalink
[PATCH] libata: implement ata_wait_register()
Browse files Browse the repository at this point in the history
As waiting for some register bits to change seems to be a common
operation shared by some controllers, implement helper function
ata_wait_register().  This function also takes care of register write
flushing.

Note that the condition is inverted, the wait is over when the masked
value does NOT match @val.  As we're waiting for bits to change, this
test is more powerful and allows the function to be used in more
places.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
  • Loading branch information
Tejun Heo authored and Jeff Garzik committed Apr 11, 2006
1 parent 643be97 commit c22daff
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 0 deletions.
47 changes: 47 additions & 0 deletions drivers/scsi/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -5029,6 +5029,52 @@ int ata_ratelimit(void)
return rc;
}

/**
* ata_wait_register - wait until register value changes
* @reg: IO-mapped register
* @mask: Mask to apply to read register value
* @val: Wait condition
* @interval_msec: polling interval in milliseconds
* @timeout_msec: timeout in milliseconds
*
* Waiting for some bits of register to change is a common
* operation for ATA controllers. This function reads 32bit LE
* IO-mapped register @reg and tests for the following condition.
*
* (*@reg & mask) != val
*
* If the condition is met, it returns; otherwise, the process is
* repeated after @interval_msec until timeout.
*
* LOCKING:
* Kernel thread context (may sleep)
*
* RETURNS:
* The final register value.
*/
u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
unsigned long interval_msec,
unsigned long timeout_msec)
{
unsigned long timeout;
u32 tmp;

tmp = ioread32(reg);

/* Calculate timeout _after_ the first read to make sure
* preceding writes reach the controller before starting to
* eat away the timeout.
*/
timeout = jiffies + (timeout_msec * HZ) / 1000;

while ((tmp & mask) == val && time_before(jiffies, timeout)) {
msleep(interval_msec);
tmp = ioread32(reg);
}

return tmp;
}

/*
* libata is essentially a library of internal helper functions for
* low-level ATA host controller drivers. As such, the API/ABI is
Expand Down Expand Up @@ -5079,6 +5125,7 @@ EXPORT_SYMBOL_GPL(ata_dev_classify);
EXPORT_SYMBOL_GPL(ata_dev_pair);
EXPORT_SYMBOL_GPL(ata_port_disable);
EXPORT_SYMBOL_GPL(ata_ratelimit);
EXPORT_SYMBOL_GPL(ata_wait_register);
EXPORT_SYMBOL_GPL(ata_busy_sleep);
EXPORT_SYMBOL_GPL(ata_port_queue_task);
EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
Expand Down
3 changes: 3 additions & 0 deletions include/linux/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,9 @@ extern unsigned int ata_busy_sleep(struct ata_port *ap,
unsigned long timeout);
extern void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *),
void *data, unsigned long delay);
extern u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
unsigned long interval_msec,
unsigned long timeout_msec);

/*
* Default driver ops implementations
Expand Down

0 comments on commit c22daff

Please sign in to comment.