Commit 2f854b82 authored by Finn Thain's avatar Finn Thain Committed by Martin K. Petersen

ncr5380: Sleep when polling, if possible

When in process context, sleep during polling if doing so won't add
significant latency. In interrupt context or if the lock is held, poll
briefly then give up. Keep both core drivers in sync.

Calibrate busy-wait iterations to allow for variation in chip register
access times between different 5380 hardware implementations.
Signed-off-by: default avatarFinn Thain <fthain@telegraphics.com.au>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Tested-by: default avatarOndrej Zary <linux@rainbow-software.org>
Tested-by: default avatarMichael Schmitz <schmitzmic@gmail.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 0ad0eff9
...@@ -293,44 +293,48 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd) ...@@ -293,44 +293,48 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
} }
/** /**
* NCR5380_poll_politely - wait for NCR5380 status bits * NCR5380_poll_politely - wait for chip register value
* @instance: controller to poll * @instance: controller to poll
* @reg: 5380 register to poll * @reg: 5380 register to poll
* @bit: Bitmask to check * @bit: Bitmask to check
* @val: Value required to exit * @val: Value required to exit
* * @wait: Time-out in jiffies
* Polls the NCR5380 in a reasonably efficient manner waiting for *
* an event to occur, after a short quick poll we begin giving the * Polls the chip in a reasonably efficient manner waiting for an
* CPU back in non IRQ contexts * event to occur. After a short quick poll we begin to yield the CPU
* * (if possible). In irq contexts the time-out is arbitrarily limited.
* Returns the value of the register or a negative error code. * Callers may hold locks as long as they are held in irq mode.
*
* Returns 0 if event occurred otherwise -ETIMEDOUT.
*/ */
static int NCR5380_poll_politely(struct Scsi_Host *instance, int reg, int bit, int val, int t) static int NCR5380_poll_politely(struct Scsi_Host *instance,
int reg, int bit, int val, int wait)
{ {
int n = 500; /* At about 8uS a cycle for the cpu access */ struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned long end = jiffies + t; unsigned long deadline = jiffies + wait;
int r; unsigned long n;
while( n-- > 0) /* Busy-wait for up to 10 ms */
{ n = min(10000U, jiffies_to_usecs(wait));
r = NCR5380_read(reg); n *= hostdata->accesses_per_ms;
if((r & bit) == val) n /= 1000;
do {
if ((NCR5380_read(reg) & bit) == val)
return 0; return 0;
cpu_relax(); cpu_relax();
} } while (n--);
/* t time yet ? */ if (irqs_disabled() || in_interrupt())
while(time_before(jiffies, end)) return -ETIMEDOUT;
{
r = NCR5380_read(reg); /* Repeatedly sleep for 1 ms until deadline */
if((r & bit) == val) while (time_is_after_jiffies(deadline)) {
schedule_timeout_uninterruptible(1);
if ((NCR5380_read(reg) & bit) == val)
return 0; return 0;
if(!in_interrupt())
cond_resched();
else
cpu_relax();
} }
return -ETIMEDOUT; return -ETIMEDOUT;
} }
...@@ -773,6 +777,7 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags) ...@@ -773,6 +777,7 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
{ {
int i; int i;
struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
unsigned long deadline;
if(in_interrupt()) if(in_interrupt())
printk(KERN_ERR "NCR5380_init called with interrupts off!\n"); printk(KERN_ERR "NCR5380_init called with interrupts off!\n");
...@@ -812,6 +817,21 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags) ...@@ -812,6 +817,21 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
NCR5380_write(MODE_REG, MR_BASE); NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(TARGET_COMMAND_REG, 0); NCR5380_write(TARGET_COMMAND_REG, 0);
NCR5380_write(SELECT_ENABLE_REG, 0); NCR5380_write(SELECT_ENABLE_REG, 0);
/* Calibrate register polling loop */
i = 0;
deadline = jiffies + 1;
do {
cpu_relax();
} while (time_is_after_jiffies(deadline));
deadline += msecs_to_jiffies(256);
do {
NCR5380_read(STATUS_REG);
++i;
cpu_relax();
} while (time_is_after_jiffies(deadline));
hostdata->accesses_per_ms = i / 256;
return 0; return 0;
} }
......
...@@ -285,6 +285,7 @@ struct NCR5380_hostdata { ...@@ -285,6 +285,7 @@ struct NCR5380_hostdata {
unsigned spin_max_w; unsigned spin_max_w;
#endif #endif
struct workqueue_struct *work_q; struct workqueue_struct *work_q;
unsigned long accesses_per_ms; /* chip register accesses per ms */
}; };
#ifdef __KERNEL__ #ifdef __KERNEL__
......
...@@ -479,43 +479,48 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd) ...@@ -479,43 +479,48 @@ static inline void initialize_SCp(struct scsi_cmnd *cmd)
} }
/** /**
* NCR5380_poll_politely - wait for NCR5380 status bits * NCR5380_poll_politely - wait for chip register value
* @instance: controller to poll * @instance: controller to poll
* @reg: 5380 register to poll * @reg: 5380 register to poll
* @bit: Bitmask to check * @bit: Bitmask to check
* @val: Value required to exit * @val: Value required to exit
* @wait: Time-out in jiffies
* *
* Polls the NCR5380 in a reasonably efficient manner waiting for * Polls the chip in a reasonably efficient manner waiting for an
* an event to occur, after a short quick poll we begin giving the * event to occur. After a short quick poll we begin to yield the CPU
* CPU back in non IRQ contexts * (if possible). In irq contexts the time-out is arbitrarily limited.
* Callers may hold locks as long as they are held in irq mode.
* *
* Returns the value of the register or a negative error code. * Returns 0 if event occurred otherwise -ETIMEDOUT.
*/ */
static int NCR5380_poll_politely(struct Scsi_Host *instance, static int NCR5380_poll_politely(struct Scsi_Host *instance,
int reg, int bit, int val, int t) int reg, int bit, int val, int wait)
{ {
int n = 500; struct NCR5380_hostdata *hostdata = shost_priv(instance);
unsigned long end = jiffies + t; unsigned long deadline = jiffies + wait;
int r; unsigned long n;
while (n-- > 0) { /* Busy-wait for up to 10 ms */
r = NCR5380_read(reg); n = min(10000U, jiffies_to_usecs(wait));
if ((r & bit) == val) n *= hostdata->accesses_per_ms;
n /= 1000;
do {
if ((NCR5380_read(reg) & bit) == val)
return 0; return 0;
cpu_relax(); cpu_relax();
} } while (n--);
/* t time yet ? */ if (irqs_disabled() || in_interrupt())
while (time_before(jiffies, end)) { return -ETIMEDOUT;
r = NCR5380_read(reg);
if ((r & bit) == val) /* Repeatedly sleep for 1 ms until deadline */
while (time_is_after_jiffies(deadline)) {
schedule_timeout_uninterruptible(1);
if ((NCR5380_read(reg) & bit) == val)
return 0; return 0;
if (!in_interrupt())
cond_resched();
else
cpu_relax();
} }
return -ETIMEDOUT; return -ETIMEDOUT;
} }
...@@ -811,6 +816,7 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags) ...@@ -811,6 +816,7 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
{ {
int i; int i;
SETUP_HOSTDATA(instance); SETUP_HOSTDATA(instance);
unsigned long deadline;
hostdata->host = instance; hostdata->host = instance;
hostdata->id_mask = 1 << instance->this_id; hostdata->id_mask = 1 << instance->this_id;
...@@ -845,6 +851,20 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags) ...@@ -845,6 +851,20 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
NCR5380_write(TARGET_COMMAND_REG, 0); NCR5380_write(TARGET_COMMAND_REG, 0);
NCR5380_write(SELECT_ENABLE_REG, 0); NCR5380_write(SELECT_ENABLE_REG, 0);
/* Calibrate register polling loop */
i = 0;
deadline = jiffies + 1;
do {
cpu_relax();
} while (time_is_after_jiffies(deadline));
deadline += msecs_to_jiffies(256);
do {
NCR5380_read(STATUS_REG);
++i;
cpu_relax();
} while (time_is_after_jiffies(deadline));
hostdata->accesses_per_ms = i / 256;
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment