c - How can I delay in a Linux interrupt handler (I know sleeping usually not possible) -


i'm working on embedded linux arm system needs react power failure signal turning off power supplies (via gpio control) in specific sequence. process needs start possible, i've installed interrupt handler detect power failure.

the problem need introduce little bit of delay between turning each supply off. understand delays not allowed in interrupt handler, it's totally okay if handler never returns (power failing!).

i'm trying introduce delay using method described in this post, can't life of me cause measurable delay (observed on oscilloscope).

what doing wrong, , how can right?

what follows relevant code.

/* function sets en_gpio low, waits until pg_gpio goes low. */ static inline void powerdown(int en_gpio, int pg_gpio) {     /* bring enable line low. */     gpio_set_value(en_gpio, 0);     /* loop until power goes low. */     while (gpio_get_value(pg_gpio) != 0); }  /* attempt @ delay function. */ #define delay_count 1000000000 static void delay(void) {     volatile u_int32_t random;     volatile u_int32_t accum;     volatile u_int32_t i;      get_random_bytes((void*)&random, 4);     accum = 0;     (i = 0; < delay_count; i++)         accum = accum * random; }  /* interrupt handler. */ static irqreturn_t power_fail_interrupt(int irq, void *dev_id) {     powerdown(vcc0v75_en, vcc0v75_pg);     delay();     powerdown(dvdd15_en, dvdd15_pg);     delay();     powerdown(dvdd18_en, dvdd18_pg);     delay();     powerdown(cvdd1_en, cvdd1_pg);     delay();     powerdown(cvdd_en, cvdd_pg);     /* doesn't matter if past point. power failing. */     /* i'm amazed printk() gets message out before power drops! */     printk(kern_alert "egon_power_fail driver: power failure detected!\n");     return irq_handled; } 

using delay functions in hard irq handlers bad idea, because interrupts disabled in hard irq handler , system hang until hard irq function finished. on other hand, can't use sleep functions in hard irq handler since hard irq atomic context.

taking account, may want use threaded irq. way hard irq handler wakes bottom half irq handler (which executed in kernel thread). in threaded handler can use regular sleep functions.

to implement threaded irq instead of regular irq, replace request_irq() function request_threaded_irq() function. e.g. if have requesting irq this:

ret = request_irq(irq, your_irq_handler, irqf_shared,                   dev_name(&dev->dev), chip); 

you can replace this:

ret = request_threaded_irq(irq, null, your_irq_handler,                            irqf_oneshot | irqf_shared,                            dev_name(&dev->dev), chip); 

here null means standard hard irq handler used (which wakes threaded irq handler), , your_irq_handler() function executed in kernel thread (where can call sleep functions). irqf_oneshot flag should used when requesting threaded irq.

it should mentioned there managed version ofrequest_threaded_irq() function, called devm_request_threaded_irq(). using (instead of regular request_threaded_irq()) allows omit free_irq() function in driver exit function (and in error path). recommend use devm_* function (if kernel version has it). don't forget remove free_irq() calls in driver if decided go devm_*.

tl;dr

replace request_irq() request_threaded_irq() (as shown above) , able use sleep in irq handler.


Comments

Popular posts from this blog

c++ - Difference between pre and post decrement in recursive function argument -

php - Nothing but 'run(); ' when browsing to my local project, how do I fix this? -

php - How can I echo out this array? -