[ARM] tegra_i2s_audio: add more elaborate error counts
Iliyan Malchev [Mon, 4 Oct 2010 19:10:29 +0000 (12:10 -0700)]
This patch replaces the error counter with two separate error counters, one for
late dma callbacks, and another for overruns (during recording) or underruns
(during playback).  The ioctls TEGRA_AUDIO_IN_GET_ERROR_COUNT and
TEGRA_AUDIO_OUT_GET_ERROR_COUNT now take a pointer to a struct containing both
error counters.

Signed-off-by: Iliyan Malchev <malchev@google.com>

arch/arm/mach-tegra/tegra_i2s_audio.c
include/linux/tegra_audio.h

index 4cbcf98..b1344fc 100644 (file)
@@ -72,7 +72,7 @@ struct audio_stream {
        struct completion fifo_completion;
        struct scatterlist sg;
 
-       unsigned errors;
+       struct tegra_audio_error_counts errors;
 
        int i2s_fifo_atn_level;
 
@@ -559,7 +559,7 @@ static bool stop_playback_if_necessary(struct audio_stream *aos)
        if (kfifo_is_empty(&aos->fifo)) {
                sound_ops->stop_playback(aos);
                if (aos->active)
-                       aos->errors++;
+                       aos->errors.full_empty++; /* underflow */
                spin_unlock_irqrestore(&aos->dma_req_lock, flags);
                pm_qos_update_request(aos->pm_qos, PM_QOS_DEFAULT_VALUE);
                return true;
@@ -575,7 +575,7 @@ static bool stop_recording_if_necessary_nosync(struct audio_stream *ais)
 
        if (ads->recording_cancelled || kfifo_is_full(&ais->fifo)) {
                if (kfifo_is_full(&ais->fifo))
-                       ais->errors++;
+                       ais->errors.full_empty++;  /* overflow */
                sound_ops->stop_recording(ais);
                return true;
        }
@@ -697,7 +697,7 @@ static void dma_tx_complete_callback(struct tegra_dma_req *req)
        if (delta_us > max_delay_us) {
                pr_debug("%s: too late by %lld us\n", __func__,
                        delta_us - max_delay_us);
-               aos->errors++;
+               aos->errors.late_dma++;
        }
 
        kfifo_dma_out_finish(&aos->fifo, count);
@@ -1074,7 +1074,7 @@ static irqreturn_t i2s_interrupt(int irq, void *data)
 
        if (status & I2S_I2S_FIFO_RX_ERR) {
                ads->pio_stats.rx_fifo_errors++;
-               ads->in.errors++;
+               ads->in.errors.full_empty++;
        }
 
        if (status & I2S_FIFO_ERR)
@@ -1283,7 +1283,7 @@ static long tegra_audio_out_ioctl(struct file *file,
                                sizeof(aos->errors)))
                        rc = -EFAULT;
                if (!rc)
-                       aos->errors = 0;
+                       memset(&aos->errors, 0, sizeof(aos->errors));
                break;
        case TEGRA_AUDIO_OUT_PRELOAD_FIFO: {
                struct tegra_audio_out_preload preload;
@@ -1422,7 +1422,7 @@ static long tegra_audio_in_ioctl(struct file *file,
                                sizeof(ais->errors)))
                        rc = -EFAULT;
                if (!rc)
-                       ais->errors = 0;
+                       memset(&ais->errors, 0, sizeof(ais->errors));
                break;
        default:
                rc = -EINVAL;
@@ -1698,7 +1698,7 @@ static int tegra_audio_out_open(struct inode *inode, struct file *file)
        mutex_lock(&ads->out.lock);
        if (!ads->out.opened++) {
                pr_info("%s: resetting fifo and error count\n", __func__);
-               ads->out.errors = 0;
+               memset(&ads->out.errors, 0, sizeof(ads->out.errors));
                kfifo_reset(&ads->out.fifo);
        }
        mutex_unlock(&ads->out.lock);
@@ -1735,7 +1735,7 @@ static int tegra_audio_in_open(struct inode *inode, struct file *file)
                 * input device.
                 */
                ads->recording_cancelled = false;
-               ads->in.errors = 0;
+               memset(&ads->in.errors, 0, sizeof(ads->in.errors));
                kfifo_reset(&ads->in.fifo);
        }
        mutex_unlock(&ads->in.lock);
index 15139cc..07192b2 100644 (file)
@@ -52,11 +52,16 @@ struct tegra_audio_buf_config {
 #define TEGRA_AUDIO_OUT_GET_BUF_CONFIG _IOR(TEGRA_AUDIO_MAGIC, 7, \
                        struct tegra_audio_buf_config *)
 
+struct tegra_audio_error_counts {
+       unsigned late_dma;
+       unsigned full_empty; /* empty for playback, full for recording */
+};
+
 #define TEGRA_AUDIO_IN_GET_ERROR_COUNT _IOR(TEGRA_AUDIO_MAGIC, 8, \
-                       unsigned *)
+                       struct tegra_audio_error_counts *)
 
 #define TEGRA_AUDIO_OUT_GET_ERROR_COUNT        _IOR(TEGRA_AUDIO_MAGIC, 9, \
-                       unsigned *)
+                       struct tegra_audio_error_counts *)
 
 struct tegra_audio_out_preload {
        void *data;