Index: linux-3.12.33-rt47-i386/kernel/irq/Kconfig =================================================================== --- linux-3.12.33-rt47-i386.orig/kernel/irq/Kconfig +++ linux-3.12.33-rt47-i386/kernel/irq/Kconfig @@ -60,6 +60,58 @@ config IRQ_DOMAIN_DEBUG config IRQ_FORCED_THREADING bool +config IRQ_THREAD_PRIOS_PARAM + bool "Support kernel parameter 'irqthreadprios'" + ---help--- + + This Kernel Parameter controls the thread-priority-setting of + automatic generated irq-threads. + The format is: pat:prio[,pat:prio] + + pat is a glob expression which matches the irq-thread name respectively + the second part of the thread name after the '-' in the + middle of the name. + The glob-pattern may use this special characters: + * match 0..n + ? match 1 + [12] char-class 1 and 2 + [1-3] char-class 1 to 3 + [!1-3] inverted char-class 1 to 3 + \* an escaped * + \? an escaped ? + \[ an escaped [ + \] an escaped ] + \: an escaped : + + e.g. irqthreadprios=ata_piix:50,uio*:60,*:20 + set irq/19-ata_piix -> 50 + + you can verify proper operation with: + > dmesg|grep irqthreadprios + > ps axH -o tid,rtprio,policy,comm --sort -rtprio + + +config IRQ_THREAD_PRIOS_PARAM_SIZE + int "maximum size of the irqthreadprios parameter" + depends on IRQ_THREAD_PRIOS_PARAM + default 200 + help + + maximum size of the irqthreadprios parameter. Unfortunately an + automatic adaption does not work because of missing malloc functionality + at early configuration time. :-( + +config IRQ_THREAD_PRIOS_PARAM_MAX + int "maximum number of irqthreadprios entries" + depends on IRQ_THREAD_PRIOS_PARAM + default 20 + help + + maximum number of the irqthreadprios entries. Unfortunately an + automatic adaption does not work because of missing malloc functionality + at early configuration time. :-( + + config SPARSE_IRQ bool "Support sparse irq numbering" if MAY_HAVE_SPARSE_IRQ ---help--- Index: linux-3.12.33-rt47-i386/kernel/irq/manage.c =================================================================== --- linux-3.12.33-rt47-i386.orig/kernel/irq/manage.c +++ linux-3.12.33-rt47-i386/kernel/irq/manage.c @@ -34,6 +34,172 @@ early_param("threadirqs", setup_forced_i # endif #endif + + +#ifdef CONFIG_IRQ_THREAD_PRIOS_PARAM +struct irqthreadprios_tab_t { + char *pat; + int prio; +}; + +static struct irqthreadprios_tab_t irqthreadprios_tab[CONFIG_IRQ_THREAD_PRIOS_PARAM_MAX]; +static int irqthreadprios_num = 0; + + +static bool __match_charclass(const char *pat, char c, const char **npat) +{ + bool complement = false, ret = true; + + if (*pat == '!') { + complement = true; + pat++; + } + if (*pat++ == c) /* First character is special */ + goto end; + + while (*pat && *pat != ']') { /* Matching */ + if (*pat == '-' && *(pat + 1) != ']') { /* Range */ + if (*(pat - 1) <= c && c <= *(pat + 1)) + goto end; + if (*(pat - 1) > *(pat + 1)) + goto error; + pat += 2; + } else if (*pat++ == c) + goto end; + } + if (!*pat) + goto error; + ret = false; + +end: + while (*pat && *pat != ']') /* Searching closing */ + pat++; + if (!*pat) + goto error; + *npat = pat + 1; + return complement ? !ret : ret; + +error: + return false; +} + +/* Glob/lazy pattern matching */ +static bool __match_glob(const char *str, const char *pat) +{ + while (*str && *pat && *pat != '*') { + switch (*pat) { + case '?': /* Matches any single character */ + str++; + pat++; + continue; + case '[': /* Character classes/Ranges */ + if (__match_charclass(pat + 1, *str, &pat)) { + str++; + continue; + } + return false; + case '\\': /* Escaped char match as normal char */ + pat++; + //fallthrough + default: + if (*str++ != *pat++) + return false; + } + } + /* Check wild card */ + if (*pat == '*') { + while (*pat == '*') //skip '*', even more than one + pat++; + if (!*pat) /* Tail wild card matches all */ + return true; + while (*str) + if (__match_glob(str++, pat)) + return true; + } + return !*str && !*pat; +} + + +int find_irq_prio(const char *intname) +{ + // return MAX_USER_RT_PRIO/2; + int i; + for (i = 0; i < irqthreadprios_num; i++) { + char *pat = irqthreadprios_tab[i].pat; + //if((strncmp(s,"*",2)==0)|| (strncmp(s,intname,100)==0)) + if (__match_glob(intname, pat)) { + printk(KERN_INFO + "irqthreadprios: %20s prio = %d (match: %s)\n", + intname, irqthreadprios_tab[i].prio, pat); + + return irqthreadprios_tab[i].prio; + } + } + printk(KERN_WARNING + "irqthreadprios: %20s prio = %d (WARNING no match, default prio used)\n", + intname, MAX_USER_RT_PRIO / 2); + + return MAX_USER_RT_PRIO / 2; +} +EXPORT_SYMBOL(find_irq_prio); + +static int parse_irqthreadprios(char *in_str) +{ + static char strbuf[CONFIG_IRQ_THREAD_PRIOS_PARAM_SIZE]; + char *str; + + if (strlen(in_str) > sizeof(strbuf) - 1) { + printk(KERN_ERR "irqthreadprios: string too long: %d\n", + strlen(in_str)); + return 0; + } + //duplicate input string for later reference of partial key-strings + strlcpy(strbuf, in_str, sizeof(strbuf) - 1); + + for (str = strbuf; str;) { + int prio; + char *priop; + char *k = strchr(str, ','); + + if (k) + *k++ = 0; //terminate arg skip ',' to next arg + + //arg format: 'name:val' e.g. 'uartlite:22' + priop = strchr(str, ':'); + while(priop && priop[-1]=='\\') { //support escaped '\:' + priop = strchr(++priop, ':'); + } + if (priop) { //ignore bad formatted args + *priop++ = 0; //terminate name, skip to val + + if (irqthreadprios_num < + (sizeof(irqthreadprios_tab) / + sizeof(irqthreadprios_tab[0]))) { + kstrtoint(priop, 0, &prio); + irqthreadprios_tab[irqthreadprios_num].prio = + clamp(prio, 0, MAX_USER_RT_PRIO); + irqthreadprios_tab[irqthreadprios_num].pat = + str; + irqthreadprios_num++; + } else { + printk(KERN_ERR + "irqthreadprios: tab overflow %d\n", + irqthreadprios_num); + } + } + + str = k; //next arg + } + + return 0; +} + +//format uartlite:55,uio_scu3:56,*:20 +early_param("irqthreadprios", parse_irqthreadprios); + +#endif + + /** * synchronize_irq - wait for pending IRQ handlers (on other CPUs) * @irq: interrupt number to wait for @@ -1028,9 +1194,13 @@ __setup_irq(unsigned int irq, struct irq */ if (new->thread_fn && !nested) { struct task_struct *t; - static const struct sched_param param = { + struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO/2, }; +#ifdef CONFIG_IRQ_THREAD_PRIOS_PARAM + param.sched_priority = find_irq_prio(new->name); +#endif + t = kthread_create(irq_thread, new, "irq/%d-%s", irq, new->name); Index: linux-3.12.33-rt47-i386/include/linux/irq.h =================================================================== --- linux-3.12.33-rt47-i386.orig/include/linux/irq.h +++ linux-3.12.33-rt47-i386/include/linux/irq.h @@ -394,6 +394,10 @@ static inline void irq_move_irq(struct i static inline void irq_move_masked_irq(struct irq_data *data) { } #endif +#ifdef CONFIG_IRQ_THREAD_PRIOS_PARAM +extern int find_irq_prio(const char *intname); +#endif + extern int no_irq_affinity; #ifdef CONFIG_HARDIRQS_SW_RESEND Index: linux-3.12.33-rt47-i386/kernel/softirq.c =================================================================== --- linux-3.12.33-rt47-i386.orig/kernel/softirq.c +++ linux-3.12.33-rt47-i386/kernel/softirq.c @@ -696,7 +696,9 @@ static inline void _local_bh_enable_nort static inline void ksoftirqd_set_sched_params(unsigned int cpu) { struct sched_param param = { .sched_priority = 1 }; - +#ifdef CONFIG_IRQ_THREAD_PRIOS_PARAM + param.sched_priority = find_irq_prio(current->comm); +#endif sched_setscheduler(current, SCHED_FIFO, ¶m); /* Take over all pending softirqs when starting */ local_irq_disable();