Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2012 Texas Instruments
0004  * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
0005  */
0006 
0007 #define DSS_SUBSYS_NAME "APPLY"
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/slab.h>
0012 #include <linux/spinlock.h>
0013 #include <linux/jiffies.h>
0014 #include <linux/delay.h>
0015 #include <linux/interrupt.h>
0016 #include <linux/seq_file.h>
0017 
0018 #include <video/omapfb_dss.h>
0019 
0020 #include "dss.h"
0021 #include "dss_features.h"
0022 #include "dispc-compat.h"
0023 
0024 #define DISPC_IRQ_MASK_ERROR            (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
0025                      DISPC_IRQ_OCP_ERR | \
0026                      DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
0027                      DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
0028                      DISPC_IRQ_SYNC_LOST | \
0029                      DISPC_IRQ_SYNC_LOST_DIGIT)
0030 
0031 #define DISPC_MAX_NR_ISRS       8
0032 
0033 struct omap_dispc_isr_data {
0034     omap_dispc_isr_t    isr;
0035     void            *arg;
0036     u32         mask;
0037 };
0038 
0039 struct dispc_irq_stats {
0040     unsigned long last_reset;
0041     unsigned irq_count;
0042     unsigned irqs[32];
0043 };
0044 
0045 static struct {
0046     spinlock_t irq_lock;
0047     u32 irq_error_mask;
0048     struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
0049     u32 error_irqs;
0050     struct work_struct error_work;
0051 
0052 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
0053     spinlock_t irq_stats_lock;
0054     struct dispc_irq_stats irq_stats;
0055 #endif
0056 } dispc_compat;
0057 
0058 
0059 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
0060 static void dispc_dump_irqs(struct seq_file *s)
0061 {
0062     unsigned long flags;
0063     struct dispc_irq_stats stats;
0064 
0065     spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags);
0066 
0067     stats = dispc_compat.irq_stats;
0068     memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats));
0069     dispc_compat.irq_stats.last_reset = jiffies;
0070 
0071     spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags);
0072 
0073     seq_printf(s, "period %u ms\n",
0074             jiffies_to_msecs(jiffies - stats.last_reset));
0075 
0076     seq_printf(s, "irqs %d\n", stats.irq_count);
0077 #define PIS(x) \
0078     seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1])
0079 
0080     PIS(FRAMEDONE);
0081     PIS(VSYNC);
0082     PIS(EVSYNC_EVEN);
0083     PIS(EVSYNC_ODD);
0084     PIS(ACBIAS_COUNT_STAT);
0085     PIS(PROG_LINE_NUM);
0086     PIS(GFX_FIFO_UNDERFLOW);
0087     PIS(GFX_END_WIN);
0088     PIS(PAL_GAMMA_MASK);
0089     PIS(OCP_ERR);
0090     PIS(VID1_FIFO_UNDERFLOW);
0091     PIS(VID1_END_WIN);
0092     PIS(VID2_FIFO_UNDERFLOW);
0093     PIS(VID2_END_WIN);
0094     if (dss_feat_get_num_ovls() > 3) {
0095         PIS(VID3_FIFO_UNDERFLOW);
0096         PIS(VID3_END_WIN);
0097     }
0098     PIS(SYNC_LOST);
0099     PIS(SYNC_LOST_DIGIT);
0100     PIS(WAKEUP);
0101     if (dss_has_feature(FEAT_MGR_LCD2)) {
0102         PIS(FRAMEDONE2);
0103         PIS(VSYNC2);
0104         PIS(ACBIAS_COUNT_STAT2);
0105         PIS(SYNC_LOST2);
0106     }
0107     if (dss_has_feature(FEAT_MGR_LCD3)) {
0108         PIS(FRAMEDONE3);
0109         PIS(VSYNC3);
0110         PIS(ACBIAS_COUNT_STAT3);
0111         PIS(SYNC_LOST3);
0112     }
0113 #undef PIS
0114 }
0115 #endif
0116 
0117 /* dispc.irq_lock has to be locked by the caller */
0118 static void _omap_dispc_set_irqs(void)
0119 {
0120     u32 mask;
0121     int i;
0122     struct omap_dispc_isr_data *isr_data;
0123 
0124     mask = dispc_compat.irq_error_mask;
0125 
0126     for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
0127         isr_data = &dispc_compat.registered_isr[i];
0128 
0129         if (isr_data->isr == NULL)
0130             continue;
0131 
0132         mask |= isr_data->mask;
0133     }
0134 
0135     dispc_write_irqenable(mask);
0136 }
0137 
0138 int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
0139 {
0140     int i;
0141     int ret;
0142     unsigned long flags;
0143     struct omap_dispc_isr_data *isr_data;
0144 
0145     if (isr == NULL)
0146         return -EINVAL;
0147 
0148     spin_lock_irqsave(&dispc_compat.irq_lock, flags);
0149 
0150     /* check for duplicate entry */
0151     for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
0152         isr_data = &dispc_compat.registered_isr[i];
0153         if (isr_data->isr == isr && isr_data->arg == arg &&
0154                 isr_data->mask == mask) {
0155             ret = -EINVAL;
0156             goto err;
0157         }
0158     }
0159 
0160     isr_data = NULL;
0161     ret = -EBUSY;
0162 
0163     for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
0164         isr_data = &dispc_compat.registered_isr[i];
0165 
0166         if (isr_data->isr != NULL)
0167             continue;
0168 
0169         isr_data->isr = isr;
0170         isr_data->arg = arg;
0171         isr_data->mask = mask;
0172         ret = 0;
0173 
0174         break;
0175     }
0176 
0177     if (ret)
0178         goto err;
0179 
0180     _omap_dispc_set_irqs();
0181 
0182     spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
0183 
0184     return 0;
0185 err:
0186     spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
0187 
0188     return ret;
0189 }
0190 EXPORT_SYMBOL(omap_dispc_register_isr);
0191 
0192 int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
0193 {
0194     int i;
0195     unsigned long flags;
0196     int ret = -EINVAL;
0197     struct omap_dispc_isr_data *isr_data;
0198 
0199     spin_lock_irqsave(&dispc_compat.irq_lock, flags);
0200 
0201     for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
0202         isr_data = &dispc_compat.registered_isr[i];
0203         if (isr_data->isr != isr || isr_data->arg != arg ||
0204                 isr_data->mask != mask)
0205             continue;
0206 
0207         /* found the correct isr */
0208 
0209         isr_data->isr = NULL;
0210         isr_data->arg = NULL;
0211         isr_data->mask = 0;
0212 
0213         ret = 0;
0214         break;
0215     }
0216 
0217     if (ret == 0)
0218         _omap_dispc_set_irqs();
0219 
0220     spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
0221 
0222     return ret;
0223 }
0224 EXPORT_SYMBOL(omap_dispc_unregister_isr);
0225 
0226 static void print_irq_status(u32 status)
0227 {
0228     if ((status & dispc_compat.irq_error_mask) == 0)
0229         return;
0230 
0231 #define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""
0232 
0233     pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n",
0234         status,
0235         PIS(OCP_ERR),
0236         PIS(GFX_FIFO_UNDERFLOW),
0237         PIS(VID1_FIFO_UNDERFLOW),
0238         PIS(VID2_FIFO_UNDERFLOW),
0239         dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "",
0240         PIS(SYNC_LOST),
0241         PIS(SYNC_LOST_DIGIT),
0242         dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "",
0243         dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : "");
0244 #undef PIS
0245 }
0246 
0247 /* Called from dss.c. Note that we don't touch clocks here,
0248  * but we presume they are on because we got an IRQ. However,
0249  * an irq handler may turn the clocks off, so we may not have
0250  * clock later in the function. */
0251 static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
0252 {
0253     int i;
0254     u32 irqstatus, irqenable;
0255     u32 handledirqs = 0;
0256     u32 unhandled_errors;
0257     struct omap_dispc_isr_data *isr_data;
0258     struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
0259 
0260     spin_lock(&dispc_compat.irq_lock);
0261 
0262     irqstatus = dispc_read_irqstatus();
0263     irqenable = dispc_read_irqenable();
0264 
0265     /* IRQ is not for us */
0266     if (!(irqstatus & irqenable)) {
0267         spin_unlock(&dispc_compat.irq_lock);
0268         return IRQ_NONE;
0269     }
0270 
0271 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
0272     spin_lock(&dispc_compat.irq_stats_lock);
0273     dispc_compat.irq_stats.irq_count++;
0274     dss_collect_irq_stats(irqstatus, dispc_compat.irq_stats.irqs);
0275     spin_unlock(&dispc_compat.irq_stats_lock);
0276 #endif
0277 
0278     print_irq_status(irqstatus);
0279 
0280     /* Ack the interrupt. Do it here before clocks are possibly turned
0281      * off */
0282     dispc_clear_irqstatus(irqstatus);
0283     /* flush posted write */
0284     dispc_read_irqstatus();
0285 
0286     /* make a copy and unlock, so that isrs can unregister
0287      * themselves */
0288     memcpy(registered_isr, dispc_compat.registered_isr,
0289             sizeof(registered_isr));
0290 
0291     spin_unlock(&dispc_compat.irq_lock);
0292 
0293     for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
0294         isr_data = &registered_isr[i];
0295 
0296         if (!isr_data->isr)
0297             continue;
0298 
0299         if (isr_data->mask & irqstatus) {
0300             isr_data->isr(isr_data->arg, irqstatus);
0301             handledirqs |= isr_data->mask;
0302         }
0303     }
0304 
0305     spin_lock(&dispc_compat.irq_lock);
0306 
0307     unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask;
0308 
0309     if (unhandled_errors) {
0310         dispc_compat.error_irqs |= unhandled_errors;
0311 
0312         dispc_compat.irq_error_mask &= ~unhandled_errors;
0313         _omap_dispc_set_irqs();
0314 
0315         schedule_work(&dispc_compat.error_work);
0316     }
0317 
0318     spin_unlock(&dispc_compat.irq_lock);
0319 
0320     return IRQ_HANDLED;
0321 }
0322 
0323 static void dispc_error_worker(struct work_struct *work)
0324 {
0325     int i;
0326     u32 errors;
0327     unsigned long flags;
0328     static const unsigned fifo_underflow_bits[] = {
0329         DISPC_IRQ_GFX_FIFO_UNDERFLOW,
0330         DISPC_IRQ_VID1_FIFO_UNDERFLOW,
0331         DISPC_IRQ_VID2_FIFO_UNDERFLOW,
0332         DISPC_IRQ_VID3_FIFO_UNDERFLOW,
0333     };
0334 
0335     spin_lock_irqsave(&dispc_compat.irq_lock, flags);
0336     errors = dispc_compat.error_irqs;
0337     dispc_compat.error_irqs = 0;
0338     spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
0339 
0340     dispc_runtime_get();
0341 
0342     for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
0343         struct omap_overlay *ovl;
0344         unsigned bit;
0345 
0346         ovl = omap_dss_get_overlay(i);
0347         bit = fifo_underflow_bits[i];
0348 
0349         if (bit & errors) {
0350             DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
0351                     ovl->name);
0352             ovl->disable(ovl);
0353             msleep(50);
0354         }
0355     }
0356 
0357     for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
0358         struct omap_overlay_manager *mgr;
0359         unsigned bit;
0360 
0361         mgr = omap_dss_get_overlay_manager(i);
0362         bit = dispc_mgr_get_sync_lost_irq(i);
0363 
0364         if (bit & errors) {
0365             int j;
0366 
0367             DSSERR("SYNC_LOST on channel %s, restarting the output "
0368                     "with video overlays disabled\n",
0369                     mgr->name);
0370 
0371             dss_mgr_disable(mgr);
0372 
0373             for (j = 0; j < omap_dss_get_num_overlays(); ++j) {
0374                 struct omap_overlay *ovl;
0375                 ovl = omap_dss_get_overlay(j);
0376 
0377                 if (ovl->id != OMAP_DSS_GFX &&
0378                         ovl->manager == mgr)
0379                     ovl->disable(ovl);
0380             }
0381 
0382             dss_mgr_enable(mgr);
0383         }
0384     }
0385 
0386     if (errors & DISPC_IRQ_OCP_ERR) {
0387         DSSERR("OCP_ERR\n");
0388         for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
0389             struct omap_overlay_manager *mgr;
0390 
0391             mgr = omap_dss_get_overlay_manager(i);
0392             dss_mgr_disable(mgr);
0393         }
0394     }
0395 
0396     spin_lock_irqsave(&dispc_compat.irq_lock, flags);
0397     dispc_compat.irq_error_mask |= errors;
0398     _omap_dispc_set_irqs();
0399     spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
0400 
0401     dispc_runtime_put();
0402 }
0403 
0404 int dss_dispc_initialize_irq(void)
0405 {
0406     int r;
0407 
0408 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
0409     spin_lock_init(&dispc_compat.irq_stats_lock);
0410     dispc_compat.irq_stats.last_reset = jiffies;
0411     dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
0412 #endif
0413 
0414     spin_lock_init(&dispc_compat.irq_lock);
0415 
0416     memset(dispc_compat.registered_isr, 0,
0417             sizeof(dispc_compat.registered_isr));
0418 
0419     dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR;
0420     if (dss_has_feature(FEAT_MGR_LCD2))
0421         dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
0422     if (dss_has_feature(FEAT_MGR_LCD3))
0423         dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;
0424     if (dss_feat_get_num_ovls() > 3)
0425         dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
0426 
0427     /*
0428      * there's SYNC_LOST_DIGIT waiting after enabling the DSS,
0429      * so clear it
0430      */
0431     dispc_clear_irqstatus(dispc_read_irqstatus());
0432 
0433     INIT_WORK(&dispc_compat.error_work, dispc_error_worker);
0434 
0435     _omap_dispc_set_irqs();
0436 
0437     r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat);
0438     if (r) {
0439         DSSERR("dispc_request_irq failed\n");
0440         return r;
0441     }
0442 
0443     return 0;
0444 }
0445 
0446 void dss_dispc_uninitialize_irq(void)
0447 {
0448     dispc_free_irq(&dispc_compat);
0449 }
0450 
0451 static void dispc_mgr_disable_isr(void *data, u32 mask)
0452 {
0453     struct completion *compl = data;
0454     complete(compl);
0455 }
0456 
0457 static void dispc_mgr_enable_lcd_out(enum omap_channel channel)
0458 {
0459     dispc_mgr_enable(channel, true);
0460 }
0461 
0462 static void dispc_mgr_disable_lcd_out(enum omap_channel channel)
0463 {
0464     DECLARE_COMPLETION_ONSTACK(framedone_compl);
0465     int r;
0466     u32 irq;
0467 
0468     if (!dispc_mgr_is_enabled(channel))
0469         return;
0470 
0471     /*
0472      * When we disable LCD output, we need to wait for FRAMEDONE to know
0473      * that DISPC has finished with the LCD output.
0474      */
0475 
0476     irq = dispc_mgr_get_framedone_irq(channel);
0477 
0478     r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
0479             irq);
0480     if (r)
0481         DSSERR("failed to register FRAMEDONE isr\n");
0482 
0483     dispc_mgr_enable(channel, false);
0484 
0485     /* if we couldn't register for framedone, just sleep and exit */
0486     if (r) {
0487         msleep(100);
0488         return;
0489     }
0490 
0491     if (!wait_for_completion_timeout(&framedone_compl,
0492                 msecs_to_jiffies(100)))
0493         DSSERR("timeout waiting for FRAME DONE\n");
0494 
0495     r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
0496             irq);
0497     if (r)
0498         DSSERR("failed to unregister FRAMEDONE isr\n");
0499 }
0500 
0501 static void dispc_digit_out_enable_isr(void *data, u32 mask)
0502 {
0503     struct completion *compl = data;
0504 
0505     /* ignore any sync lost interrupts */
0506     if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD))
0507         complete(compl);
0508 }
0509 
0510 static void dispc_mgr_enable_digit_out(void)
0511 {
0512     DECLARE_COMPLETION_ONSTACK(vsync_compl);
0513     int r;
0514     u32 irq_mask;
0515 
0516     if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
0517         return;
0518 
0519     /*
0520      * Digit output produces some sync lost interrupts during the first
0521      * frame when enabling. Those need to be ignored, so we register for the
0522      * sync lost irq to prevent the error handler from triggering.
0523      */
0524 
0525     irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) |
0526         dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT);
0527 
0528     r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl,
0529             irq_mask);
0530     if (r) {
0531         DSSERR("failed to register %x isr\n", irq_mask);
0532         return;
0533     }
0534 
0535     dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true);
0536 
0537     /* wait for the first evsync */
0538     if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100)))
0539         DSSERR("timeout waiting for digit out to start\n");
0540 
0541     r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl,
0542             irq_mask);
0543     if (r)
0544         DSSERR("failed to unregister %x isr\n", irq_mask);
0545 }
0546 
0547 static void dispc_mgr_disable_digit_out(void)
0548 {
0549     DECLARE_COMPLETION_ONSTACK(framedone_compl);
0550     int r, i;
0551     u32 irq_mask;
0552     int num_irqs;
0553 
0554     if (!dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
0555         return;
0556 
0557     /*
0558      * When we disable the digit output, we need to wait for FRAMEDONE to
0559      * know that DISPC has finished with the output.
0560      */
0561 
0562     irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT);
0563     num_irqs = 1;
0564 
0565     if (!irq_mask) {
0566         /*
0567          * omap 2/3 don't have framedone irq for TV, so we need to use
0568          * vsyncs for this.
0569          */
0570 
0571         irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT);
0572         /*
0573          * We need to wait for both even and odd vsyncs. Note that this
0574          * is not totally reliable, as we could get a vsync interrupt
0575          * before we disable the output, which leads to timeout in the
0576          * wait_for_completion.
0577          */
0578         num_irqs = 2;
0579     }
0580 
0581     r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
0582             irq_mask);
0583     if (r)
0584         DSSERR("failed to register %x isr\n", irq_mask);
0585 
0586     dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false);
0587 
0588     /* if we couldn't register the irq, just sleep and exit */
0589     if (r) {
0590         msleep(100);
0591         return;
0592     }
0593 
0594     for (i = 0; i < num_irqs; ++i) {
0595         if (!wait_for_completion_timeout(&framedone_compl,
0596                     msecs_to_jiffies(100)))
0597             DSSERR("timeout waiting for digit out to stop\n");
0598     }
0599 
0600     r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
0601             irq_mask);
0602     if (r)
0603         DSSERR("failed to unregister %x isr\n", irq_mask);
0604 }
0605 
0606 void dispc_mgr_enable_sync(enum omap_channel channel)
0607 {
0608     if (dss_mgr_is_lcd(channel))
0609         dispc_mgr_enable_lcd_out(channel);
0610     else if (channel == OMAP_DSS_CHANNEL_DIGIT)
0611         dispc_mgr_enable_digit_out();
0612     else
0613         WARN_ON(1);
0614 }
0615 
0616 void dispc_mgr_disable_sync(enum omap_channel channel)
0617 {
0618     if (dss_mgr_is_lcd(channel))
0619         dispc_mgr_disable_lcd_out(channel);
0620     else if (channel == OMAP_DSS_CHANNEL_DIGIT)
0621         dispc_mgr_disable_digit_out();
0622     else
0623         WARN_ON(1);
0624 }
0625 
0626 static inline void dispc_irq_wait_handler(void *data, u32 mask)
0627 {
0628     complete((struct completion *)data);
0629 }
0630 
0631 int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
0632         unsigned long timeout)
0633 {
0634 
0635     int r;
0636     long time_left;
0637     DECLARE_COMPLETION_ONSTACK(completion);
0638 
0639     r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
0640             irqmask);
0641 
0642     if (r)
0643         return r;
0644 
0645     time_left = wait_for_completion_interruptible_timeout(&completion,
0646             timeout);
0647 
0648     omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
0649 
0650     if (time_left == 0)
0651         return -ETIMEDOUT;
0652 
0653     if (time_left == -ERESTARTSYS)
0654         return -ERESTARTSYS;
0655 
0656     return 0;
0657 }