aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/gpio-button-hotplug
Commit message (Collapse)AuthorAgeFilesLines
* gpio-button-hotplug: add volume button handlingChuanhong Guo2019-09-042-1/+3
| | | | | | | This is used by PISEN WMB001N. Signed-off-by: Chuanhong Guo <gch981213@gmail.com> (cherry picked from commit 11182349e1f31f873ebddd69d6b87dec638eaabf)
* gpio-button-hotplug: unify polled and interrupt codeDavid Bauer2019-07-191-65/+76
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This patch unifies the polled and interrupt-driven gpio_keys code paths as well implements consistent handling of the debounce interval set for the GPIO buttons and switches. Hotplug events will only be fired if 1. The input changes its state and remains stable for the duration of the debounce interval (default is 5 ms). 2. In the initial stable (no state-change for duration of the debounce interval) state once the driver module gets loaded. Switch type inputs will always report their stable state. Unpressed buttons will not trigger an event for the initial stable state. Whereas pressed buttons will trigger an event. This is consistent with upstream's gpio-key driver that uses the input subsystem (and dont use autorepeat). Prior to this patch, this was handled inconsistently for interrupt-based an polled gpio-keys. Hence this patch unifies the shared logic into the gpio_keys_handle_button() function and modify both implementations to handle the initial state properly. The changes described in 2. ) . can have an impact on the failsafe trigger. Up until now, the script checked for button state changes. On the down side, this allowed to trigger the failsafe by releasing a held button at the right time. On the plus side, the button's polarity setting didn't matter. Now, the failsafe will only engage when a button was pressed at the right moment (same as before), but now it can theoretically also trigger when the button was pressed the whole time the kernel booted and well into the fast-blinking preinit phase. However, the chances that this can happen are really small. This is because the gpio-button module is usually up and ready even before the preinit state is entered. So, the initial pressed button event gets lost and most devices behave as before. Bisectors: If this patch causes a device to permanently go into failsafe or experience weird behavior due to inputs, please check the following: - the GPIO polarity setting for the button - the software-debounce value Run-tested for 'gpio-keys' and 'gpio-keys-polled' on - devolo WiFi pro 1200e - devolo WiFi pro 1750c - devolo WiFi pro 1750x - Netgear WNDR4700 - Meraki MR24 - RT-AC58U Signed-off-by: David Bauer <mail@david-bauer.net> Signed-off-by: Christian Lamparter <chunkeey@gmail.com> [further cleanups, simplification and unification] (cherry picked from commit 27f3f493de0610c74de2ea406641b256bfcc13a9)
* gpio-button-hotplug: fix 4.19 build breakage on malta/be64Petr Štetiar2019-07-191-0/+1
| | | | | | | | | | | | | | While testing 4.19 build on malta/be64, I've encountered following error: gpio-button-hotplug/gpio-button-hotplug.c:529:18: error: implicit declaration of function 'gpio_to_desc' which is caused by the missing include fixed by this patch. Signed-off-by: Petr Štetiar <ynezz@true.cz> Signed-off-by: Christian Lamparter <chunkeey@gmail.com> (cherry picked from commit dd6d82112a10796dd5aa0f9e9c76ec8e77e7e211)
* gpio-button-hotplug: gpio-keys: fix always missing first eventPetr Štetiar2019-06-091-9/+2
| | | | | | | | | | | | | Commit afc056d7dc83 ("gpio-button-hotplug: support interrupt properties") changed the gpio-keys interrupt handling logic in a way, that it always misses first event, which causes issues with rc.button scripts, so this patch restores the previous behaviour. Fixes: afc056d7dc83 ("gpio-button-hotplug: support interrupt properties") Reported-by: Kristian Evensen <kristian.evensen@gmail.com> Tested-by: Kuan-Yi Li <kyli.tw@gmail.com> Signed-off-by: Petr Štetiar <ynezz@true.cz> Signed-off-by: Christian Lamparter <chunkeey@gmail.com> [drop state check]
* gpio-button-hotplug: fix wrong initial seen valuePetr Štetiar2019-06-091-0/+3
| | | | | | | | | | | | | | | Currently the generated event contains wrong seen value, when the button is pressed for the first time: rmmod gpio_button_hotplug; modprobe gpio_button_hotplug [ pressing the wps key immediately after modprobe ] gpio-keys: create event, name=wps, seen=1088, pressed=1 So this patch adds a check for this corner case and makes seen=0 if the button is pressed for the first time. Tested-by: Kuan-Yi Li <kyli.tw@gmail.com> Signed-off-by: Petr Štetiar <ynezz@true.cz>
* gpio-button-hotplug: use pr_debug and pr_errPetr Štetiar2019-06-091-17/+6
| | | | | | | pr_debug can be used with dynamic debugging. Tested-by: Kuan-Yi Li <kyli.tw@gmail.com> Signed-off-by: Petr Štetiar <ynezz@true.cz>
* gpio-button-hotplug: support interrupt propertiesChristian Lamparter2019-05-311-21/+93
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Upstream Linux's input gpio-keys driver supports specifying a external interrupt for a gpio via the 'interrupts' properties as well as having support for software debounce. This patch ports these features to OpenWrt's event version. Only the "pure" interrupt-driven support is left behind, since this goes a bit against the "gpio" in the "gpio-keys" and I don't have a real device to test this with. This patch also silences the generated warnings showing up since 4.14 due to the 'constification' of the struct gpio_keys_button *buttons variable in the upstream struct gpio_keys_platform_data declaration. gpio-button-hotplug.c: In function 'gpio_keys_get_devtree_pdata': gpio-button-hotplug.c:392:10: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers] button = &pdata->buttons[i++]; ^ gpio-button-hotplug.c: In function 'gpio_keys_button_probe': gpio-button-hotplug.c:537:12: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers] bdata->b = &pdata->buttons[i]; ^ gpio-button-hotplug.c: In function 'gpio_keys_probe': gpio-button-hotplug.c:563:37: warning: initialization discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers] struct gpio_keys_button *button = &pdata->buttons[i]; ^ Acked-by: Petr Štetiar <ynezz@true.cz> Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
* gpio-button-hotplug: add KEY_POWER2 handlingAlan Swanson2019-05-301-0/+1
| | | | | | | | | | | | | | | | For devices such as BTHOMEHUBV5A with both reset and restart buttons, its easily accessible restart button has been assigned to KEY_POWER power script to poweroff preventing accidental (or malicious) factory resets by KEY_RESTART reset script. However an easily accessible button immediately powering off the device is also undesirable. As KEY_RESTART is already used for reset script (and there's no KEY_REBOOT in Linux input events), use KEY_POWER2 for rebooting via new reboot script with 5 second seen delay. Fixes: FS#1965 Signed-off-by: Alan Swanson <reiver@improbability.net> Signed-off-by: Petr Štetiar <ynezz@true.cz> [long line wrap]
* build: use KERNEL_MAKE_FLAGS for kernel file compilationsKarl Vogel2017-10-291-2/+1
| | | | | | | The build system already defines KERNEL_CROSS which defaults to TARGET_CROSS. Make use of this variable for kernel makefiles. Signed-off-by: Karl Vogel <karl.vogel@gmail.com>
* gpio-button-hotplug: leave platform_device.dev.platform_data untouchedFurong Xu2017-08-211-2/+1
| | | | | | | | | | | | get platform_data from gpio_keys_button_dev.pdata, and fix a illegal pointer dereference like this: [ 51.143776] gpio-keys-polled gpio-keys-polled: missing poll_interval value [ 51.150852] gpio-keys-polled: probe of gpio-keys-polled failed with error -22 [ 828.159993] gpio-keys-polled gpio-keys-polled: no memory for button data [ 828.166821] gpio-keys-polled: probe of gpio-keys-polled failed with error -12 Signed-off-by: Furong Xu <xfr@outlook.com>
* treewide: add license tagsFlorian Eckert2017-06-241-0/+1
| | | | | | Add licence tags where missing. Signed-off-by: Florian Eckert <fe@dev.tdt.de>
* gpio-button-hotplug: add more buttonsMathias Kresin2016-11-271-15/+24
| | | | | | The keycodes are used by some boards. Signed-off-by: Mathias Kresin <dev@kresin.me>
* kernel/gpio-button-hotplug: drop Build/Prepare rule in favor of default oneAlexandru Ardelean2016-10-151-5/+0
| | | | Signed-off-by: Alexandru Ardelean <ardeleanalex@gmail.com>
* treewide: replace nbd@openwrt.org with nbd@nbd.nameFelix Fietkau2016-06-071-3/+3
| | | | Signed-off-by: Felix Fietkau <nbd@nbd.name>
* kernel: gpio-button-hotplug: Add missing ONESHOT flag to threaded IRQ requestJohn Crispin2016-03-032-2/+2
| | | | | | | | | | | | | | | | | | | | | | | | | Without the IRQF_ONESHOT flag in devm_request_threaded_irq() call I get following error: genirq: Threaded irq requested with handler=NULL and !ONESHOT for irq 56 gpio-keys gpio-keys: failed to request irq:56 for gpio:20 >From kernel/irq/manage.c: The interrupt was requested with handler = NULL, so we use the default primary handler for it. But it does not have the oneshot flag set. In combination with level interrupts this is deadly, because the default primary handler just wakes the thread, then the irq lines is reenabled, but the device still has the level irq asserted. Rinse and repeat.... While this works for edge type interrupts, we play it safe and reject unconditionally because we can't say for sure which type this interrupt really has. The type flags are unreliable as the underlying chip implementation can override them. Signed-off-by: Petr Štetiar <ynezz@true.cz> SVN-Revision: 48894
* kernel: gpio-button-hotplug: update to use threaded irq'sJohn Crispin2016-02-121-8/+5
| | | | | | | | | | | | Many gpio controllers 'cansleep' due to the fact that they are behind busses e.g. i2c etc. Using threaded irq's allows for 'sleep-able' gpio's to be used. Signed-off-by: Pushpal Sidhu <psidhu@gateworks.com> Signed-off-by: Tim Harvey <tharvey@gateworks.com> SVN-Revision: 48696
* gpio-button-hotplug: handle EPROBE_DEFER and other errorsHauke Mehrtens2015-07-261-5/+15
| | | | | | | | | | of_get_gpio_flags() could return an error like EPROBE_DEFER which was not handled before. This patch takes the code from gpio_keys_polled.c for error handling and also improves some other unrelated small parts. Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> SVN-Revision: 46502
* build: drop obsolete kernel version dependenciesFelix Fietkau2015-01-241-1/+0
| | | | | | Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 44110
* gpio-button-hotplug: remove #ifdef CONFIG_HOTPLUG, it is gone in newer ↵Felix Fietkau2014-05-231-7/+0
| | | | | | | | kernels (fixes #16413) Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 40838
* gpio-button-hotplug: fix (and extend) package descriptionHauke Mehrtens2014-05-141-2/+8
| | | | | | Signed-off-by: Rafał Miłecki <zajec5@gmail.com> SVN-Revision: 40765
* gpio-button-hotplug: don't build for 3.3 kernelsFlorian Fainelli2014-03-121-0/+1
| | | | | | | | | 3.3 kernels do not have the required changes which would make gpio-button-hotplug work, disallow building on those kernels for now. Signed-off-by: Florian Fainelli <florian@openwrt.org> SVN-Revision: 39903
* gpio-button-hotplug: add wwan buttonHauke Mehrtens2014-01-141-0/+1
| | | | | | | | | | | The wimax key will be used as a generic wwan key starting with Linux 3.13. The brcm47xx target uses this key for the 3g buttons. Also remove the ifdef around KEY_WPS_BUTTON, this is in the kernel for a long time now. Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> SVN-Revision: 39290
* gpio-button-hotplug: fix crash on removeJonas Gorski2013-12-171-1/+1
| | | | | | | | | | Don't call gpio_keys_remove recursively. Setting the platform data to NULL triggered an oops on the second iteration, so there was no infinate loop. Signed-off-by: Jonas Gorski <jogo@openwrt.org> SVN-Revision: 39124
* gpio-button-hotplug: add irq mode to driverJohn Crispin2013-12-091-94/+176
| | | | | | Signed-off-by: John Crispin <blogic@openwrt.org> SVN-Revision: 39021
* gpio-button-hotplug: add support for sliding switchesJohn Crispin2013-11-111-12/+8
| | | | | | Signed-off-by: John Crispin <blogic@openwrt.org> SVN-Revision: 38725
* gpio-button-hotplug: add support for power buttonsJohn Crispin2013-10-281-0/+1
| | | | | | Signed-off-by: John Crispin <blogic@openwrt.org> SVN-Revision: 38557
* gpio-button-hotplug: debounce the initial button state, the first reads at ↵Felix Fietkau2013-08-051-2/+4
| | | | | | | | boot time might be wrong Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 37702
* gpio-button-hotplug: cleanup, fix compiler warningFelix Fietkau2013-08-031-4/+2
| | | | | | Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 37665
* gpio-button-hotplug: fix active_low handling, possibly broken in r37643Felix Fietkau2013-08-031-8/+9
| | | | | | Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 37664
* gpio-button-hotplug: use gpio_button_get_value() to initialize last_state.John Crispin2013-08-011-1/+1
| | | | | | | | | | | TL-WR720N-v3 has a slider switch composed of 2 GPIO buttons which can be used to swtich between 3 positions. At leat 1 button is in pressed state in any of those positions. Initialize 'last_state' as 0 (released) will cause the device to automatically enter failsafe mode on every bootup. Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com> SVN-Revision: 37643
* gpio-button-hotplug: use gpio_button_get_value() to fetch state.John Crispin2013-08-011-4/+1
| | | | | | Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com> SVN-Revision: 37642
* gpio-button-hotplug: add inline function gpio_button_get_value().John Crispin2013-08-011-0/+9
| | | | | | Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com> SVN-Revision: 37641
* gpio-button-hotplug: add support for EV_SWLuka Perkov2013-07-021-7/+21
| | | | | | Signed-off-by: Luka Perkov <luka@openwrt.org> SVN-Revision: 37130
* gpio-button-hotplug: improve gpio button debouncing, verify state changes ↵Felix Fietkau2013-06-291-6/+8
| | | | | | | | over multiple polls. fixes spurious failsafe triggers (#13784) Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 37090
* packages: clean up the package folderJohn Crispin2013-06-213-0/+609
Signed-off-by: John Crispin <blogic@openwrt.org> SVN-Revision: 37007
an class="n">WAITQ(sdom->processor)); } else if ( domain_runnable(sdom) ) { list_for_each_entry ( i, RUNQ(sdom->processor), run_list ) { if ( (i->deadline > inf->deadline) || is_idle_task(i->owner) ) { __list_add(&inf->run_list, i->run_list.prev, &i->run_list); break; } } if ( &i->waitq == RUNQ(sdom->processor) ) list_add_tail(&inf->run_list, RUNQ(sdom->processor)); } /* silently ignore tasks in other states like BLOCKED, DYING, STOPPED, etc * - they shouldn't be on any queue */ } /** at_alloc_task - allocate private info for a task */ static int at_alloc_task(struct domain *p) { ASSERT(p != NULL); p->sched_priv = xmalloc(struct at_dom_info); if ( p->sched_priv == NULL ) return -1; return 0; } /* prepare a task to be added to scheduling */ static void at_add_task(struct domain *p) { s_time_t now = NOW(); ASSERT( p->sched_priv != NULL ); DOM_INFO(p)->owner = p; p->lastschd = now; /* DOM 0's parameters must be set here for it to boot the system! */ if(p->id == 0) { DOM_INFO(p)->remain = MILLISECS(15); DOM_INFO(p)->nat_period = DOM_INFO(p)->period = MILLISECS(20); DOM_INFO(p)->nat_slice = DOM_INFO(p)->slice = MILLISECS(15); DOM_INFO(p)->latency = MILLISECS(5); DOM_INFO(p)->xtratime = 1; DOM_INFO(p)->deadline = now; DOM_INFO(p)->prevddln = now; } else /* other domains run basically best effort unless otherwise set */ { DOM_INFO(p)->remain = 0; DOM_INFO(p)->nat_period = DOM_INFO(p)->period = SECONDS(10); DOM_INFO(p)->nat_slice = DOM_INFO(p)->slice = MILLISECS(10); DOM_INFO(p)->latency = SECONDS(10); DOM_INFO(p)->xtratime = 1; DOM_INFO(p)->deadline = now; // DOM_INFO(p)->deadline = now + SECONDS(10); DOM_INFO(p)->prevddln = 0; } INIT_LIST_HEAD(&(DOM_INFO(p)->run_list)); INIT_LIST_HEAD(&(DOM_INFO(p)->waitq)); } /** * dequeue - remove a domain from any queues it is on. * @sdom: the task to remove */ static void dequeue(struct domain *sdom) { struct at_dom_info *inf = DOM_INFO(sdom); ASSERT(sdom->id != IDLE_DOMAIN_ID); /* just delete it from all the queues! */ list_del(&inf->waitq); INIT_LIST_HEAD(&inf->waitq); if(__task_on_runqueue(sdom)) __del_from_runqueue(sdom); } /* * unblock * * This function deals with updating the sdom for a domain * which has just been unblocked. * * Xen's Atropos treats unblocking slightly differently to Nemesis: * * - "Short blocking" domains (i.e. that unblock before their deadline has * expired) are treated the same as in nemesis (put on the wait queue and * given preferential treatment in selecting domains for extra time). * * - "Long blocking" domains do not simply have their period truncated to their * unblocking latency as before but also have their slice recomputed to be the * same fraction of their new period. Each time the domain is scheduled, the * period and slice are doubled until they reach their original ("natural") * values, as set by the user (and stored in nat_period and nat_slice). The * idea is to give better response times to unblocking whilst preserving QoS * guarantees to other domains. */ static void unblock(struct domain *sdom) { s_time_t time = NOW(); struct at_dom_info *inf = DOM_INFO(sdom); dequeue(sdom); /* We distinguish two cases... short and long blocks */ if ( inf->deadline < time ) { /* Long blocking case */ /* The sdom has passed its deadline since it was blocked. Give it its new deadline based on the latency value. */ inf->prevddln = time; /* Scale the scheduling parameters as requested by the latency hint. */ inf->deadline = time + inf->latency; inf->slice = inf->nat_slice / ( inf->nat_period / inf->latency ); inf->period = inf->latency; inf->remain = inf->slice; } else { /* Short blocking case */ /* We leave REMAIN intact, but put this domain on the WAIT queue marked as recently unblocked. It will be given priority over other domains on the wait queue until while REMAIN>0 in a generous attempt to help it make up for its own foolishness. */ if(inf->remain > 0) inf->state = ATROPOS_TASK_UNBLOCKED; else inf->state = ATROPOS_TASK_WAIT; } requeue(sdom); } static int at_init_idle_task(struct domain *p) { if(at_alloc_task(p) < 0) return -1; at_add_task(p); dequeue(p); requeue(p); return 0; } static void block(struct domain* sdom) { DOM_INFO(sdom)->state = ATROPOS_TASK_BLOCKED; dequeue(sdom); requeue(sdom); } /** * ATROPOS - main scheduler function */ task_slice_t ksched_scheduler(s_time_t time) { struct domain *cur_sdom = current; /* Current sdom */ s_time_t newtime; s_time_t ranfor; /* How long the domain ran */ struct domain *sdom; /* tmp. scheduling domain */ int cpu = cur_sdom->processor; /* current CPU */ struct at_dom_info *cur_info; static unsigned long waitq_rrobin = 0; int i; task_slice_t ret; cur_info = DOM_INFO(cur_sdom); ASSERT( cur_sdom != NULL); /* If we were spinning in the idle loop, there is no current * domain to deschedule. */ if (is_idle_task(cur_sdom)) goto deschedule_done; /***************************** * * Deschedule the current scheduling domain * ****************************/ /* Record the time the domain was preempted and for how long it ran. Work out if the domain is going to be blocked to save some pointless queue shuffling */ cur_sdom->lastdeschd = time; ranfor = (time - cur_sdom->lastschd); dequeue(cur_sdom); if ( domain_runnable(cur_sdom) || (cur_info->state == ATROPOS_TASK_UNBLOCKED) ) { /* In this block, we are doing accounting for an sdom which has been running in contracted time. Note that this could now happen even if the domain is on the wait queue (i.e. if it blocked) */ /* Deduct guaranteed time from the domain */ cur_info->remain -= ranfor; /* If guaranteed time has run out... */ if ( cur_info->remain <= 0 ) { /* Move domain to correct position in WAIT queue */ /* XXX sdom_unblocked doesn't need this since it is already in the correct place. */ cur_info->state = ATROPOS_TASK_WAIT; } } requeue(cur_sdom); deschedule_done: /***************************** * * We have now successfully descheduled the current sdom. * The next task is the allocate CPU time to any sdom it is due to. * ****************************/ cur_sdom = NULL; /***************************** * * Allocate CPU time to any waiting domains who have passed their * period deadline. If necessary, move them to run queue. * ****************************/ while(!list_empty(WAITQ(cpu)) && DOM_INFO(sdom = waitq_el(WAITQ(cpu)->next))->deadline <= time ) { struct at_dom_info *inf = DOM_INFO(sdom); dequeue(sdom); if ( inf->period != inf->nat_period ) { /* This domain has had its parameters adjusted as a result of * unblocking and they need to be adjusted before requeuing it */ inf->slice *= 2; inf->period *= 2; if ( inf->period > inf->nat_period ) { inf->period = inf->nat_period; inf->slice = inf->nat_slice; } } /* Domain begins a new period and receives a slice of CPU * If this domain has been blocking then throw away the * rest of it's remain - it can't be trusted */ if (inf->remain > 0) inf->remain = inf->slice; else inf->remain += inf->slice; inf->prevddln = inf->deadline; inf->deadline += inf->period; if ( inf->remain <= 0 ) inf->state = ATROPOS_TASK_WAIT; /* Place on the appropriate queue */ requeue(sdom); } /***************************** * * Next we need to pick an sdom to run. * If anything is actually 'runnable', we run that. * If nothing is, we pick a waiting sdom to run optimistically. * If there aren't even any of those, we have to spin waiting for an * event or a suitable time condition to happen. * ****************************/ /* we guarantee there's always something on the runqueue */ cur_info = list_entry(RUNQ(cpu)->next, struct at_dom_info, run_list); cur_sdom = cur_info->owner; newtime = time + cur_info->remain; /* MAW - the idle domain is always on the run queue. We run from the * runqueue if it's NOT the idle domain or if there's nothing on the wait * queue */ if (cur_sdom->id == IDLE_DOMAIN_ID && !list_empty(WAITQ(cpu))) { struct at_dom_info *inf; /* Try running a domain on the WAIT queue - this part of the scheduler isn't particularly efficient but then again, we don't have any guaranteed domains to worry about. */ /* See if there are any unblocked domains on the WAIT queue who we can give preferential treatment to. */ list_for_each_entry ( inf, WAITQ(cpu), waitq ) { sdom = inf->owner; if (inf->state == ATROPOS_TASK_UNBLOCKED) { cur_sdom = sdom; cur_info = inf; newtime = time + inf->remain; goto found; } } /* init values needed to approximate round-robin for slack time */ i = 0; if ( waitq_rrobin >= q_len(WAITQ(cpu))) waitq_rrobin = 0; /* Last chance: pick a domain on the wait queue with the XTRA flag set. The NEXT_OPTM field is used to cheaply achieve an approximation of round-robin order */ list_for_each_entry ( inf, WAITQ(cpu), waitq ) { sdom = inf->owner; if (inf->xtratime && i >= waitq_rrobin) { cur_sdom = sdom; cur_info = inf; newtime = time + BESTEFFORT_QUANTUM; waitq_rrobin = i + 1; /* set this value ready for next */ goto found; } i++; } } found: /********************** * * We now have to work out the time when we next need to * make a scheduling decision. We set the alarm timer * to cause an interrupt at that time. * **********************/ #define MIN(x,y) ( ( x < y ) ? x : y ) #define MAX(x,y) ( ( x > y ) ? x : y ) /* If we might be able to run a waiting domain before this one has */ /* exhausted its time, cut short the time allocation */ if (!list_empty(WAITQ(cpu))) { newtime = MIN(newtime, DOM_INFO(waitq_el(WAITQ(cpu)->next))->deadline); } /* don't allow pointlessly small time slices */ newtime = MAX(newtime, time + BESTEFFORT_QUANTUM); ret.task = cur_sdom; ret.time = newtime - time; TRACE_1D(0, cur_sdom->id); return ret; } /* set up some private data structures */ static int at_init_scheduler() { int i; for ( i = 0; i < NR_CPUS; i++ ) { schedule_data[i].sched_priv = xmalloc(sizeof(struct at_cpu_info)); if ( schedule_data[i].sched_priv == NULL ) return -1; INIT_LIST_HEAD(WAITQ(i)); INIT_LIST_HEAD(RUNQ(i)); } return 0; } /* print relevant per-domain info for a run queue dump */ static void at_dump_runq_el(struct domain *p) { printk("lastschd = %llu, xtratime = %d ", p->lastschd, DOM_INFO(p)->xtratime); } /* dump relevant per-cpu state for a run queue dump */ static void at_dump_cpu_state(int cpu) { struct list_head *queue; int loop = 0; struct at_dom_info *d_inf; struct domain *d; queue = RUNQ(cpu); printk("\nRUNQUEUE rq %lx n: %lx, p: %lx\n", (unsigned long)queue, (unsigned long) queue->next, (unsigned long) queue->prev); list_for_each_entry ( d_inf, queue, run_list ) { d = d_inf->owner; printk("%3d: %d has=%c ", loop++, d->id, test_bit(DF_RUNNING, &d->flags) ? 'T':'F'); at_dump_runq_el(d); printk("c=0x%X%08X\n", (u32)(d->cpu_time>>32), (u32)d->cpu_time); printk(" l: %lx n: %lx p: %lx\n", (unsigned long)&d_inf->run_list, (unsigned long)d_inf->run_list.next, (unsigned long)d_inf->run_list.prev); } queue = WAITQ(cpu); printk("\nWAITQUEUE rq %lx n: %lx, p: %lx\n", (unsigned long)queue, (unsigned long) queue->next, (unsigned long) queue->prev); list_for_each_entry ( d_inf, queue, waitq ) { d = d_inf->owner; printk("%3d: %d has=%c ", loop++, d->id, test_bit(DF_RUNNING, &d->flags) ? 'T':'F'); at_dump_runq_el(d); printk("c=0x%X%08X\n", (u32)(d->cpu_time>>32), (u32)d->cpu_time); printk(" l: %lx n: %lx p: %lx\n", (unsigned long)&d_inf->waitq, (unsigned long)d_inf->waitq.next, (unsigned long)d_inf->waitq.prev); } } /* set or fetch domain scheduling parameters */ static int at_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { if ( cmd->direction == SCHED_INFO_PUT ) { /* sanity checking! */ if( cmd->u.atropos.latency > cmd->u.atropos.nat_period || cmd->u.atropos.latency == 0 || cmd->u.atropos.nat_slice > cmd->u.atropos.nat_period ) return -EINVAL; DOM_INFO(p)->nat_period = cmd->u.atropos.nat_period; DOM_INFO(p)->nat_slice = cmd->u.atropos.nat_slice; DOM_INFO(p)->latency = cmd->u.atropos.latency; DOM_INFO(p)->xtratime = !!cmd->u.atropos.xtratime; } else if ( cmd->direction == SCHED_INFO_GET ) { cmd->u.atropos.nat_period = DOM_INFO(p)->nat_period; cmd->u.atropos.nat_slice = DOM_INFO(p)->nat_slice; cmd->u.atropos.latency = DOM_INFO(p)->latency; cmd->u.atropos.xtratime = DOM_INFO(p)->xtratime; } return 0; } /* free memory associated with a task */ static void at_free_task(struct domain *p) { xfree( DOM_INFO(p) ); } /* print decoded domain private state value (if known) */ static int at_prn_state(int state) { int ret = 0; switch(state) { case ATROPOS_TASK_UNBLOCKED: printk("Unblocked"); break; case ATROPOS_TASK_WAIT: printk("Wait"); break; default: ret = -1; } return ret; } struct scheduler sched_atropos_def = { .name = "Atropos Soft Real Time Scheduler", .opt_name = "atropos", .sched_id = SCHED_ATROPOS, .init_scheduler = at_init_scheduler, .init_idle_task = at_init_idle_task, .alloc_task = at_alloc_task, .add_task = at_add_task, .free_task = at_free_task, .wake = unblock, .sleep = block, .do_schedule = ksched_scheduler, .adjdom = at_adjdom, .dump_cpu_state = at_dump_cpu_state, .prn_state = at_prn_state, }; /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil */