From 990e73cba7fc82ed9990f90899214769cd6257d1 Mon Sep 17 00:00:00 2001 From: "sd386@font.cl.cam.ac.uk" Date: Mon, 17 Jan 2005 13:38:54 +0000 Subject: [PATCH 01/54] bitkeeper revision 1.1159.221.1 (41ebbfeezjfpGp20MD6f6Xl2r6Wd3Q) Added new simple EDF scheduler --- .rootkeys | 2 + tools/libxc/Makefile | 1 + tools/libxc/xc.h | 8 + tools/libxc/xc_sedf.c | 45 ++ tools/python/xen/lowlevel/xc/xc.c | 64 +++ tools/python/xen/xend/XendClient.py | 6 + tools/python/xen/xend/XendDomain.py | 18 + tools/python/xen/xend/server/SrvDomain.py | 8 + tools/python/xen/xm/main.py | 17 + xen/common/sched_sedf.c | 505 ++++++++++++++++++++++ xen/common/schedule.c | 4 +- xen/include/public/sched_ctl.h | 10 + 12 files changed, 687 insertions(+), 1 deletion(-) create mode 100644 tools/libxc/xc_sedf.c create mode 100644 xen/common/sched_sedf.c diff --git a/.rootkeys b/.rootkeys index 1691f867c4..7b301acebb 100644 --- a/.rootkeys +++ b/.rootkeys @@ -336,6 +336,7 @@ 3fbba6dctWRWlFJkYb6hdix2X4WMuw tools/libxc/xc_private.c 3fbba6dcbVrG2hPzEzwdeV_UC8kydQ tools/libxc/xc_private.h 40589968UQFnJeOMn8UIFLbXBuwXjw tools/libxc/xc_rrobin.c +41ebbfe9U0b0kI-HgjK7VEY4EvW7_w tools/libxc/xc_sedf.c 40e1b09dMYB4ItGCqcMIzirdMd9I-w tools/libxutil/Makefile 40e033325Sjqs-_4TuzeUEprP_gYFg tools/libxutil/allocate.c 40e03332KYz7o1bn2MG_KPbBlyoIMA tools/libxutil/allocate.h @@ -715,6 +716,7 @@ 4064773cJ31vZt-zhbSoxqft1Jaw0w xen/common/sched_atropos.c 40589968dD2D1aejwSOvrROg7fOvGQ xen/common/sched_bvt.c 40589968be_t_n0-w6ggceW7h-sx0w xen/common/sched_rrobin.c +41ebbfe9oF1BF3cH5v7yE3eOL9uPbA xen/common/sched_sedf.c 3e397e6619PgAfBbw2XFbXkewvUWgw xen/common/schedule.c 3ddb79bdB9RNMnkQnUyZ5C9hhMSQQw xen/common/slab.c 3ddb79bd0gVQYmL2zvuJnldvD0AGxQ xen/common/softirq.c diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile index 78ba7f3bf3..87c8c337ad 100644 --- a/tools/libxc/Makefile +++ b/tools/libxc/Makefile @@ -12,6 +12,7 @@ vpath %c $(XEN_LIBXUTIL) INCLUDES += -I $(XEN_LIBXUTIL) SRCS := +SRCS += xc_sedf.c SRCS += xc_atropos.c SRCS += xc_bvtsched.c SRCS += xc_domain.c diff --git a/tools/libxc/xc.h b/tools/libxc/xc.h index 7778b71673..badfbb375d 100644 --- a/tools/libxc/xc.h +++ b/tools/libxc/xc.h @@ -132,6 +132,14 @@ int xc_rrobin_global_set(int xc_handle, u64 slice); int xc_rrobin_global_get(int xc_handle, u64 *slice); +int xc_sedf_domain_set(int xc_handle, + u32 domid, + u64 period, u64 slice); + +int xc_sedf_domain_get(int xc_handle, + u32 domid, + u64* period, u64 *slice); + typedef evtchn_status_t xc_evtchn_status_t; int xc_evtchn_alloc_unbound(int xc_handle, u32 dom, diff --git a/tools/libxc/xc_sedf.c b/tools/libxc/xc_sedf.c new file mode 100644 index 0000000000..92c052fe23 --- /dev/null +++ b/tools/libxc/xc_sedf.c @@ -0,0 +1,45 @@ +/****************************************************************************** + * xc_sedf.c + * + * API for manipulating parameters of the Simple EDF scheduler. + * + * changes by Stephan Diestelhorst + * based on code + * by Mark Williamson, Copyright (c) 2004 Intel Research Cambridge. + */ + +#include "xc_private.h" + +int xc_sedf_domain_set(int xc_handle, + u32 domid, u64 period, u64 slice) +{ + dom0_op_t op; + struct sedf_adjdom *p = &op.u.adjustdom.u.sedf; + + op.cmd = DOM0_ADJUSTDOM; + op.u.adjustdom.domain = (domid_t)domid; + op.u.adjustdom.sched_id = SCHED_SEDF; + op.u.adjustdom.direction = SCHED_INFO_PUT; + + p->period = period; + p->slice = slice; + return do_dom0_op(xc_handle, &op); +} + +int xc_sedf_domain_get(int xc_handle, u32 domid, u64 *period, u64 *slice) +{ + dom0_op_t op; + int ret; + struct sedf_adjdom *p = &op.u.adjustdom.u.sedf; + + op.cmd = DOM0_ADJUSTDOM; + op.u.adjustdom.domain = (domid_t)domid; + op.u.adjustdom.sched_id = SCHED_SEDF; + op.u.adjustdom.direction = SCHED_INFO_GET; + + ret = do_dom0_op(xc_handle, &op); + + *period = p->period; + *slice = p->slice; + return ret; +} diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index 2dd8680b4f..55fabf9683 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -758,6 +758,50 @@ static PyObject *pyxc_rrobin_global_set(PyObject *self, return zero; } +static PyObject *pyxc_sedf_domain_set(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u32 domid; + u64 period, slice; + + static char *kwd_list[] = { "dom", "period", "slice", NULL }; + + if( !PyArg_ParseTupleAndKeywords(args, kwds, "iLL", kwd_list, &domid, + &period, &slice) ) + return NULL; + + if ( xc_sedf_domain_set(xc->xc_handle, domid, period, slice) != 0 ) + return PyErr_SetFromErrno(xc_error); + + Py_INCREF(zero); + return zero; +} + +static PyObject *pyxc_sedf_domain_get(PyObject *self, + PyObject *args, + PyObject *kwds) +{ + XcObject *xc = (XcObject *)self; + u32 domid; + u64 period, slice; + + static char *kwd_list[] = { "dom", NULL }; + + if( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &domid) ) + return NULL; + + if ( xc_sedf_domain_get( xc->xc_handle, domid, &period, + &slice) ) + return PyErr_SetFromErrno(xc_error); + + return Py_BuildValue("{s:i,s:L,s:L}", + "domain", domid, + "period", period, + "slice", slice); +} + static PyObject *pyxc_shadow_control(PyObject *self, PyObject *args, PyObject *kwds) @@ -984,6 +1028,26 @@ static PyMethodDef pyxc_methods[] = { "Get Round Robin scheduler settings\n" "Returns [dict]:\n" " slice [long]: Scheduler time slice.\n" }, + + { "sedf_domain_set", + (PyCFunction)pyxc_sedf_domain_set, + METH_KEYWORDS, "\n" + "Set the scheduling parameters for a domain when running with Atropos.\n" + " dom [int]: domain to set\n" + " period [long]: domain's scheduling period\n" + " slice [long]: domain's slice per period\n" + "Returns: [int] 0 on success; -1 on error.\n" }, + + { "sedf_domain_get", + (PyCFunction)pyxc_sedf_domain_get, + METH_KEYWORDS, "\n" + "Get the current scheduling parameters for a domain when running with\n" + "the Atropos scheduler." + " dom [int]: domain to query\n" + "Returns: [dict]\n" + " domain [int]: domain ID\n" + " period [long]: scheduler period\n" + " slice [long]: CPU reservation per period\n"}, { "evtchn_alloc_unbound", (PyCFunction)pyxc_evtchn_alloc_unbound, diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py index 8290165412..0d5ac106f2 100644 --- a/tools/python/xen/xend/XendClient.py +++ b/tools/python/xen/xend/XendClient.py @@ -272,6 +272,12 @@ class Xend: 'latency' : latency, 'xtratime': xtratime }) + def xend_domain_cpu_sedf_set(self, id, period, slice): + return self.xendPost(self.domainurl(id), + {'op' : 'cpu_sedf_set', + 'period' : period, + 'slice' : slice }) + def xend_domain_maxmem_set(self, id, memory): return self.xendPost(self.domainurl(id), { 'op' : 'maxmem_set', diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index fc53b4de03..fc5fba1efe 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -659,6 +659,24 @@ class XendDomain: return xc.atropos_domain_get(dominfo.dom) except Exception, ex: raise XendError(str(ex)) + + def domain_cpu_sedf_set(self, id, period, slice): + """Set Atropos scheduler parameters for a domain. + """ + dominfo = self.domain_lookup(id) + try: + return xc.sedf_domain_set(dominfo.dom, period, slice) + except Exception, ex: + raise XendError(str(ex)) + + def domain_cpu_sedf_get(self, id): + """Get Atropos scheduler parameters for a domain. + """ + dominfo = self.domain_lookup(id) + try: + return xc.sedf_domain_get(dominfo.dom) + except Exception, ex: + raise XendError(str(ex)) def domain_device_create(self, id, devconfig): """Create a new device for a domain. diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index c06b260ce1..46868f859c 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -132,6 +132,14 @@ class SrvDomain(SrvDir): ['xtratime', 'int']]) val = fn(req.args, {'dom': self.dom.id}) return val + + def op_cpu_sedf_set(self, op, req): + fn = FormFn(self.xd.domain_cpu_sedf_set, + [['dom', 'str'], + ['period', 'int'], + ['slice', 'int']]) + val = fn(req.args, {'dom': self.dom.id}) + return val def op_maxmem_set(self, op, req): fn = FormFn(self.xd.domain_maxmem_set, diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index e7454e507a..845e475a9c 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -587,6 +587,23 @@ class ProgRrobin(Prog): xm.prog(ProgRrobin) +class ProgSedf(Prog): + group = 'scheduler' + name= "sedf" + info = """Set simple EDF parameters.""" + + def help(self, args): + print args[0], "DOM PERIOD SLICE" + print "\nSet simple EDF parameters." + + def main(self, args): + if len(args) != 4: self.err("%s: Invalid argument(s)" % args[0]) + dom = args[1] + v = map(int, args[2:4]) + server.xend_domain_cpu_sedf_set(dom, *v) + +xm.prog(ProgSedf) + class ProgInfo(Prog): group = 'host' name = "info" diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c new file mode 100644 index 0000000000..a85e112970 --- /dev/null +++ b/xen/common/sched_sedf.c @@ -0,0 +1,505 @@ +/**************************************************************************** + * Simple EDF scheduler for xen + * + * by Stephan Diestelhorst (C) 2004 Cambridge University + * based on code by Mark Williamson (C) 2004 Intel Research Cambridge + */ + +#include +#include +#include +#include +#include +#include +#include + +#define SEDFLEVEL 0 +#define PRINT(_f, _a...) \ +if ((_f)<=SEDFLEVEL) printk(_a ); + +/* + TODO: + TESTING! + implement stylish features! + tracing instead of PRINTs +*/ + + +#define TRC_SEDF 0xBEEF0000 + +struct sedf_dom_info +{ + struct domain *owner; + struct list_head list; + + //Parameters for EDF + s_time_t period; //=(relative deadline) + s_time_t slice; //=worst case execution time + int extratime; + //Bookkeeping + s_time_t absdead; + s_time_t sched_start; + s_time_t cputime; + s_time_t absblock; + //Statistics + s_time_t block_time_tot; + s_time_t penalty_time_tot; + +}; + +struct sedf_cpu_info { + struct list_head runnableq; + struct list_head waitq; +}; + +#define DOM_INFO(d) ((struct sedf_dom_info *)((d)->sched_priv)) +#define CPU_INFO(cpu) ((struct sedf_cpu_info *)schedule_data[cpu].sched_priv) +#define LIST(d) (&DOM_INFO(d)->list) +#define RUNQ(cpu) (&CPU_INFO(cpu)->runnableq) +#define WAITQ(cpu) (&CPU_INFO(cpu)->waitq) +#define IDLETASK(cpu) ((struct domain *)schedule_data[cpu].idle) + +static xmem_cache_t *dom_info_cache; + +/*static inline void __add_to_runqueue_head(struct domain *d) +{ + list_add(RUNLIST(d), RUNQUEUE(d->processor)); +} + +static inline void __add_to_runqueue_tail(struct domain *d) +{ + list_add_tail(RUNLIST(d), RUNQUEUE(d->processor)); +}*/ + +static inline void __del_from_queue(struct domain *d) +{ + struct list_head *list = LIST(d); + list_del(list); + list->next = NULL; +} + +/* adds a domain to the queue of processes which wait for the beginning of the next period + * this list is therefore sortet by this time, which is simply absol. deadline - period + */ +static inline void __add_to_waitqueue_sort(struct domain *d) { + struct list_head *cur; + struct sedf_dom_info *curinf; + + PRINT(3,"Adding domain %i (bop= %llu) to waitq\n",d->id,DOM_INFO(d)->absdead - DOM_INFO(d)->period); + //iterate through all elements to find our "hole" + list_for_each(cur,WAITQ(d->processor)){ + curinf = list_entry(cur,struct sedf_dom_info,list); + if ( DOM_INFO(d)->absdead - DOM_INFO(d)->period < curinf->absdead - curinf->period) + break; + else + PRINT(4,"\tbehind domain %i (bop= %llu)\n",curinf->owner->id,curinf->absdead - curinf->period); + } + //cur now contains the element, before which we'll enqueue + PRINT(3,"\tlist_add to %x\n",cur->prev); + list_add(LIST(d),cur->prev); + +} + +/* adds a domain to the queue of processes which have started their current period and are + * runnable (i.e. not blocked, dieing,...). The first element on this list is running on the processor, + * if the list is empty the idle task will run. As we are implementing EDF, this list is sorted by + * deadlines. + */ +static inline void __add_to_runqueue_sort(struct domain *d) { + struct list_head *cur; + struct sedf_dom_info *curinf; + + PRINT(3,"Adding domain %i (deadl= %llu) to runq\n",d->id,DOM_INFO(d)->absdead); + //iterate through all elements to find our "hole" + list_for_each(cur,RUNQ(d->processor)){ + curinf = list_entry(cur,struct sedf_dom_info,list); + if (DOM_INFO(d)->absdead < curinf->absdead) + break; + else + PRINT(4,"\tbehind domain %i (deadl= %llu)\n",curinf->owner->id,curinf->absdead); + } + //cur now contains the element, before which we'll enqueue + PRINT(3,"\tlist_add to %x\n",cur->prev); + list_add(LIST(d),cur->prev); + +} +static inline int __task_on_queue(struct domain *d) { + return (((LIST(d))->next != NULL) && (LIST(d)->next != LIST(d))); +} + +/* Initialises the queues and creates the domain info cache */ +static int sedf_init_scheduler() { + int i; + PRINT(2,"sedf_init_scheduler was called\n"); + + for ( i = 0; i < NR_CPUS; i++ ) { + schedule_data[i].sched_priv = xmalloc(sizeof(struct sedf_cpu_info)); + if ( schedule_data[i].sched_priv == NULL ) + return -1; + INIT_LIST_HEAD(WAITQ(i)); + INIT_LIST_HEAD(RUNQ(i)); + } + + dom_info_cache = xmem_cache_create( + "SEDF dom info", sizeof(struct sedf_dom_info), 0, 0, 0, NULL); + if ( dom_info_cache == NULL ) + { + printk("Could not allocate SLAB cache.\n"); + return -1; + } + + return 0; +} + +/* Allocates memory for per domain private scheduling data*/ +static int sedf_alloc_task(struct domain *d) { + PRINT(2,"sedf_alloc_task was called, domain-id %i\n",d->id); + if ( (d->sched_priv = xmem_cache_alloc(dom_info_cache)) == NULL ) + return -1; + memset(d->sched_priv, 0, sizeof(struct sedf_dom_info)); + return 0; +} + +/* Setup the sedf_dom_info */ +static void sedf_add_task(struct domain *d) +{ + //s_time_t now=NOW(); + struct sedf_dom_info *inf=DOM_INFO(d); + inf->owner = d; + + PRINT(2,"sedf_add_task was called, domain-id %i\n",d->id); + if (d->id==0) { + //set dom0 to something useful to boot the machine + inf->period = MILLISECS(20); + inf->slice = MILLISECS(15); + inf->absdead= 0; + } + else { + //other domains don't get any execution time at all in the beginning! + inf->period = MILLISECS(20); + inf->slice = 0; + inf->absdead= 0; + } + INIT_LIST_HEAD(&(inf->list)); +} + +/* Frees memory used by domain info */ +static void sedf_free_task(struct domain *d) +{ + PRINT(2,"sedf_free_task was called, domain-id %i\n",d->id); + ASSERT(d->sched_priv != NULL); + xmem_cache_free(dom_info_cache, d->sched_priv); +} + +/* Initialises idle task */ +static int sedf_init_idle_task(struct domain *d) { + PRINT(2,"sedf_init_idle_task was called, domain-id %i\n",d->id); + if ( sedf_alloc_task(d) < 0 ) + return -1; + + sedf_add_task(d); + DOM_INFO(d)->absdead=0; + set_bit(DF_RUNNING, &d->flags); + //the idle task doesn't have to turn up on any list... + return 0; +} + +#define MIN(x,y) (((x)<(y))?(x):(y)) +/* Main scheduling function + * Reasons for calling this function are: + * -timeslice for the current period used up + * -domain on waitqueue has started it's period*/ +static task_slice_t sedf_do_schedule(s_time_t now) +{ + struct sedf_dom_info *inf = DOM_INFO(current); + int cpu = current->processor; + struct list_head *runq = RUNQ(cpu); + struct list_head *waitq = WAITQ(cpu); + struct list_head *cur,*tmp; + struct sedf_dom_info *curinf; + task_slice_t ret; + + //first of all update the domains cputime + inf->cputime += now - inf->sched_start; + + //scheduling decisions, which don't involve the running domain + if (is_idle_task(inf->owner)) + goto check_waitq; //idle task doesn't get scheduled on the runq + if (!((inf->cputime >= inf->slice) || !domain_runnable(inf->owner))) + goto check_waitq; //nothing to do with the running task + + //remove tasks that can't run + __del_from_queue(inf->owner); + + //manage bookkeeping + if (inf->cputime >= inf->slice) { + inf->absdead += inf->period; + inf->cputime -= inf->slice; + if (inf->cputime<0) inf->cputime = 0; + } + if (inf->absdeadid,now,inf->absdead); + //add a runnable domain to the waitqueue + if (domain_runnable(inf->owner)) + __add_to_waitqueue_sort(inf->owner); + else + inf->absblock=now; + +check_waitq: + //check for the first elements of the waitqueue, whether their next period has already started + list_for_each_safe(cur,tmp,waitq) { + curinf = list_entry(cur,struct sedf_dom_info,list); + if (curinf->absdead - curinf->period<=now) { + __del_from_queue(curinf->owner); + __add_to_runqueue_sort(curinf->owner); + } + else + break; + } + + //process the runq + list_for_each_safe(cur,tmp,runq) { + curinf = list_entry(cur,struct sedf_dom_info,list); + if (unlikely(curinf->slice == 0)) { + //special treatment of elements with empty slice + __del_from_queue(curinf->owner); + curinf->absdead += curinf->period; + __add_to_waitqueue_sort(curinf->owner); + } + else + if (unlikely((curinf->absdead < now) || (curinf->cputime > curinf->slice))) { + //we missed the deadline or the slice was already finished... might hapen because of dom_adj. + //printk("Ouch! Domain %i missed deadline %llu\n",curinf->owner->id,curinf->absdead); + __del_from_queue(curinf->owner); + curinf->absdead += ((now - curinf->absdead) / curinf->period + 1) * curinf->period; + //force start of period to be in future! + //curinf->absdead += curinf->period; + curinf->cputime = 0; + __add_to_runqueue_sort(curinf->owner); + } + else + break; + } + + //now simply pick the first domain from the runqueue + struct sedf_dom_info *runinf, *waitinf; + + if (!list_empty(runq)) { + runinf = list_entry(runq->next,struct sedf_dom_info,list); + ret.task = runinf->owner; + if (!list_empty(waitq)) { + //rerun scheduler, when scheduled domain reaches it's end of slice or the first domain from the waitqueue gets ready + waitinf = list_entry(waitq->next,struct sedf_dom_info,list); + ret.time = MIN(now + runinf->slice - runinf->cputime,waitinf->absdead - waitinf->period) - now; + } + else { + ret.time = runinf->slice - runinf->cputime; + } + } + else { + //we have an empty runqueue => let the idle domain run and start the scheduler, when the next task becomes available + ret.task = IDLETASK(cpu); + if (!list_empty(waitq)) { + waitinf = list_entry(waitq->next,struct sedf_dom_info,list); + ret.time = (waitinf->absdead - waitinf->period) - now; + } + else { + //this could porbably never happen, but one never knows... + //it can... imagine a second CPU, which is pure scifi ATM, but one never knows ;) + ret.time=SECONDS(1); + } + } + if (ret.time<0) + printk("Ouch! We are seriously BEHIND schedule! %lli\n",ret.time); + DOM_INFO(ret.task)->sched_start=now; + return ret; +} + +static void sedf_sleep(struct domain *d) { + PRINT(2,"sedf_sleep was called, domain-id %i\n",d->id); + if ( test_bit(DF_RUNNING, &d->flags) ) + cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ); + else if ( __task_on_queue(d) ) + __del_from_queue(d); +} + +/* This function wakes ifup a domain, i.e. moves them into the waitqueue + * things to mention are: admission control is taking place nowhere at + * the moment, so we can't be sure, whether it is safe to wake the domain + * up at all. Anyway, even if it is safe (total cpu usage <=100%) there are + * some considerations on when to allow the domain to wake up and have it's + * first deadline... + * I detected 3 cases, which could describe the possible behaviour of the scheduler, + * and I'll try to make them more clear: + * + * 1. Very conservative + * -when a blocked domain unblocks, it is allowed to start execution at + * the beginning of the next complete period + * (D..deadline, R..running, B..blocking/sleeping, U..unblocking/waking up + * + * DRRB_____D__U_____DRRRRR___D________ ... + * + * -this causes the domain to miss a period (and a deadlline) + * -doesn't disturb the schedule at all + * -deadlines keep occuring isochronous + * + * 2. Conservative Part 1 + * -when a domain unblocks in the same period as it was blocked it unblocks and + * may consume the rest of it's original time-slice minus the time it was blocked + * (assume period=9, slice=5) + * + * DRB_UR___DRRRRR___D... + * + * -this also doesn't disturb scheduling, but might lead to the fact, that the domain + * can't finish it's workload in the period + * + * Part 2a + * -it is obvious that such behaviour, applied when then unblocking is happening in + * later domains,tinyvnc works fine aswell + * + * DRB______D___UR___D... + * + * Part 2b + * -if one needs the full slice in the next period, it is necessary to treat the unblocking + * time as the start of the new period, i.e. move the deadline further back (later) + * -this doesn't disturb scheduling as well, because for EDF periods can be treated as minimal + * inter-release times and scheduling stays correct, when deadlines are kept relative to the time + * the process unblocks + * + * DRB______D___URRRR___D... + * (D) + * -problem: deadlines don't occur isochronous anymore + * + * 3. Unconservative (i.e. incorrect) + * -to boost the performance of I/O dependent domains it would be possible to put the domain into + * the runnable queue immediately, and let it run for the remainder of the slice of the current period + * (or even worse: allocate a new full slice for the domain) (and probably tweaking the deadline/slice even more) + * -either behaviour can lead to missed deadlines in other domains as opposed to approaches 1,2a,2b + */ +void sedf_wake(struct domain *d) { + //for the first try just implement the "very conservative" way of waking domains up + s_time_t now = NOW(); + struct sedf_dom_info* inf = DOM_INFO(d); + + PRINT(3,"sedf_wake was called, domain-id %i\n",d->id); + + if (unlikely(is_idle_task(d))) + return; + + if ( unlikely(__task_on_queue(d)) ) { + PRINT(3,"\tdomain %i is already in some queue\n",d->id); + return; + } + + //very conservative way of unblocking + //make sure that the start of the period for this + //domain is happening in the future + PRINT(3,"waking up domain %i (deadl= %llu period= %llu now= %llu)\n",d->id,inf->absdead,inf->period,now); + inf->absdead += ((now - inf->absdead) / inf->period+1)*inf->period; + PRINT(3,"waking up domain %i (deadl= %llu period= %llu now= %llu)\n",d->id,inf->absdead,inf->period,now); + + __add_to_waitqueue_sort(d); + PRINT(3,"added to waitq\n"); + + //TODO: Implement more fancy unblocking schemes! + /*if (now < inf->absdead) { + //short blocking + } + else { + //long blocking + }*/ + + //do some statistics here... + if (inf->absblock!=0) { + inf->block_time_tot += now - inf->absblock; + inf->penalty_time_tot += (inf->absdead - inf-> period) - inf->absblock; + /*if (DOM_INFO(d)->block_time_tot) + PRINT(3,"penalty: %lu\n",(DOM_INFO(d)->penalty_time_tot*100)/DOM_INFO(d)->block_time_tot);*/ + } + /*if ( is_idle_task(schedule_data[d->processor].curr)) { + cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ); + return; + }*/ + + //check whether the awakened task needs to get scheduled before the next sched. decision + if (inf->absdead - inf->period < schedule_data[d->processor].s_timer.expires) + cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ); +} + + +/* This could probably be a bit more specific!*/ +static void sedf_dump_domain(struct domain *d) { + printk("%u has=%c ", d->id, + test_bit(DF_RUNNING, &d->flags) ? 'T':'F'); + printk("c=%llu p=%llu sl=%llu ddl=%llu", d->cpu_time,DOM_INFO(d)->period,DOM_INFO(d)->slice,DOM_INFO(d)->absdead); + if (DOM_INFO(d)->block_time_tot!=0) + printf(" penalty: %lu",(DOM_INFO(d)->penalty_time_tot*100)/DOM_INFO(d)->block_time_tot); + printf("\n"); +} + +static void sedf_dump_cpu_state(int i) +{ + struct list_head *list, *queue; + int loop = 0; + struct sedf_dom_info *d_inf; + + printk("now=%llu\n",NOW()); + queue = RUNQ(i); + printk("RUNQ rq %lx n: %lx, p: %lx\n", (unsigned long)queue, + (unsigned long) queue->next, (unsigned long) queue->prev); + list_for_each ( list, queue ) + { + printk("%3d: ",loop++); + d_inf = list_entry(list, struct sedf_dom_info, list); + sedf_dump_domain(d_inf->owner); + } + + queue = WAITQ(i); + printk("\nWAITQ rq %lx n: %lx, p: %lx\n", (unsigned long)queue, + (unsigned long) queue->next, (unsigned long) queue->prev); + list_for_each ( list, queue ) + { + printk("%3d: ",loop++); + d_inf = list_entry(list, struct sedf_dom_info, list); + sedf_dump_domain(d_inf->owner); + } + +} + +/* set or fetch domain scheduling parameters */ +static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { + PRINT(2,"sedf_adjdom was called, domain-id %i new period %llu new slice %llu\n",p->id,cmd->u.sedf.period,cmd->u.sedf.slice); + if ( cmd->direction == SCHED_INFO_PUT ) + { + /* sanity checking! */ + if(cmd->u.sedf.slice > cmd->u.sedf.period ) + return -EINVAL; + + DOM_INFO(p)->period = cmd->u.sedf.period; + DOM_INFO(p)->slice = cmd->u.sedf.slice; + } + else if ( cmd->direction == SCHED_INFO_GET ) + { + cmd->u.sedf.period = DOM_INFO(p)->period; + cmd->u.sedf.slice = DOM_INFO(p)->slice; + } + PRINT(2,"sedf_adjdom_finished\n"); + return 0; +} + +struct scheduler sched_sedf_def = { + .name = "Simple EDF Scheduler", + .opt_name = "sedf", + .sched_id = SCHED_SEDF, + + .init_idle_task = sedf_init_idle_task, + .alloc_task = sedf_alloc_task, + .add_task = sedf_add_task, + .free_task = sedf_free_task, + .init_scheduler = sedf_init_scheduler, + .do_schedule = sedf_do_schedule, + .dump_cpu_state = sedf_dump_cpu_state, + .sleep = sedf_sleep, + .wake = sedf_wake, + .adjdom = sedf_adjdom, +}; diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 4aceef7d2a..27e87cd0f5 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -68,10 +68,12 @@ schedule_data_t schedule_data[NR_CPUS]; extern struct scheduler sched_bvt_def; extern struct scheduler sched_rrobin_def; extern struct scheduler sched_atropos_def; +extern struct scheduler sched_sedf_def; static struct scheduler *schedulers[] = { &sched_bvt_def, &sched_rrobin_def, &sched_atropos_def, + &sched_sedf_def, NULL }; @@ -285,7 +287,7 @@ long sched_adjdom(struct sched_adjdom_cmd *cmd) if ( cmd->sched_id != ops.sched_id ) return -EINVAL; - + if ( cmd->direction != SCHED_INFO_PUT && cmd->direction != SCHED_INFO_GET ) return -EINVAL; diff --git a/xen/include/public/sched_ctl.h b/xen/include/public/sched_ctl.h index bd6a717521..f2b9722a4d 100644 --- a/xen/include/public/sched_ctl.h +++ b/xen/include/public/sched_ctl.h @@ -11,6 +11,7 @@ #define SCHED_BVT 0 #define SCHED_ATROPOS 2 #define SCHED_RROBIN 3 +#define SCHED_SEDF 4 /* these describe the intended direction used for a scheduler control or domain * command */ @@ -64,6 +65,15 @@ struct sched_adjdom_cmd u64 latency; /* 32 */ u32 xtratime; /* 36 */ } PACKED atropos; + + struct sedf_adjdom + { + u64 period; /* 16 */ + u64 slice; /* 24 */ + u64 dummy1; /* 32 */ + u32 dummy2; /* 36 */ + } PACKED sedf; + } PACKED u; } PACKED; /* 40 bytes */ From b1cbe136f63e49928273d8cde72accbf1b65a9d2 Mon Sep 17 00:00:00 2001 From: "sd386@font.cl.cam.ac.uk" Date: Fri, 28 Jan 2005 11:51:45 +0000 Subject: [PATCH 02/54] bitkeeper revision 1.1159.170.102 (41fa2751heRkQ76AYa9Oe-6cOyJuLw) Enhanced SEDF scheduler --- tools/libxc/xc.h | 4 +- tools/libxc/xc_sedf.c | 18 +- tools/python/xen/lowlevel/xc/xc.c | 50 ++- tools/python/xen/xend/XendClient.py | 11 +- tools/python/xen/xend/XendDomain.py | 8 +- tools/python/xen/xend/server/SrvDomain.py | 5 +- tools/python/xen/xm/main.py | 10 +- xen/common/sched_sedf.c | 492 +++++++++++++++++----- xen/include/public/sched_ctl.h | 5 +- 9 files changed, 445 insertions(+), 158 deletions(-) diff --git a/tools/libxc/xc.h b/tools/libxc/xc.h index 159e71fb45..24e35bda39 100644 --- a/tools/libxc/xc.h +++ b/tools/libxc/xc.h @@ -243,11 +243,11 @@ int xc_rrobin_global_get(int xc_handle, u64 *slice); int xc_sedf_domain_set(int xc_handle, u32 domid, - u64 period, u64 slice); + u64 period, u64 slice, u64 latency, u16 extratime, u16 weight); int xc_sedf_domain_get(int xc_handle, u32 domid, - u64* period, u64 *slice); + u64* period, u64 *slice, u64 *latency, u16 *extratime, u16* weight); typedef evtchn_status_t xc_evtchn_status_t; diff --git a/tools/libxc/xc_sedf.c b/tools/libxc/xc_sedf.c index 92c052fe23..a3a0598a7d 100644 --- a/tools/libxc/xc_sedf.c +++ b/tools/libxc/xc_sedf.c @@ -11,7 +11,7 @@ #include "xc_private.h" int xc_sedf_domain_set(int xc_handle, - u32 domid, u64 period, u64 slice) + u32 domid, u64 period, u64 slice,u64 latency, u16 extratime,u16 weight) { dom0_op_t op; struct sedf_adjdom *p = &op.u.adjustdom.u.sedf; @@ -21,12 +21,15 @@ int xc_sedf_domain_set(int xc_handle, op.u.adjustdom.sched_id = SCHED_SEDF; op.u.adjustdom.direction = SCHED_INFO_PUT; - p->period = period; - p->slice = slice; + p->period = period; + p->slice = slice; + p->latency = latency; + p->extratime = extratime; + p->weight = weight; return do_dom0_op(xc_handle, &op); } -int xc_sedf_domain_get(int xc_handle, u32 domid, u64 *period, u64 *slice) +int xc_sedf_domain_get(int xc_handle, u32 domid, u64 *period, u64 *slice, u64* latency, u16* extratime, u16* weight) { dom0_op_t op; int ret; @@ -39,7 +42,10 @@ int xc_sedf_domain_get(int xc_handle, u32 domid, u64 *period, u64 *slice) ret = do_dom0_op(xc_handle, &op); - *period = p->period; - *slice = p->slice; + *period = p->period; + *slice = p->slice; + *latency = p->latency; + *extratime = p->extratime; + *weight = p->weight; return ret; } diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c index be28b6d945..e772494f5f 100644 --- a/tools/python/xen/lowlevel/xc/xc.c +++ b/tools/python/xen/lowlevel/xc/xc.c @@ -791,15 +791,14 @@ static PyObject *pyxc_sedf_domain_set(PyObject *self, { XcObject *xc = (XcObject *)self; u32 domid; - u64 period, slice; + u64 period, slice, latency; + u16 extratime, weight; + static char *kwd_list[] = { "dom", "period", "slice", "latency", "extratime", "weight",NULL }; - static char *kwd_list[] = { "dom", "period", "slice", NULL }; - - if( !PyArg_ParseTupleAndKeywords(args, kwds, "iLL", kwd_list, &domid, - &period, &slice) ) + if( !PyArg_ParseTupleAndKeywords(args, kwds, "iLLLhh", kwd_list, &domid, + &period, &slice, &latency, &extratime, &weight) ) return NULL; - - if ( xc_sedf_domain_set(xc->xc_handle, domid, period, slice) != 0 ) + if ( xc_sedf_domain_set(xc->xc_handle, domid, period, slice, latency, extratime,weight) != 0 ) return PyErr_SetFromErrno(xc_error); Py_INCREF(zero); @@ -812,21 +811,24 @@ static PyObject *pyxc_sedf_domain_get(PyObject *self, { XcObject *xc = (XcObject *)self; u32 domid; - u64 period, slice; - + u64 period, slice,latency; + u16 weight, extratime; + static char *kwd_list[] = { "dom", NULL }; if( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &domid) ) return NULL; if ( xc_sedf_domain_get( xc->xc_handle, domid, &period, - &slice) ) + &slice,&latency,&extratime,&weight) ) return PyErr_SetFromErrno(xc_error); - return Py_BuildValue("{s:i,s:L,s:L}", - "domain", domid, - "period", period, - "slice", slice); + return Py_BuildValue("{s:i,s:L,s:L,s:L,s:i}", + "domain", domid, + "period", period, + "slice", slice, + "latency", latency, + "extratime", extratime); } static PyObject *pyxc_shadow_control(PyObject *self, @@ -1068,9 +1070,11 @@ static PyMethodDef pyxc_methods[] = { (PyCFunction)pyxc_sedf_domain_set, METH_KEYWORDS, "\n" "Set the scheduling parameters for a domain when running with Atropos.\n" - " dom [int]: domain to set\n" - " period [long]: domain's scheduling period\n" - " slice [long]: domain's slice per period\n" + " dom [int]: domain to set\n" + " period [long]: domain's scheduling period\n" + " slice [long]: domain's slice per period\n" + " latency [long]: domain's wakeup latency hint\n" + " extratime [int]: domain aware of extratime?\n" "Returns: [int] 0 on success; -1 on error.\n" }, { "sedf_domain_get", @@ -1078,11 +1082,13 @@ static PyMethodDef pyxc_methods[] = { METH_KEYWORDS, "\n" "Get the current scheduling parameters for a domain when running with\n" "the Atropos scheduler." - " dom [int]: domain to query\n" - "Returns: [dict]\n" - " domain [int]: domain ID\n" - " period [long]: scheduler period\n" - " slice [long]: CPU reservation per period\n"}, + " dom [int]: domain to query\n" + "Returns: [dict]\n" + " domain [int]: domain ID\n" + " period [long]: scheduler period\n" + " slice [long]: CPU reservation per period\n" + " latency [long]: domain's wakeup latency hint\n" + " extratime [int]: domain aware of extratime?\n"}, { "evtchn_alloc_unbound", (PyCFunction)pyxc_evtchn_alloc_unbound, diff --git a/tools/python/xen/xend/XendClient.py b/tools/python/xen/xend/XendClient.py index af6cc68971..fc14e307b0 100644 --- a/tools/python/xen/xend/XendClient.py +++ b/tools/python/xen/xend/XendClient.py @@ -273,11 +273,14 @@ class Xend: 'latency' : latency, 'xtratime': xtratime }) - def xend_domain_cpu_sedf_set(self, id, period, slice): + def xend_domain_cpu_sedf_set(self, id, period, slice, latency, extratime, weight): return self.xendPost(self.domainurl(id), - {'op' : 'cpu_sedf_set', - 'period' : period, - 'slice' : slice }) + {'op' : 'cpu_sedf_set', + 'period' : period, + 'slice' : slice, + 'latency' : latency, + 'extratime' : extratime, + 'weight' : weight }) def xend_domain_maxmem_set(self, id, memory): return self.xendPost(self.domainurl(id), diff --git a/tools/python/xen/xend/XendDomain.py b/tools/python/xen/xend/XendDomain.py index f280bc5786..2d46562660 100644 --- a/tools/python/xen/xend/XendDomain.py +++ b/tools/python/xen/xend/XendDomain.py @@ -660,12 +660,12 @@ class XendDomain: except Exception, ex: raise XendError(str(ex)) - def domain_cpu_sedf_set(self, id, period, slice): - """Set Atropos scheduler parameters for a domain. + def domain_cpu_sedf_set(self, id, period, slice, latency, extratime, weight): + """Set Simple EDF scheduler parameters for a domain. """ - dominfo = self.domain_lookup(id) + dominfo = self.domain_lookup(id) try: - return xc.sedf_domain_set(dominfo.dom, period, slice) + return xc.sedf_domain_set(dominfo.dom, period, slice, latency, extratime, weight) except Exception, ex: raise XendError(str(ex)) diff --git a/tools/python/xen/xend/server/SrvDomain.py b/tools/python/xen/xend/server/SrvDomain.py index ced4f1f83a..50664bfab6 100644 --- a/tools/python/xen/xend/server/SrvDomain.py +++ b/tools/python/xen/xend/server/SrvDomain.py @@ -138,7 +138,10 @@ class SrvDomain(SrvDir): fn = FormFn(self.xd.domain_cpu_sedf_set, [['dom', 'str'], ['period', 'int'], - ['slice', 'int']]) + ['slice', 'int'], + ['latency', 'int'], + ['extratime', 'int'], + ['weight', 'int']]) val = fn(req.args, {'dom': self.dom.id}) return val diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 42a79bac56..11b7617c03 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -606,14 +606,14 @@ class ProgSedf(Prog): info = """Set simple EDF parameters.""" def help(self, args): - print args[0], "DOM PERIOD SLICE" + print args[0], "DOM PERIOD SLICE LATENCY EXTRATIME WEIGHT" print "\nSet simple EDF parameters." def main(self, args): - if len(args) != 4: self.err("%s: Invalid argument(s)" % args[0]) - dom = args[1] - v = map(int, args[2:4]) - server.xend_domain_cpu_sedf_set(dom, *v) + if len(args) != 7: self.err("%s: Invalid argument(s)" % args[0]) + dom = args[1] + v = map(int, args[2:7]) + server.xend_domain_cpu_sedf_set(dom, *v) xm.prog(ProgSedf) diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c index a85e112970..3c2913965d 100644 --- a/xen/common/sched_sedf.c +++ b/xen/common/sched_sedf.c @@ -13,7 +13,7 @@ #include #include -#define SEDFLEVEL 0 +#define SEDFLEVEL 2 #define PRINT(_f, _a...) \ if ((_f)<=SEDFLEVEL) printk(_a ); @@ -26,50 +26,104 @@ if ((_f)<=SEDFLEVEL) printk(_a ); #define TRC_SEDF 0xBEEF0000 +#define EXTRA_NONE (0) +#define EXTRA_AWARE (1) +#define EXTRA_RUNNING (2) +#define EXTRA_QUANTUM (MICROSECS(1000)) +#define WEIGHT_PERIOD (MILLISECS(100)) +#define WEIGHT_SAFETY (MILLISECS(5)) struct sedf_dom_info { struct domain *owner; struct list_head list; + struct list_head extralist; //Parameters for EDF s_time_t period; //=(relative deadline) s_time_t slice; //=worst case execution time - int extratime; + + //Advaced Parameters + //Latency Scaling + s_time_t period_orig; + s_time_t slice_orig; + s_time_t latency; + //extra-time status of domain + short extra; + //weights for "Scheduling for Beginners/ Lazy/ etc." + short weight; + //Bookkeeping s_time_t absdead; s_time_t sched_start; s_time_t cputime; s_time_t absblock; + //Statistics s_time_t block_time_tot; s_time_t penalty_time_tot; - + s_time_t extra_time_tot; + int block_tot; + int short_block_tot; + int long_block_tot; + int short_cont; }; struct sedf_cpu_info { struct list_head runnableq; struct list_head waitq; + struct list_head extraq; }; -#define DOM_INFO(d) ((struct sedf_dom_info *)((d)->sched_priv)) -#define CPU_INFO(cpu) ((struct sedf_cpu_info *)schedule_data[cpu].sched_priv) -#define LIST(d) (&DOM_INFO(d)->list) -#define RUNQ(cpu) (&CPU_INFO(cpu)->runnableq) -#define WAITQ(cpu) (&CPU_INFO(cpu)->waitq) -#define IDLETASK(cpu) ((struct domain *)schedule_data[cpu].idle) +#define DOM_INFO(d) ((struct sedf_dom_info *)((d)->sched_priv)) +#define CPU_INFO(cpu) ((struct sedf_cpu_info *)schedule_data[cpu].sched_priv) +#define LIST(d) (&DOM_INFO(d)->list) +#define EXTRALIST(d) (&DOM_INFO(d)->extralist) +#define RUNQ(cpu) (&CPU_INFO(cpu)->runnableq) +#define WAITQ(cpu) (&CPU_INFO(cpu)->waitq) +#define EXTRAQ(cpu) (&CPU_INFO(cpu)->extraq) +#define IDLETASK(cpu) ((struct domain *)schedule_data[cpu].idle) + +#define PERIOD_BEGIN(inf) ((inf)->absdead - (inf)->period) static xmem_cache_t *dom_info_cache; -/*static inline void __add_to_runqueue_head(struct domain *d) +static inline void extraq_add_head(struct domain *d) { - list_add(RUNLIST(d), RUNQUEUE(d->processor)); + list_add(EXTRALIST(d), EXTRAQ(d->processor)); } -static inline void __add_to_runqueue_tail(struct domain *d) +static inline void extraq_add_tail(struct domain *d) { - list_add_tail(RUNLIST(d), RUNQUEUE(d->processor)); -}*/ + list_add_tail(EXTRALIST(d), EXTRAQ(d->processor)); +} + +static inline void extraq_del(struct domain *d) +{ + struct list_head *list = EXTRALIST(d); + list_del(list); + list->next = NULL; +} + +static inline int extraq_on(struct domain *d) { + return (((EXTRALIST(d))->next != NULL) && (EXTRALIST(d)->next != EXTRALIST(d))); +} + +static inline void extraq_check(struct domain *d) { + if (extraq_on(d)) { + PRINT(2,"Dom %i is on extraQ\n",d->id); + if (DOM_INFO(d)->extra == EXTRA_NONE) { + extraq_del(d); + PRINT(2,"Removed dom %i from extraQ\n",d->id); + } + } else { + PRINT(2,"Dom %i is NOT on extraQ\n",d->id); + if (DOM_INFO(d)->extra != EXTRA_NONE) { + PRINT(2,"Added dom %i to extraQ\n",d->id); + extraq_add_tail(d); + } + } +} static inline void __del_from_queue(struct domain *d) { @@ -85,14 +139,14 @@ static inline void __add_to_waitqueue_sort(struct domain *d) { struct list_head *cur; struct sedf_dom_info *curinf; - PRINT(3,"Adding domain %i (bop= %llu) to waitq\n",d->id,DOM_INFO(d)->absdead - DOM_INFO(d)->period); + PRINT(3,"Adding domain %i (bop= %llu) to waitq\n",d->id,PERIOD_BEGIN(DOM_INFO(d))); //iterate through all elements to find our "hole" list_for_each(cur,WAITQ(d->processor)){ curinf = list_entry(cur,struct sedf_dom_info,list); - if ( DOM_INFO(d)->absdead - DOM_INFO(d)->period < curinf->absdead - curinf->period) + if (PERIOD_BEGIN(DOM_INFO(d)) < PERIOD_BEGIN(curinf)) break; else - PRINT(4,"\tbehind domain %i (bop= %llu)\n",curinf->owner->id,curinf->absdead - curinf->period); + PRINT(4,"\tbehind domain %i (bop= %llu)\n",curinf->owner->id,PERIOD_BEGIN(curinf)); } //cur now contains the element, before which we'll enqueue PRINT(3,"\tlist_add to %x\n",cur->prev); @@ -136,10 +190,11 @@ static int sedf_init_scheduler() { schedule_data[i].sched_priv = xmalloc(sizeof(struct sedf_cpu_info)); if ( schedule_data[i].sched_priv == NULL ) return -1; - INIT_LIST_HEAD(WAITQ(i)); + INIT_LIST_HEAD(WAITQ(i));//used for Latency Scaling INIT_LIST_HEAD(RUNQ(i)); + INIT_LIST_HEAD(EXTRAQ(i)); } - + //we could not find any suitable domain => look for domains that are aware of extratime dom_info_cache = xmem_cache_create( "SEDF dom info", sizeof(struct sedf_dom_info), 0, 0, 0, NULL); if ( dom_info_cache == NULL ) @@ -170,17 +225,23 @@ static void sedf_add_task(struct domain *d) PRINT(2,"sedf_add_task was called, domain-id %i\n",d->id); if (d->id==0) { //set dom0 to something useful to boot the machine - inf->period = MILLISECS(20); - inf->slice = MILLISECS(15); - inf->absdead= 0; + inf->period = MILLISECS(20); + inf->slice = MILLISECS(15); + inf->latency = 0; + inf->absdead = 0; + inf->extra = EXTRA_NONE;//EXTRA_AWARE; } else { //other domains don't get any execution time at all in the beginning! - inf->period = MILLISECS(20); - inf->slice = 0; - inf->absdead= 0; + inf->period = MILLISECS(20); + inf->slice = 0; + inf->absdead = 0; + inf->latency = 0; + inf->extra = EXTRA_NONE;//EXTRA_AWARE } + inf->period_orig = inf->period; inf->slice_orig = inf->slice; INIT_LIST_HEAD(&(inf->list)); + INIT_LIST_HEAD(&(inf->extralist)); } /* Frees memory used by domain info */ @@ -208,48 +269,80 @@ static int sedf_init_idle_task(struct domain *d) { /* Main scheduling function * Reasons for calling this function are: * -timeslice for the current period used up - * -domain on waitqueue has started it's period*/ + * -domain on waitqueue has started it's period + * -and various others ;) in general: determin which domain to run next*/ static task_slice_t sedf_do_schedule(s_time_t now) { struct sedf_dom_info *inf = DOM_INFO(current); int cpu = current->processor; struct list_head *runq = RUNQ(cpu); struct list_head *waitq = WAITQ(cpu); + struct list_head *extraq = EXTRAQ(cpu); struct list_head *cur,*tmp; struct sedf_dom_info *curinf; task_slice_t ret; + - //first of all update the domains cputime - inf->cputime += now - inf->sched_start; - - //scheduling decisions, which don't involve the running domain + //idle tasks don't need any of the following stuf if (is_idle_task(inf->owner)) goto check_waitq; //idle task doesn't get scheduled on the runq - if (!((inf->cputime >= inf->slice) || !domain_runnable(inf->owner))) - goto check_waitq; //nothing to do with the running task - //remove tasks that can't run - __del_from_queue(inf->owner); + if (unlikely(inf->extra == EXTRA_RUNNING)) { + //special treatment of domains running in extra time + inf->extra = EXTRA_AWARE; + inf->cputime=0; + inf->extra_time_tot += now - inf->sched_start; - //manage bookkeeping - if (inf->cputime >= inf->slice) { - inf->absdead += inf->period; - inf->cputime -= inf->slice; - if (inf->cputime<0) inf->cputime = 0; + extraq_del(current); //remove extradomain from head of the queue + if (domain_runnable(inf->owner)) + extraq_add_tail(current); //and add to the tail if it is runnable => round-robin + else + __del_from_queue(inf->owner); //if domain blocked in extratime remove it from waitq(/runq) as well } - if (inf->absdeadid,now,inf->absdead); - //add a runnable domain to the waitqueue - if (domain_runnable(inf->owner)) - __add_to_waitqueue_sort(inf->owner); - else - inf->absblock=now; + else { + //current domain is running in real time mode + //update the domains cputime + inf->cputime += now - inf->sched_start; + //scheduling decisions, which don't move the running domain to any queues + if ((inf->cputime < inf->slice) && domain_runnable(inf->owner)) + goto check_waitq; //there is nothing to do with the running task + //remove tasks that can't run + __del_from_queue(inf->owner); + + //manage bookkeeping (i.e. calculate next deadline, memorize overun time of slice) of finished domains + if (inf->cputime >= inf->slice) { + inf->cputime -= inf->slice; + + if (inf->period < inf->period_orig) { + //this domain runs in latency scaling mode + inf->period *= 2; + inf->slice *= 2; + if ((inf->period > inf->period_orig) || (inf->slice > inf->slice_orig)) { + //now switch back to standard timing + inf->period = inf->period_orig; + inf->slice = inf->slice_orig; + } + } + inf->absdead += inf->period; //set next deadline + } + //if (inf->absdeadid,now,inf->absdead); + //add a runnable domain to the waitqueue + if (domain_runnable(inf->owner)) + __add_to_waitqueue_sort(inf->owner); + else { + //we have a blocked realtime task + inf->absblock=now; + if (inf->extra == EXTRA_AWARE) + extraq_del(inf->owner); //remove a blocked domain from the extraq aswell + } + } check_waitq: //check for the first elements of the waitqueue, whether their next period has already started list_for_each_safe(cur,tmp,waitq) { curinf = list_entry(cur,struct sedf_dom_info,list); - if (curinf->absdead - curinf->period<=now) { + if (PERIOD_BEGIN(curinf) <= now) { __del_from_queue(curinf->owner); __add_to_runqueue_sort(curinf->owner); } @@ -266,19 +359,19 @@ check_waitq: curinf->absdead += curinf->period; __add_to_waitqueue_sort(curinf->owner); } - else + else { if (unlikely((curinf->absdead < now) || (curinf->cputime > curinf->slice))) { //we missed the deadline or the slice was already finished... might hapen because of dom_adj. //printk("Ouch! Domain %i missed deadline %llu\n",curinf->owner->id,curinf->absdead); __del_from_queue(curinf->owner); - curinf->absdead += ((now - curinf->absdead) / curinf->period + 1) * curinf->period; - //force start of period to be in future! - //curinf->absdead += curinf->period; + curinf->absdead += ((now - curinf->absdead + (curinf->period-1)) / curinf->period) * curinf->period; + //force start of period to be in future and aligned to period borders! curinf->cputime = 0; __add_to_runqueue_sort(curinf->owner); } else break; + } } //now simply pick the first domain from the runqueue @@ -290,23 +383,33 @@ check_waitq: if (!list_empty(waitq)) { //rerun scheduler, when scheduled domain reaches it's end of slice or the first domain from the waitqueue gets ready waitinf = list_entry(waitq->next,struct sedf_dom_info,list); - ret.time = MIN(now + runinf->slice - runinf->cputime,waitinf->absdead - waitinf->period) - now; + ret.time = MIN(now + runinf->slice - runinf->cputime,PERIOD_BEGIN(waitinf)) - now; } else { ret.time = runinf->slice - runinf->cputime; } } else { - //we have an empty runqueue => let the idle domain run and start the scheduler, when the next task becomes available - ret.task = IDLETASK(cpu); if (!list_empty(waitq)) { - waitinf = list_entry(waitq->next,struct sedf_dom_info,list); - ret.time = (waitinf->absdead - waitinf->period) - now; + waitinf = list_entry(waitq->next,struct sedf_dom_info,list); + //we could not find any suitable domain => look for domains that are aware of extratime + if (!list_empty(extraq) && (PERIOD_BEGIN(waitinf) - now >= EXTRA_QUANTUM)) { + runinf = list_entry(extraq->next,struct sedf_dom_info,extralist); + runinf->extra = EXTRA_RUNNING; + ret.task = runinf->owner; + ret.time = EXTRA_QUANTUM; + } + else { + //we have an empty run- and extraqueue or too less time => idle task! + ret.task = IDLETASK(cpu); + ret.time = PERIOD_BEGIN(waitinf) - now; + } } else { - //this could porbably never happen, but one never knows... + //this could probably never happen, but one never knows... //it can... imagine a second CPU, which is pure scifi ATM, but one never knows ;) - ret.time=SECONDS(1); + ret.task = IDLETASK(cpu); + ret.time = SECONDS(1); } } if (ret.time<0) @@ -319,8 +422,12 @@ static void sedf_sleep(struct domain *d) { PRINT(2,"sedf_sleep was called, domain-id %i\n",d->id); if ( test_bit(DF_RUNNING, &d->flags) ) cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ); - else if ( __task_on_queue(d) ) - __del_from_queue(d); + else { + if ( __task_on_queue(d) ) + __del_from_queue(d); + if (extraq_on(d)) + extraq_del(d); + } } /* This function wakes ifup a domain, i.e. moves them into the waitqueue @@ -343,7 +450,7 @@ static void sedf_sleep(struct domain *d) { * -doesn't disturb the schedule at all * -deadlines keep occuring isochronous * - * 2. Conservative Part 1 + * 2. Conservative Part 1: Short Unblocking * -when a domain unblocks in the same period as it was blocked it unblocks and * may consume the rest of it's original time-slice minus the time it was blocked * (assume period=9, slice=5) @@ -352,10 +459,13 @@ static void sedf_sleep(struct domain *d) { * * -this also doesn't disturb scheduling, but might lead to the fact, that the domain * can't finish it's workload in the period + * -in addition to that the domain can be treated prioritised when extratime is available * + * Part2: Long Unblocking * Part 2a * -it is obvious that such behaviour, applied when then unblocking is happening in - * later domains,tinyvnc works fine aswell + * later periods, works fine aswell + * -the domain is treated as if it would have been running since the start of its new period * * DRB______D___UR___D... * @@ -369,13 +479,62 @@ static void sedf_sleep(struct domain *d) { * DRB______D___URRRR___D... * (D) * -problem: deadlines don't occur isochronous anymore + * Part 2c (Improved Atropos design) + * -when a domain unblocks it is given a very short period (=latency hint) and slice length scaled + * accordingly + * -both rise again to the original value (e.g. get doubled every period) * * 3. Unconservative (i.e. incorrect) * -to boost the performance of I/O dependent domains it would be possible to put the domain into * the runnable queue immediately, and let it run for the remainder of the slice of the current period - * (or even worse: allocate a new full slice for the domain) (and probably tweaking the deadline/slice even more) + * (or even worse: allocate a new full slice for the domain) * -either behaviour can lead to missed deadlines in other domains as opposed to approaches 1,2a,2b */ +static inline void unblock_short_vcons(struct sedf_dom_info* inf, s_time_t now) { inf->absdead += inf->period;} +static inline void unblock_long_vcons(struct sedf_dom_info* inf, s_time_t now) { + inf->absdead += ((now - inf->absdead) / inf->period + 1) * inf->period; //very conservative + inf->cputime = 0; +} + +static inline void unblock_short_cons(struct sedf_dom_info* inf, s_time_t now) { + inf->cputime += now - inf->absblock; //treat blocked time as consumed by the domain + if (inf->cputime + EXTRA_QUANTUM > inf->slice) { + //we don't have a reasonable amount of time in our slice left :( + inf->cputime=0; + inf->absdead += inf->period; //start in next period! + } + else + inf->short_cont++; +} +static inline void unblock_long_cons_a(struct sedf_dom_info* inf, s_time_t now) { + inf->cputime = (now - inf->absdead) % inf->period; //treat the time the domain was blocked in the CURRENT + //period as consumed by the domain + if (inf->cputime + EXTRA_QUANTUM > inf->slice) { + //we don't have a reasonable amount of time in our slice left :( + inf->cputime=0; + inf->absdead += inf->period; //start in next period! + } +} +static inline void unblock_long_cons_b(struct sedf_dom_info* inf,s_time_t now) { + inf->absdead = now + inf->period; //Conservative 2b + inf->cputime = 0; +} +static inline void unblock_long_cons_c(struct sedf_dom_info* inf,s_time_t now) { + if (likely(inf->latency)) { + //sclae the slice and period accordingly to the latency hint + inf->period = inf->latency; //reduce period temporarily to the latency hint + ASSERT((inf->latency < ULONG_MAX) && (inf->slice_orig < ULONG_MAX)); //this results in max. 4s slice/period length + inf->slice = (inf->latency * inf->slice_orig) / inf->period_orig; //scale slice accordingly, so that utilisation stays the same + } + else { + //we don't have a latency hint.. use some other technique + inf->absdead = now + inf->period; //Conservative 2b... + inf->cputime = 0; + } +} + +/*static inline void unblock_short_vcons +static inline void unblock_short_vcons*/ void sedf_wake(struct domain *d) { //for the first try just implement the "very conservative" way of waking domains up s_time_t now = NOW(); @@ -390,29 +549,52 @@ void sedf_wake(struct domain *d) { PRINT(3,"\tdomain %i is already in some queue\n",d->id); return; } - + if ( unlikely(extraq_on(d)) ) { + PRINT(3,"\tdomain %i is already in the extraQ\n",d->id); + } + if (unlikely(inf->absdead == 0)) + inf->absdead = now + inf->slice; //initial setup of the deadline + //very conservative way of unblocking //make sure that the start of the period for this //domain is happening in the future PRINT(3,"waking up domain %i (deadl= %llu period= %llu now= %llu)\n",d->id,inf->absdead,inf->period,now); - inf->absdead += ((now - inf->absdead) / inf->period+1)*inf->period; - PRINT(3,"waking up domain %i (deadl= %llu period= %llu now= %llu)\n",d->id,inf->absdead,inf->period,now); + inf->block_tot++; + if (unlikely(now< PERIOD_BEGIN(inf))) { + //this might happen, imagine unblocking in extra-time! + if (likely(inf->extra == EXTRA_AWARE)) + extraq_add_tail(d); //SD: Could extraq_add_head be better? + //else + //This is very very unlikely, ie. might even be an error?! + } + else { + if (now < inf->absdead) { + //short blocking + inf->short_block_tot++; + //unblock_short_vcons(inf, now); + unblock_short_cons(inf, now); + if (inf->extra == EXTRA_AWARE) + extraq_add_head(d); + } + else { + //long blocking + inf->long_block_tot++; + //PRINT(3,"old=%llu ",inf->absdead); + //unblock_long_vcons(inf, now); + unblock_long_cons_c(inf,now); + if (inf->extra == EXTRA_AWARE) + extraq_add_tail(d); + } + } + PRINT(3,"waking up domain %i (deadl= %llu period= %llu now= %llu)\n",d->id,inf->absdead,inf->period,now); __add_to_waitqueue_sort(d); PRINT(3,"added to waitq\n"); - //TODO: Implement more fancy unblocking schemes! - /*if (now < inf->absdead) { - //short blocking - } - else { - //long blocking - }*/ - //do some statistics here... if (inf->absblock!=0) { inf->block_time_tot += now - inf->absblock; - inf->penalty_time_tot += (inf->absdead - inf-> period) - inf->absblock; + inf->penalty_time_tot += PERIOD_BEGIN(inf) + inf->cputime - inf->absblock; /*if (DOM_INFO(d)->block_time_tot) PRINT(3,"penalty: %lu\n",(DOM_INFO(d)->penalty_time_tot*100)/DOM_INFO(d)->block_time_tot);*/ } @@ -422,7 +604,10 @@ void sedf_wake(struct domain *d) { }*/ //check whether the awakened task needs to get scheduled before the next sched. decision - if (inf->absdead - inf->period < schedule_data[d->processor].s_timer.expires) + //and check, whether we are idling and this domain is extratime aware + if ((PERIOD_BEGIN(inf) < schedule_data[d->processor].s_timer.expires) || + (is_idle_task(schedule_data[d->processor].curr) && (now + EXTRA_QUANTUM < schedule_data[d->processor].s_timer.expires) && + (inf->extra == EXTRA_AWARE))) cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ); } @@ -431,57 +616,140 @@ void sedf_wake(struct domain *d) { static void sedf_dump_domain(struct domain *d) { printk("%u has=%c ", d->id, test_bit(DF_RUNNING, &d->flags) ? 'T':'F'); - printk("c=%llu p=%llu sl=%llu ddl=%llu", d->cpu_time,DOM_INFO(d)->period,DOM_INFO(d)->slice,DOM_INFO(d)->absdead); + printk("p=%llu sl=%llu ddl=%llu w=%u c=%llu xtr(%s)=%llu", + DOM_INFO(d)->period, DOM_INFO(d)->slice, DOM_INFO(d)->absdead, DOM_INFO(d)->weight, d->cpu_time, + DOM_INFO(d)->extra ? "yes" : "no", DOM_INFO(d)->extra_time_tot); + if (d->cpu_time !=0) + printf(" (%lu%)", (DOM_INFO(d)->extra_time_tot * 100) / d->cpu_time); if (DOM_INFO(d)->block_time_tot!=0) - printf(" penalty: %lu",(DOM_INFO(d)->penalty_time_tot*100)/DOM_INFO(d)->block_time_tot); + printf(" pen=%lu%", (DOM_INFO(d)->penalty_time_tot * 100) / DOM_INFO(d)->block_time_tot); + if (DOM_INFO(d)->block_tot!=0) + printf("\n blks=%lu sh=%lu (%lu%) (shc=%lu (%lu%)) l=%lu (%lu%) avg: b=%llu p=%llu", DOM_INFO(d)->block_tot, + DOM_INFO(d)->short_block_tot, (DOM_INFO(d)->short_block_tot * 100) / DOM_INFO(d)->block_tot, + DOM_INFO(d)->short_cont, (DOM_INFO(d)->short_cont * 100) / DOM_INFO(d)->block_tot, + DOM_INFO(d)->long_block_tot, (DOM_INFO(d)->long_block_tot * 100) / DOM_INFO(d)->block_tot, + (DOM_INFO(d)->block_time_tot) / DOM_INFO(d)->block_tot, + (DOM_INFO(d)->penalty_time_tot) / DOM_INFO(d)->block_tot); printf("\n"); } static void sedf_dump_cpu_state(int i) { - struct list_head *list, *queue; - int loop = 0; - struct sedf_dom_info *d_inf; - - printk("now=%llu\n",NOW()); - queue = RUNQ(i); - printk("RUNQ rq %lx n: %lx, p: %lx\n", (unsigned long)queue, - (unsigned long) queue->next, (unsigned long) queue->prev); - list_for_each ( list, queue ) - { - printk("%3d: ",loop++); - d_inf = list_entry(list, struct sedf_dom_info, list); - sedf_dump_domain(d_inf->owner); - } - - queue = WAITQ(i); - printk("\nWAITQ rq %lx n: %lx, p: %lx\n", (unsigned long)queue, - (unsigned long) queue->next, (unsigned long) queue->prev); - list_for_each ( list, queue ) - { - printk("%3d: ",loop++); - d_inf = list_entry(list, struct sedf_dom_info, list); - sedf_dump_domain(d_inf->owner); - } - + struct list_head *list, *queue, *tmp; + int loop = 0; +/* int found = 0; + int id1st = 0;*/ + struct sedf_dom_info *d_inf; + struct domain* d; + + printk("now=%llu\n",NOW()); + queue = RUNQ(i); + printk("RUNQ rq %lx n: %lx, p: %lx\n", (unsigned long)queue, + (unsigned long) queue->next, (unsigned long) queue->prev); + list_for_each_safe ( list, tmp, queue ) + { + printk("%3d: ",loop++); + d_inf = list_entry(list, struct sedf_dom_info, list); + sedf_dump_domain(d_inf->owner); + } + + queue = WAITQ(i); loop = 0; + printk("\nWAITQ rq %lx n: %lx, p: %lx\n", (unsigned long)queue, + (unsigned long) queue->next, (unsigned long) queue->prev); + list_for_each_safe ( list, tmp, queue ) + { + printk("%3d: ",loop++); + d_inf = list_entry(list, struct sedf_dom_info, list); + sedf_dump_domain(d_inf->owner); + } + + queue = EXTRAQ(i); loop = 0; + printk("\nEXTRAQ rq %lx n: %lx, p: %lx\n", (unsigned long)queue, + (unsigned long) queue->next, (unsigned long) queue->prev); + list_for_each_safe ( list, tmp, queue ) + { + d_inf = list_entry(list, struct sedf_dom_info, extralist); + +/* if (found) { + if (id1st == d_inf->owner->id) + break; + } + else { id1st=d_inf->owner->id; found=1;}*/ + printk("%3d: ",loop++); + sedf_dump_domain(d_inf->owner); + } + + loop = 0; + printk("\nnot on Q\n"); + for_each_domain(d) { + if (!extraq_on(d) && !__task_on_queue(d)) { + printk("%3d: ",loop++); + sedf_dump_domain(d); + } + } +} +//Adjusts periods and slices of the domains accordingly to their weights +static inline int sedf_adjust_weights(struct domain *p, struct sched_adjdom_cmd *cmd) { + int sumw = 0; + s_time_t sumt = 0; + + //sum up all weights + for_each_domain(p) { + if (DOM_INFO(p)->weight) + sumw += DOM_INFO(p)->weight; + else { + //don't modify domains who don't have a weight, but sum up + //the time they need, projected to a WEIGHT_PERIOD, so that + //this time is not given to the weight-driven domains + ASSERT((WEIGHT_PERIOD < ULONG_MAX) && (DOM_INFO(p)->slice_orig < ULONG_MAX)); //this results in max. 4s slice/period length + sumt += (WEIGHT_PERIOD * DOM_INFO(p)->slice_orig) / DOM_INFO(p)->period_orig; + } + } + //adjust all slices (and periods) to the new weight + for_each_domain(p) { + if (DOM_INFO(p)->weight) { + DOM_INFO(p)->period_orig = + DOM_INFO(p)->period = WEIGHT_PERIOD; + DOM_INFO(p)->slice_orig = + DOM_INFO(p)->slice = (DOM_INFO(p)->weight * (WEIGHT_PERIOD - WEIGHT_SAFETY - sumt)) / sumw; + } + } + return 0; } /* set or fetch domain scheduling parameters */ static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { - PRINT(2,"sedf_adjdom was called, domain-id %i new period %llu new slice %llu\n",p->id,cmd->u.sedf.period,cmd->u.sedf.slice); + PRINT(2,"sedf_adjdom was called, domain-id %i new period %llu new slice %llu\n" + "latency %llu extra: %s\n",p->id,cmd->u.sedf.period,cmd->u.sedf.slice,cmd->u.sedf.latency,(cmd->u.sedf.extratime)?"yes":"no"); if ( cmd->direction == SCHED_INFO_PUT ) { - /* sanity checking! */ - if(cmd->u.sedf.slice > cmd->u.sedf.period ) - return -EINVAL; - - DOM_INFO(p)->period = cmd->u.sedf.period; - DOM_INFO(p)->slice = cmd->u.sedf.slice; + if (!cmd->u.sedf.period && !cmd->u.sedf.weight) //check for sane parameters + return -EINVAL; + if (cmd->u.sedf.weight) { + DOM_INFO(p)->weight = cmd->u.sedf.weight; //weight driven domains + } + else { + //time driven domains + if(cmd->u.sedf.slice > cmd->u.sedf.period ) /* sanity checking! */ + return -EINVAL; + DOM_INFO(p)->period_orig = + DOM_INFO(p)->period = cmd->u.sedf.period; + DOM_INFO(p)->slice_orig = + DOM_INFO(p)->slice = cmd->u.sedf.slice; + } + if (sedf_adjust_weights(p,cmd)) + return -EINVAL; + DOM_INFO(p)->extra = cmd->u.sedf.extratime; + DOM_INFO(p)->latency = cmd->u.sedf.latency; + extraq_check(p); } else if ( cmd->direction == SCHED_INFO_GET ) { - cmd->u.sedf.period = DOM_INFO(p)->period; - cmd->u.sedf.slice = DOM_INFO(p)->slice; + cmd->u.sedf.period = DOM_INFO(p)->period; + cmd->u.sedf.slice = DOM_INFO(p)->slice; + cmd->u.sedf.extratime = DOM_INFO(p)->extra; + cmd->u.sedf.latency = DOM_INFO(p)->latency; + cmd->u.sedf.weight = DOM_INFO(p)->weight; } PRINT(2,"sedf_adjdom_finished\n"); return 0; diff --git a/xen/include/public/sched_ctl.h b/xen/include/public/sched_ctl.h index f2b9722a4d..5c21769485 100644 --- a/xen/include/public/sched_ctl.h +++ b/xen/include/public/sched_ctl.h @@ -70,8 +70,9 @@ struct sched_adjdom_cmd { u64 period; /* 16 */ u64 slice; /* 24 */ - u64 dummy1; /* 32 */ - u32 dummy2; /* 36 */ + u64 latency; /* 32 */ + u16 extratime; /* 36 */ + u16 weight; /* 38 */ } PACKED sedf; } PACKED u; From 0cabc0963227bc9b83e864b087ff0bef20bdbe6b Mon Sep 17 00:00:00 2001 From: "sd386@font.cl.cam.ac.uk" Date: Fri, 28 Jan 2005 17:31:35 +0000 Subject: [PATCH 03/54] bitkeeper revision 1.1159.170.103 (41fa76f7AyfHPooBzZbsn0ctSduSJg) Bugfixing in SEDF --- xen/common/sched_sedf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c index 3c2913965d..10a12b674e 100644 --- a/xen/common/sched_sedf.c +++ b/xen/common/sched_sedf.c @@ -730,6 +730,7 @@ static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { } else { //time driven domains + DOM_INFO(p)->weight = 0; if(cmd->u.sedf.slice > cmd->u.sedf.period ) /* sanity checking! */ return -EINVAL; DOM_INFO(p)->period_orig = From 1276e201ddadd24b017c3550a76488ad282789c3 Mon Sep 17 00:00:00 2001 From: "sd386@font.cl.cam.ac.uk" Date: Thu, 17 Feb 2005 18:50:24 +0000 Subject: [PATCH 04/54] bitkeeper revision 1.1159.170.104 (4214e770zuNBDS-jq2cWXHSs1B4UOw) Extended sedf scheduler (weighted extraqueues), added enhanced scheduling histogramm --- xen/common/sched_sedf.c | 258 +++++++++++++++++++++++++++++-------- xen/common/schedule.c | 92 ++++++++++++- xen/include/xen/sched-if.h | 11 +- 3 files changed, 302 insertions(+), 59 deletions(-) diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c index 10a12b674e..01e944d554 100644 --- a/xen/common/sched_sedf.c +++ b/xen/common/sched_sedf.c @@ -13,14 +13,33 @@ #include #include +//#include + #define SEDFLEVEL 2 #define PRINT(_f, _a...) \ if ((_f)<=SEDFLEVEL) printk(_a ); +//various ways of unblocking domains +#define UNBLOCK_ISOCHRONOUS_EDF 1 +#define UNBLOCK_EDF 2 +#define UNBLOCK_ATROPOS 3 +#define UNBLOCK_SHORT_RESUME 4 +#define UNBLOCK_BURST 5 + +#define UNBLOCK UNBLOCK_BURST + +//various ways of treating extra-time +#define EXTRA_OFF 1 +#define EXTRA_ROUNDR 2 +#define EXTRA_SLICE_WEIGHT 3 +#define EXTRA_BLOCK_WEIGHT 4 + +#define EXTRA EXTRA_OFF + + /* TODO: TESTING! - implement stylish features! tracing instead of PRINTs */ @@ -29,15 +48,16 @@ if ((_f)<=SEDFLEVEL) printk(_a ); #define EXTRA_NONE (0) #define EXTRA_AWARE (1) #define EXTRA_RUNNING (2) -#define EXTRA_QUANTUM (MICROSECS(1000)) +#define EXTRA_QUANTUM (MICROSECS(500)) #define WEIGHT_PERIOD (MILLISECS(100)) #define WEIGHT_SAFETY (MILLISECS(5)) + struct sedf_dom_info { struct domain *owner; struct list_head list; - struct list_head extralist; + struct list_head extralist[2]; //Parameters for EDF s_time_t period; //=(relative deadline) @@ -50,14 +70,17 @@ struct sedf_dom_info s_time_t latency; //extra-time status of domain short extra; - //weights for "Scheduling for Beginners/ Lazy/ etc." + //weights for "Scheduling for beginners/ lazy/ etc." short weight; //Bookkeeping s_time_t absdead; s_time_t sched_start; s_time_t cputime; - s_time_t absblock; + s_time_t absblock; + s_time_t absunblock; //time the domain unblocked, used by burst mode to determine unblocking intervals + int score[2]; //scores for {util, block penalty}-weighted extratime distribution + s_time_t short_block_lost_tot; //Statistics s_time_t block_time_tot; @@ -109,6 +132,37 @@ static inline int extraq_on(struct domain *d) { return (((EXTRALIST(d))->next != NULL) && (EXTRALIST(d)->next != EXTRALIST(d))); } +/* adds a domain to the queue of processes which are aware of extra time. List is sorted by score, + where a lower score means higher priority for an extra slice. It also updates the score, by simply subtracting + a fixed value from each entry, in order to avoid overflow. The algorithm works by simply charging each domain + that recieved extratime with an inverse of its weight. + */ +static inline void extraq_add_sort_update(struct domain *d, unsigned long sub) { + struct list_head *cur; + struct sedf_dom_info *curinf; + + PRINT(3,"Adding domain %i (score= %llu) to extraq\n",d->id,DOM_INFO(d)->score); + //iterate through all elements to find our "hole" and on our way update all the other scores + list_for_each(cur,EXTRAQ(d->processor)){ + curinf = list_entry(cur,struct sedf_dom_info,extralist); + curinf->score -= sub; + if (DOM_INFO(d)->score < curinf->score) + break; + else + PRINT(4,"\tbehind domain %i (score= %llu)\n",curinf->owner->id,curinf->score); + } + //cur now contains the element, before which we'll enqueue + PRINT(3,"\tlist_add to %x\n",cur->prev); + list_add(EXTRALIST(d),cur->prev); + + //continue updating the extraq + if ((cur != EXTRAQ(d->processor)) && sub) + for (cur = cur->next; cur != EXTRAQ(d->processor); cur = cur-> next) { + curinf = list_entry(cur,struct sedf_dom_info,extralist); + curinf->score -= sub; + PRINT(4,"\tupdating domain %i (score= %llu)\n",curinf->owner->id,curinf->score); + } +} static inline void extraq_check(struct domain *d) { if (extraq_on(d)) { PRINT(2,"Dom %i is on extraQ\n",d->id); @@ -120,11 +174,10 @@ static inline void extraq_check(struct domain *d) { PRINT(2,"Dom %i is NOT on extraQ\n",d->id); if (DOM_INFO(d)->extra != EXTRA_NONE) { PRINT(2,"Added dom %i to extraQ\n",d->id); - extraq_add_tail(d); + extraq_add_sort_update(d, 0); } } } - static inline void __del_from_queue(struct domain *d) { struct list_head *list = LIST(d); @@ -277,29 +330,45 @@ static task_slice_t sedf_do_schedule(s_time_t now) int cpu = current->processor; struct list_head *runq = RUNQ(cpu); struct list_head *waitq = WAITQ(cpu); + #if (EXTRA > EXTRA_OFF) struct list_head *extraq = EXTRAQ(cpu); + #endif struct list_head *cur,*tmp; struct sedf_dom_info *curinf; task_slice_t ret; - + #if (EXTRA == EXTRA_SLICE_WEIGHT) + unsigned long oldscore; + #endif //idle tasks don't need any of the following stuf if (is_idle_task(inf->owner)) goto check_waitq; //idle task doesn't get scheduled on the runq - + + #if (EXTRA > EXTRA_OFF) if (unlikely(inf->extra == EXTRA_RUNNING)) { //special treatment of domains running in extra time inf->extra = EXTRA_AWARE; inf->cputime=0; inf->extra_time_tot += now - inf->sched_start; - extraq_del(current); //remove extradomain from head of the queue - if (domain_runnable(inf->owner)) - extraq_add_tail(current); //and add to the tail if it is runnable => round-robin + extraq_del(current); //remove extradomain from head of the queue + + #if (EXTRA == EXTRA_ROUNDR) + if (domain_runnable(current)) + extraq_add_tail(current); //and add to the tail if it is runnable => round-robin + #elif (EXTRA == EXTRA_SLICE_WEIGHT) + oldscore = inf->score; //update the score + inf->score = (inf->period << 10) / inf->slice; //use fixed point arithmetic with 10 bits + + if (domain_runnable(current)) + extraq_add_sort_update(current, oldscore); //add according to score: weighted round robin + #endif else - __del_from_queue(inf->owner); //if domain blocked in extratime remove it from waitq(/runq) as well + __del_from_queue(inf->owner); //if domain blocked in extratime remove it from waitq(/runq) as well } - else { + else + #endif + { //current domain is running in real time mode //update the domains cputime inf->cputime += now - inf->sched_start; @@ -315,13 +384,18 @@ static task_slice_t sedf_do_schedule(s_time_t now) inf->cputime -= inf->slice; if (inf->period < inf->period_orig) { - //this domain runs in latency scaling mode - inf->period *= 2; - inf->slice *= 2; - if ((inf->period > inf->period_orig) || (inf->slice > inf->slice_orig)) { - //now switch back to standard timing - inf->period = inf->period_orig; - inf->slice = inf->slice_orig; + //this domain runs in latency scaling or burst mode + #if (UNBLOCK == UNBLOCK_BURST) + if (now - inf->absunblock >= 2 * inf->period) + #endif + { + inf->period *= 2; + inf->slice *= 2; + if ((inf->period > inf->period_orig) || (inf->slice > inf->slice_orig)) { + //now switch back to standard timing + inf->period = inf->period_orig; + inf->slice = inf->slice_orig; + } } } inf->absdead += inf->period; //set next deadline @@ -333,9 +407,11 @@ static task_slice_t sedf_do_schedule(s_time_t now) __add_to_waitqueue_sort(inf->owner); else { //we have a blocked realtime task - inf->absblock=now; + inf->absblock = now; + #if (EXTRA > EXTRA_OFF) if (inf->extra == EXTRA_AWARE) extraq_del(inf->owner); //remove a blocked domain from the extraq aswell + #endif } } check_waitq: @@ -393,13 +469,16 @@ check_waitq: if (!list_empty(waitq)) { waitinf = list_entry(waitq->next,struct sedf_dom_info,list); //we could not find any suitable domain => look for domains that are aware of extratime + #if (EXTRA > EXTRA_OFF) if (!list_empty(extraq) && (PERIOD_BEGIN(waitinf) - now >= EXTRA_QUANTUM)) { runinf = list_entry(extraq->next,struct sedf_dom_info,extralist); runinf->extra = EXTRA_RUNNING; ret.task = runinf->owner; ret.time = EXTRA_QUANTUM; } - else { + else + #endif + { //we have an empty run- and extraqueue or too less time => idle task! ret.task = IDLETASK(cpu); ret.time = PERIOD_BEGIN(waitinf) - now; @@ -420,13 +499,19 @@ check_waitq: static void sedf_sleep(struct domain *d) { PRINT(2,"sedf_sleep was called, domain-id %i\n",d->id); - if ( test_bit(DF_RUNNING, &d->flags) ) + if ( test_bit(DF_RUNNING, &d->flags) ) { +#ifdef ADV_SCHED_HISTO + adv_sched_hist_start(d->processor); +#endif cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ); + } else { if ( __task_on_queue(d) ) __del_from_queue(d); + #if (EXTRA > EXTRA_OFF) if (extraq_on(d)) extraq_del(d); + #endif } } @@ -490,9 +575,8 @@ static void sedf_sleep(struct domain *d) { * (or even worse: allocate a new full slice for the domain) * -either behaviour can lead to missed deadlines in other domains as opposed to approaches 1,2a,2b */ -static inline void unblock_short_vcons(struct sedf_dom_info* inf, s_time_t now) { inf->absdead += inf->period;} -static inline void unblock_long_vcons(struct sedf_dom_info* inf, s_time_t now) { - inf->absdead += ((now - inf->absdead) / inf->period + 1) * inf->period; //very conservative +static inline void unblock_short_vcons(struct sedf_dom_info* inf, s_time_t now) { + inf->absdead += inf->period; inf->cputime = 0; } @@ -500,19 +584,23 @@ static inline void unblock_short_cons(struct sedf_dom_info* inf, s_time_t now) { inf->cputime += now - inf->absblock; //treat blocked time as consumed by the domain if (inf->cputime + EXTRA_QUANTUM > inf->slice) { //we don't have a reasonable amount of time in our slice left :( - inf->cputime=0; - inf->absdead += inf->period; //start in next period! + unblock_short_vcons(inf, now); //start in next period! } else - inf->short_cont++; + inf->short_cont++; //we let the domain run in the current period } + +static inline void unblock_long_vcons(struct sedf_dom_info* inf, s_time_t now) { + inf->absdead += ((now - inf->absdead) / inf->period + 1) * inf->period; //very conservative + inf->cputime = 0; +} + static inline void unblock_long_cons_a(struct sedf_dom_info* inf, s_time_t now) { inf->cputime = (now - inf->absdead) % inf->period; //treat the time the domain was blocked in the CURRENT //period as consumed by the domain if (inf->cputime + EXTRA_QUANTUM > inf->slice) { //we don't have a reasonable amount of time in our slice left :( - inf->cputime=0; - inf->absdead += inf->period; //start in next period! + unblock_long_vcons(inf, now); //start in next period! } } static inline void unblock_long_cons_b(struct sedf_dom_info* inf,s_time_t now) { @@ -521,20 +609,52 @@ static inline void unblock_long_cons_b(struct sedf_dom_info* inf,s_time_t now) { } static inline void unblock_long_cons_c(struct sedf_dom_info* inf,s_time_t now) { if (likely(inf->latency)) { - //sclae the slice and period accordingly to the latency hint + //scale the slice and period accordingly to the latency hint inf->period = inf->latency; //reduce period temporarily to the latency hint - ASSERT((inf->latency < ULONG_MAX) && (inf->slice_orig < ULONG_MAX)); //this results in max. 4s slice/period length - inf->slice = (inf->latency * inf->slice_orig) / inf->period_orig; //scale slice accordingly, so that utilisation stays the same + ASSERT((inf->period < ULONG_MAX) && (inf->slice_orig < ULONG_MAX)); //this results in max. 4s slice/period length + inf->slice = (inf->period * inf->slice_orig) / inf->period_orig; //scale slice accordingly, so that utilisation stays the same } else { //we don't have a latency hint.. use some other technique - inf->absdead = now + inf->period; //Conservative 2b... - inf->cputime = 0; + unblock_long_cons_b(inf, now); } } +//a new idea of dealing with short blocks: burst period scaling +static inline void unblock_short_burst(struct sedf_dom_info* inf, s_time_t now) { + inf->cputime += now - inf->absblock; //treat blocked time as consumed by the domain + + if (inf->cputime + EXTRA_QUANTUM <= inf->slice) { + inf->short_cont++; //we let the domain run in the current period + } + else { + //we don't have a reasonable amount of time in our slice left => switch to burst mode + if (likely(inf->absunblock)) { + inf->period = now - inf->absunblock; //set the period-length to the current blocking interval + ASSERT((inf->period < ULONG_MAX) && (inf->slice_orig < ULONG_MAX));//this results in max. 4s slice/period length + inf->slice = (inf->period * inf->slice_orig) / inf->period_orig;//scale slice accordingly, so that utilisation stays the same + } + else { + inf->cputime=0; //in Case we haven't unblocked before + inf->absdead += inf->period; //start in next period! + } + } + inf->absunblock = now; +} +static inline void unblock_long_burst(struct sedf_dom_info* inf,s_time_t now) { + if (unlikely(inf->latency && (inf->period > inf->latency))) { + //sclae the slice and period accordingly to the latency hint + inf->period = inf->latency; //reduce period temporarily to the latency hint + ASSERT((inf->period < ULONG_MAX) && (inf->slice_orig < ULONG_MAX)); //this results in max. 4s slice/period length + inf->slice = (inf->period * inf->slice_orig) / inf->period_orig; //scale slice accordingly, so that utilisation stays the same + } + else { + //we don't have a latency hint.. or we are currently in "burst mode": use some other technique + //this should be in fact the normal way of operation, when we are in sync with the device! + unblock_long_cons_b(inf, now); + } + inf->absunblock = now; +} -/*static inline void unblock_short_vcons -static inline void unblock_short_vcons*/ void sedf_wake(struct domain *d) { //for the first try just implement the "very conservative" way of waking domains up s_time_t now = NOW(); @@ -555,16 +675,19 @@ void sedf_wake(struct domain *d) { if (unlikely(inf->absdead == 0)) inf->absdead = now + inf->slice; //initial setup of the deadline - //very conservative way of unblocking - //make sure that the start of the period for this - //domain is happening in the future PRINT(3,"waking up domain %i (deadl= %llu period= %llu now= %llu)\n",d->id,inf->absdead,inf->period,now); inf->block_tot++; if (unlikely(now< PERIOD_BEGIN(inf))) { //this might happen, imagine unblocking in extra-time! if (likely(inf->extra == EXTRA_AWARE)) + #if (EXTRA == EXTRA_ROUNDR) extraq_add_tail(d); //SD: Could extraq_add_head be better? + #elif (EXTRA == EXTRA_SLICE_WEIGHT) + extraq_add_sort_update(d, 0); + #else + ; + #endif //else //This is very very unlikely, ie. might even be an error?! } @@ -572,19 +695,48 @@ void sedf_wake(struct domain *d) { if (now < inf->absdead) { //short blocking inf->short_block_tot++; - //unblock_short_vcons(inf, now); + #if (UNBLOCK <= UNBLOCK_ATROPOS) + unblock_short_vcons(inf, now); + #elif (UNBLOCK == UNBLOCK_SHORT_RESUME) unblock_short_cons(inf, now); - if (inf->extra == EXTRA_AWARE) + #elif (UNBLOCK == UNBLOCK_BURST) + unblock_short_burst(inf, now); + #endif + + if (inf->extra == EXTRA_AWARE) + #if (EXTRA == EXTRA_OFF) + ; + #elif (EXTRA == EXTRA_ROUNDR) extraq_add_head(d); + #elif (EXTRA == EXTRA_SLICE_WEIGHT) + extraq_add_sort_update(d, 0); + #endif } else { //long blocking inf->long_block_tot++; //PRINT(3,"old=%llu ",inf->absdead); - //unblock_long_vcons(inf, now); - unblock_long_cons_c(inf,now); + #if (UNBLOCK == UNBLOCK_ISOCHRONOUS_EDF) + unblock_long_vcons(inf, now); + #elif (UNBLOCK == UNBLOCK_EDF) + unblock_long_cons_b(inf, now); + #elif (UNBLOCK == UNBLOCK_ATROPOS) + unblock_long_cons_c(inf, now); + #elif (UNBLOCK == UNBLOCK_SHORT_RESUME) + unblock_long_cons_b(inf, now); + //unblock_short_cons_c(inf, now); + #elif (UNBLOCK == UNBLOCK_BURST) + unblock_long_burst(inf, now); + #endif + if (inf->extra == EXTRA_AWARE) - extraq_add_tail(d); + #if (EXTRA == EXTRA_OFF) + ; + #elif (EXTRA == EXTRA_ROUNDR) + extraq_add_head(d); + #elif (EXTRA == EXTRA_SLICE_WEIGHT) + extraq_add_sort_update(d,0); + #endif } } PRINT(3,"waking up domain %i (deadl= %llu period= %llu now= %llu)\n",d->id,inf->absdead,inf->period,now); @@ -592,7 +744,7 @@ void sedf_wake(struct domain *d) { PRINT(3,"added to waitq\n"); //do some statistics here... - if (inf->absblock!=0) { + if (inf->absblock != 0) { inf->block_time_tot += now - inf->absblock; inf->penalty_time_tot += PERIOD_BEGIN(inf) + inf->cputime - inf->absblock; /*if (DOM_INFO(d)->block_time_tot) @@ -607,8 +759,12 @@ void sedf_wake(struct domain *d) { //and check, whether we are idling and this domain is extratime aware if ((PERIOD_BEGIN(inf) < schedule_data[d->processor].s_timer.expires) || (is_idle_task(schedule_data[d->processor].curr) && (now + EXTRA_QUANTUM < schedule_data[d->processor].s_timer.expires) && - (inf->extra == EXTRA_AWARE))) + (inf->extra == EXTRA_AWARE))) { +#ifdef ADV_SCHED_HISTO + adv_sched_hist_start(d->processor); +#endif cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ); + } } @@ -616,9 +772,9 @@ void sedf_wake(struct domain *d) { static void sedf_dump_domain(struct domain *d) { printk("%u has=%c ", d->id, test_bit(DF_RUNNING, &d->flags) ? 'T':'F'); - printk("p=%llu sl=%llu ddl=%llu w=%u c=%llu xtr(%s)=%llu", + printk("p=%llu sl=%llu ddl=%llu w=%u c=%llu sc=%i xtr(%s)=%llu", DOM_INFO(d)->period, DOM_INFO(d)->slice, DOM_INFO(d)->absdead, DOM_INFO(d)->weight, d->cpu_time, - DOM_INFO(d)->extra ? "yes" : "no", DOM_INFO(d)->extra_time_tot); + DOM_INFO(d)->score, DOM_INFO(d)->extra ? "yes" : "no", DOM_INFO(d)->extra_time_tot); if (d->cpu_time !=0) printf(" (%lu%)", (DOM_INFO(d)->extra_time_tot * 100) / d->cpu_time); if (DOM_INFO(d)->block_time_tot!=0) diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 86c39e1a95..3334c19ce0 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -34,6 +34,8 @@ string_param("sched", opt_sched); /*#define WAKE_HISTO*/ /*#define BLOCKTIME_HISTO*/ +/*#define ADV_SCHED_HISTO*/ +//#include #if defined(WAKE_HISTO) #define BUCKETS 31 @@ -198,6 +200,10 @@ void domain_wake(struct domain *d) /* Block the currently-executing domain until a pertinent event occurs. */ long do_block(void) { +#ifdef ADV_SCHED_HISTO + adv_sched_hist_start(current->processor); +#endif + ASSERT(current->id != IDLE_DOMAIN_ID); current->shared_info->vcpu_data[0].evtchn_upcall_mask = 0; set_bit(DF_BLOCKED, ¤t->flags); @@ -209,6 +215,10 @@ long do_block(void) /* Voluntarily yield the processor for this allocation. */ static long do_yield(void) { +#ifdef ADV_SCHED_HISTO + adv_sched_hist_start(current->processor); +#endif + TRACE_2D(TRC_SCHED_YIELD, current->id, current); __enter_scheduler(); return 0; @@ -328,8 +338,14 @@ void __enter_scheduler(void) perfc_incrc(sched_run); spin_lock_irq(&schedule_data[cpu].schedule_lock); - + +#ifdef ADV_SCHED_HISTO + adv_sched_hist_from_stop(cpu); +#endif now = NOW(); +#ifdef ADV_SCHED_HISTO + adv_sched_hist_start(cpu); +#endif rem_ac_timer(&schedule_data[cpu].s_timer); @@ -369,9 +385,12 @@ void __enter_scheduler(void) if ( !is_idle_task(next) ) update_dom_time(next->shared_info); - if ( unlikely(prev == next) ) + if ( unlikely(prev == next) ) { +#ifdef ADV_SCHED_HISTO + adv_sched_hist_to_stop(cpu); +#endif return; - + } perfc_incrc(sched_ctx); #if defined(WAKE_HISTO) @@ -393,7 +412,6 @@ void __enter_scheduler(void) #endif TRACE_2D(TRC_SCHED_SWITCH, next->id, next); - switch_to(prev, next); /* @@ -407,7 +425,10 @@ void __enter_scheduler(void) /* Mark a timer event for the newly-scheduled domain. */ if ( !is_idle_task(next) ) send_guest_virq(next, VIRQ_TIMER); - + +#ifdef ADV_SCHED_HISTO + adv_sched_hist_to_stop(cpu); +#endif schedule_tail(next); BUG(); @@ -431,6 +452,10 @@ int idle_cpu(int cpu) /* The scheduler timer: force a run through the scheduler*/ static void s_timer_fn(unsigned long unused) { +#ifdef ADV_SCHED_HISTO + adv_sched_hist_start(current->processor); +#endif + TRACE_0D(TRC_SCHED_S_TIMER_FN); raise_softirq(SCHEDULE_SOFTIRQ); perfc_incrc(sched_irq); @@ -572,6 +597,63 @@ void reset_sched_histo(unsigned char key) schedule_data[j].hist[i] = 0; } #else +#if defined(ADV_SCHED_HISTO) +void print_sched_histo(unsigned char key) +{ + int i, j, k,t; + printf("Hello!\n"); + for ( k = 0; k < smp_num_cpus; k++ ) + { + j = 0; + t = 0; + printf ("CPU[%02d]: scheduler latency histogram FROM (ms:[count])\n", k); + for ( i = 0; i < BUCKETS; i++ ) + { + //if ( schedule_data[k].hist[i] != 0 ) + { + t += schedule_data[k].from_hist[i]; + if ( i < BUCKETS-1 ) + printk("%3d:[%7u] ", i, schedule_data[k].from_hist[i]); + else + printk(" >:[%7u] ", schedule_data[k].from_hist[i]); + //if ( !(++j % 5) ) + printk("\n"); + } + } + printk("\nTotal: %i\n",t); + } + for ( k = 0; k < smp_num_cpus; k++ ) + { + j = 0; t = 0; + printf ("CPU[%02d]: scheduler latency histogram TO (ms:[count])\n", k); + for ( i = 0; i < BUCKETS; i++ ) + { + //if ( schedule_data[k].hist[i] != 0 ) + { + t += schedule_data[k].from_hist[i]; + if ( i < BUCKETS-1 ) + printk("%3d:[%7u] ", i, schedule_data[k].to_hist[i]); + else + printk(" >:[%7u] ", schedule_data[k].to_hist[i]); + //if ( !(++j % 5) ) + printk("\n"); + } + } + printk("\nTotal: %i\n",t); + } + +} +void reset_sched_histo(unsigned char key) +{ + int i, j; + for ( j = 0; j < smp_num_cpus; j++ ) { + for ( i=0; i < BUCKETS; i++ ) + schedule_data[j].to_hist[i] = schedule_data[j].from_hist[i] = 0; + schedule_data[j].save_tsc = 0; + } +} +#else void print_sched_histo(unsigned char key) { } void reset_sched_histo(unsigned char key) { } #endif +#endif diff --git a/xen/include/xen/sched-if.h b/xen/include/xen/sched-if.h index 15f992614a..a33b0559ed 100644 --- a/xen/include/xen/sched-if.h +++ b/xen/include/xen/sched-if.h @@ -7,7 +7,9 @@ * Portions by Mark Williamson are (C) 2004 Intel Research Cambridge */ -#define BUCKETS 10 +//#define ADV_SCHED_HISTO +#define BUCKETS 10 +/*300*/ typedef struct schedule_data_st { @@ -17,6 +19,11 @@ typedef struct schedule_data_st struct domain *idle; /* idle task for this cpu */ void * sched_priv; struct ac_timer s_timer; /* scheduling timer */ +#ifdef ADV_SCHED_HISTO + u32 to_hist[BUCKETS]; + u32 from_hist[BUCKETS]; + u64 save_tsc; +#endif #ifdef BUCKETS u32 hist[BUCKETS]; /* for scheduler latency histogram */ #endif @@ -55,5 +62,3 @@ struct scheduler /* per CPU scheduler information */ extern schedule_data_t schedule_data[]; - - From ffcf0352a2d552197e34214121bb85dc9583d247 Mon Sep 17 00:00:00 2001 From: "sd386@font.cl.cam.ac.uk" Date: Wed, 9 Mar 2005 14:35:02 +0000 Subject: [PATCH 05/54] bitkeeper revision 1.1159.170.105 (422f0996UBOVE7bb-GrY-kHTfrNOMQ) Implemented twol level extra-time scheduling and added an advanced scheduling history --- .rootkeys | 1 + xen/common/sched_sedf.c | 688 ++++++++++++++++++++----------- xen/include/xen/adv_sched_hist.h | 40 ++ 3 files changed, 498 insertions(+), 231 deletions(-) create mode 100644 xen/include/xen/adv_sched_hist.h diff --git a/.rootkeys b/.rootkeys index 3f6124f99e..be0623acf5 100644 --- a/.rootkeys +++ b/.rootkeys @@ -854,6 +854,7 @@ 3ddb79c25UE59iu4JJcbRalx95mvcg xen/include/public/xen.h 3e397e66m2tO3s-J8Jnr7Ws_tGoPTg xen/include/xen/ac_timer.h 40715b2epYl2jBbxzz9CI2rgIca7Zg xen/include/xen/acpi.h +422f0995xCgnbsVhTjSncnqIABs64g xen/include/xen/adv_sched_hist.h 3ddb79c0c0cX_DZE209-Bb-Rx1v-Aw xen/include/xen/cache.h 3f840f12CkbYSlwMrY2S11Mpyxg7Nw xen/include/xen/compiler.h 3ddb79c259jh8hE7vre_8NuE7nwNSA xen/include/xen/config.h diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c index 01e944d554..1509432572 100644 --- a/xen/common/sched_sedf.c +++ b/xen/common/sched_sedf.c @@ -5,6 +5,14 @@ * based on code by Mark Williamson (C) 2004 Intel Research Cambridge */ +/* + TODO: + TESTING! + tracing instead of PRINTs +*/ + + + #include #include #include @@ -25,8 +33,8 @@ if ((_f)<=SEDFLEVEL) printk(_a ); #define UNBLOCK_ATROPOS 3 #define UNBLOCK_SHORT_RESUME 4 #define UNBLOCK_BURST 5 - -#define UNBLOCK UNBLOCK_BURST +#define UNBLOCK_EXTRA_SUPPORT 6 +#define UNBLOCK UNBLOCK_EXTRA_SUPPORT //various ways of treating extra-time #define EXTRA_OFF 1 @@ -34,20 +42,19 @@ if ((_f)<=SEDFLEVEL) printk(_a ); #define EXTRA_SLICE_WEIGHT 3 #define EXTRA_BLOCK_WEIGHT 4 -#define EXTRA EXTRA_OFF +#define EXTRA EXTRA_BLOCK_WEIGHT - -/* - TODO: - TESTING! - tracing instead of PRINTs -*/ - - -#define TRC_SEDF 0xBEEF0000 #define EXTRA_NONE (0) #define EXTRA_AWARE (1) -#define EXTRA_RUNNING (2) +#define EXTRA_RUN_PEN (2) +#define EXTRA_RUN_UTIL (4) +#define EXTRA_WANT_PEN_Q (8) +#define EXTRA_PEN_Q (0) +#define EXTRA_UTIL_Q (1) + +#define extra_runs(inf) ((inf->extra) & 6) +#define extra_get_cur_q(inf) (((inf->extra & 6) >> 1)-1) + #define EXTRA_QUANTUM (MICROSECS(500)) #define WEIGHT_PERIOD (MILLISECS(100)) #define WEIGHT_SAFETY (MILLISECS(5)) @@ -70,7 +77,7 @@ struct sedf_dom_info s_time_t latency; //extra-time status of domain short extra; - //weights for "Scheduling for beginners/ lazy/ etc." + //weights for "Scheduling for beginners/ lazy/ etc." ;) short weight; //Bookkeeping @@ -90,46 +97,58 @@ struct sedf_dom_info int short_block_tot; int long_block_tot; int short_cont; + int pen_extra_blocks; + int pen_extra_slices; }; struct sedf_cpu_info { struct list_head runnableq; struct list_head waitq; - struct list_head extraq; + struct list_head extraq[2]; }; #define DOM_INFO(d) ((struct sedf_dom_info *)((d)->sched_priv)) #define CPU_INFO(cpu) ((struct sedf_cpu_info *)schedule_data[cpu].sched_priv) #define LIST(d) (&DOM_INFO(d)->list) -#define EXTRALIST(d) (&DOM_INFO(d)->extralist) +#define EXTRALIST(d,i) (&(DOM_INFO(d)->extralist[i])) #define RUNQ(cpu) (&CPU_INFO(cpu)->runnableq) #define WAITQ(cpu) (&CPU_INFO(cpu)->waitq) -#define EXTRAQ(cpu) (&CPU_INFO(cpu)->extraq) +#define EXTRAQ(cpu,i) (&(CPU_INFO(cpu)->extraq[i])) #define IDLETASK(cpu) ((struct domain *)schedule_data[cpu].idle) #define PERIOD_BEGIN(inf) ((inf)->absdead - (inf)->period) +#define MIN(x,y) (((x)<(y))?(x):(y)) +#define DIV_UP(x,y) (((x) + (y) - 1) / y) + static xmem_cache_t *dom_info_cache; -static inline void extraq_add_head(struct domain *d) -{ - list_add(EXTRALIST(d), EXTRAQ(d->processor)); +static void sedf_dump_cpu_state(int i); + +static inline int extraq_on(struct domain *d, int i) { + return ((EXTRALIST(d,i)->next != NULL) && (EXTRALIST(d,i)->next != EXTRALIST(d,i))); } -static inline void extraq_add_tail(struct domain *d) +static inline void extraq_add_head(struct domain *d, int i) { - list_add_tail(EXTRALIST(d), EXTRAQ(d->processor)); + list_add(EXTRALIST(d,i), EXTRAQ(d->processor,i)); } -static inline void extraq_del(struct domain *d) +static inline void extraq_add_tail(struct domain *d, int i) { - struct list_head *list = EXTRALIST(d); - list_del(list); - list->next = NULL; + list_add_tail(EXTRALIST(d,i), EXTRAQ(d->processor,i)); } -static inline int extraq_on(struct domain *d) { - return (((EXTRALIST(d))->next != NULL) && (EXTRALIST(d)->next != EXTRALIST(d))); +static inline void extraq_del(struct domain *d, int i) +{ + struct list_head *list = EXTRALIST(d,i); + /*if (!extraq_on(d,i)) { + PRINT(0,"extraq_del: domain %i is NOT on L%i extraq! HALTING\n",d->id,i); + sedf_dump_cpu_state(0);(*((int*)0))++; + }*/ + PRINT(3, "Removing domain %i from L%i extraq\n", d->id,i); + list_del(list); + list->next = NULL; } /* adds a domain to the queue of processes which are aware of extra time. List is sorted by score, @@ -137,50 +156,57 @@ static inline int extraq_on(struct domain *d) { a fixed value from each entry, in order to avoid overflow. The algorithm works by simply charging each domain that recieved extratime with an inverse of its weight. */ -static inline void extraq_add_sort_update(struct domain *d, unsigned long sub) { +static inline void extraq_add_sort_update(struct domain *d, int i, int sub) { struct list_head *cur; struct sedf_dom_info *curinf; - PRINT(3,"Adding domain %i (score= %llu) to extraq\n",d->id,DOM_INFO(d)->score); + /*if (extraq_on(d,i)) { + PRINT(0,"extraq_add_sort_update: domain %i is already on L%i extraq! HALTING\n",d->id,i); + sedf_dump_cpu_state(0);(*((int*)0))++; + }*/ + PRINT(3, "Adding domain %i (score= %i, short_pen= %lli) to L%i extraq\n", d->id, + DOM_INFO(d)->score[i], DOM_INFO(d)->short_block_lost_tot, i); //iterate through all elements to find our "hole" and on our way update all the other scores - list_for_each(cur,EXTRAQ(d->processor)){ - curinf = list_entry(cur,struct sedf_dom_info,extralist); - curinf->score -= sub; - if (DOM_INFO(d)->score < curinf->score) + list_for_each(cur,EXTRAQ(d->processor,i)){ + curinf = list_entry(cur,struct sedf_dom_info,extralist[i]); + curinf->score[i] -= sub; + if (DOM_INFO(d)->score[i] < curinf->score[i]) break; else - PRINT(4,"\tbehind domain %i (score= %llu)\n",curinf->owner->id,curinf->score); + PRINT(4,"\tbehind domain %i (score= %i)\n", curinf->owner->id, curinf->score[i]); } - //cur now contains the element, before which we'll enqueue - PRINT(3,"\tlist_add to %x\n",cur->prev); - list_add(EXTRALIST(d),cur->prev); + //cur now contains the element, before which we'll enq ueue + PRINT(3, "\tlist_add to %x\n", cur->prev); + list_add(EXTRALIST(d,i),cur->prev); //continue updating the extraq - if ((cur != EXTRAQ(d->processor)) && sub) - for (cur = cur->next; cur != EXTRAQ(d->processor); cur = cur-> next) { - curinf = list_entry(cur,struct sedf_dom_info,extralist); - curinf->score -= sub; - PRINT(4,"\tupdating domain %i (score= %llu)\n",curinf->owner->id,curinf->score); + if ((cur != EXTRAQ(d->processor,i)) && sub) + for (cur = cur->next; cur != EXTRAQ(d->processor,i); cur = cur-> next) { + curinf = list_entry(cur,struct sedf_dom_info,extralist[i]); + curinf->score[i] -= sub; + PRINT(4, "\tupdating domain %i (score= %llu)\n", curinf->owner->id, curinf->score[i]); } } static inline void extraq_check(struct domain *d) { - if (extraq_on(d)) { + if (extraq_on(d, EXTRA_UTIL_Q)) { PRINT(2,"Dom %i is on extraQ\n",d->id); - if (DOM_INFO(d)->extra == EXTRA_NONE) { - extraq_del(d); - PRINT(2,"Removed dom %i from extraQ\n",d->id); + if (!(DOM_INFO(d)->extra & EXTRA_AWARE)) { + extraq_del(d, EXTRA_UTIL_Q); + PRINT(2,"Removed dom %i from L1 extraQ\n",d->id); } } else { - PRINT(2,"Dom %i is NOT on extraQ\n",d->id); - if (DOM_INFO(d)->extra != EXTRA_NONE) { - PRINT(2,"Added dom %i to extraQ\n",d->id); - extraq_add_sort_update(d, 0); + PRINT(2,"Dom %i is NOT on L1 extraQ\n",d->id); + if ((DOM_INFO(d)->extra & EXTRA_AWARE) && domain_runnable(d)) { + extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); + PRINT(2,"Added dom %i to L1 extraQ\n",d->id); + //TODO: add extraq_add_tail } } } static inline void __del_from_queue(struct domain *d) { struct list_head *list = LIST(d); + PRINT(3,"Removing domain %i (bop= %llu) from runq/waitq\n",d->id,PERIOD_BEGIN(DOM_INFO(d))); list_del(list); list->next = NULL; } @@ -192,7 +218,7 @@ static inline void __add_to_waitqueue_sort(struct domain *d) { struct list_head *cur; struct sedf_dom_info *curinf; - PRINT(3,"Adding domain %i (bop= %llu) to waitq\n",d->id,PERIOD_BEGIN(DOM_INFO(d))); + PRINT(3,"Adding domain %i (bop= %llu) to waitq\n",d->id,PERIOD_BEGIN(DOM_INFO(d))); //iterate through all elements to find our "hole" list_for_each(cur,WAITQ(d->processor)){ curinf = list_entry(cur,struct sedf_dom_info,list); @@ -243,13 +269,12 @@ static int sedf_init_scheduler() { schedule_data[i].sched_priv = xmalloc(sizeof(struct sedf_cpu_info)); if ( schedule_data[i].sched_priv == NULL ) return -1; - INIT_LIST_HEAD(WAITQ(i));//used for Latency Scaling + INIT_LIST_HEAD(WAITQ(i)); INIT_LIST_HEAD(RUNQ(i)); - INIT_LIST_HEAD(EXTRAQ(i)); + INIT_LIST_HEAD(EXTRAQ(i,EXTRA_PEN_Q)); + INIT_LIST_HEAD(EXTRAQ(i,EXTRA_UTIL_Q)); } - //we could not find any suitable domain => look for domains that are aware of extratime - dom_info_cache = xmem_cache_create( - "SEDF dom info", sizeof(struct sedf_dom_info), 0, 0, 0, NULL); + dom_info_cache = xmem_cache_create("SEDF dom info", sizeof(struct sedf_dom_info), 0, 0, 0, NULL); if ( dom_info_cache == NULL ) { printk("Could not allocate SLAB cache.\n"); @@ -294,7 +319,8 @@ static void sedf_add_task(struct domain *d) } inf->period_orig = inf->period; inf->slice_orig = inf->slice; INIT_LIST_HEAD(&(inf->list)); - INIT_LIST_HEAD(&(inf->extralist)); + INIT_LIST_HEAD(&(inf->extralist[EXTRA_PEN_Q])); + INIT_LIST_HEAD(&(inf->extralist[EXTRA_UTIL_Q])); } /* Frees memory used by domain info */ @@ -312,112 +338,72 @@ static int sedf_init_idle_task(struct domain *d) { return -1; sedf_add_task(d); - DOM_INFO(d)->absdead=0; + DOM_INFO(d)->absdead = 0; set_bit(DF_RUNNING, &d->flags); //the idle task doesn't have to turn up on any list... return 0; } -#define MIN(x,y) (((x)<(y))?(x):(y)) -/* Main scheduling function - * Reasons for calling this function are: - * -timeslice for the current period used up - * -domain on waitqueue has started it's period - * -and various others ;) in general: determin which domain to run next*/ -static task_slice_t sedf_do_schedule(s_time_t now) -{ - struct sedf_dom_info *inf = DOM_INFO(current); - int cpu = current->processor; - struct list_head *runq = RUNQ(cpu); - struct list_head *waitq = WAITQ(cpu); - #if (EXTRA > EXTRA_OFF) - struct list_head *extraq = EXTRAQ(cpu); - #endif - struct list_head *cur,*tmp; - struct sedf_dom_info *curinf; - task_slice_t ret; - #if (EXTRA == EXTRA_SLICE_WEIGHT) - unsigned long oldscore; - #endif +/* handles the rescheduling, bookkeeping of domains running in their realtime-time :)*/ +static inline void desched_edf_dom (s_time_t now, struct domain* d) { + struct sedf_dom_info* inf = DOM_INFO(d); - //idle tasks don't need any of the following stuf - if (is_idle_task(inf->owner)) - goto check_waitq; //idle task doesn't get scheduled on the runq - - #if (EXTRA > EXTRA_OFF) - if (unlikely(inf->extra == EXTRA_RUNNING)) { - //special treatment of domains running in extra time - inf->extra = EXTRA_AWARE; - inf->cputime=0; - inf->extra_time_tot += now - inf->sched_start; + //current domain is running in real time mode + inf->cputime += now - inf->sched_start; //update the domains cputime + //scheduling decisions, which don't remove the running domain from the runq + if ((inf->cputime < inf->slice) && domain_runnable(d)) + return; //there is nothing to do with the running task - extraq_del(current); //remove extradomain from head of the queue + __del_from_queue(d); + /*if (__task_on_queue(current)) { + PRINT(0,"domain %i was removed but still on run/waitq => HALT\n",current->id); + sedf_dump_cpu_state(0);(*((int*)0))++; + }*/ + + //manage bookkeeping (i.e. calculate next deadline, memorize overun time of slice) of finished domains + if (inf->cputime >= inf->slice) { + inf->cputime -= inf->slice; - #if (EXTRA == EXTRA_ROUNDR) - if (domain_runnable(current)) - extraq_add_tail(current); //and add to the tail if it is runnable => round-robin - #elif (EXTRA == EXTRA_SLICE_WEIGHT) - oldscore = inf->score; //update the score - inf->score = (inf->period << 10) / inf->slice; //use fixed point arithmetic with 10 bits - - if (domain_runnable(current)) - extraq_add_sort_update(current, oldscore); //add according to score: weighted round robin - #endif - else - __del_from_queue(inf->owner); //if domain blocked in extratime remove it from waitq(/runq) as well - } - else - #endif - { - //current domain is running in real time mode - //update the domains cputime - inf->cputime += now - inf->sched_start; - //scheduling decisions, which don't move the running domain to any queues - if ((inf->cputime < inf->slice) && domain_runnable(inf->owner)) - goto check_waitq; //there is nothing to do with the running task - - //remove tasks that can't run - __del_from_queue(inf->owner); - - //manage bookkeeping (i.e. calculate next deadline, memorize overun time of slice) of finished domains - if (inf->cputime >= inf->slice) { - inf->cputime -= inf->slice; - - if (inf->period < inf->period_orig) { - //this domain runs in latency scaling or burst mode - #if (UNBLOCK == UNBLOCK_BURST) - if (now - inf->absunblock >= 2 * inf->period) - #endif - { - inf->period *= 2; - inf->slice *= 2; - if ((inf->period > inf->period_orig) || (inf->slice > inf->slice_orig)) { - //now switch back to standard timing - inf->period = inf->period_orig; - inf->slice = inf->slice_orig; - } + if (inf->period < inf->period_orig) { + //this domain runs in latency scaling or burst mode + #if (UNBLOCK == UNBLOCK_BURST) + if (now - inf->absunblock >= 2 * inf->period) + #endif + { + inf->period *= 2; inf->slice *= 2; + if ((inf->period > inf->period_orig) || (inf->slice > inf->slice_orig)) { + inf->period = inf->period_orig; //update the domains cputime + inf->slice = inf->slice_orig; } } - inf->absdead += inf->period; //set next deadline - } - //if (inf->absdeadid,now,inf->absdead); - //add a runnable domain to the waitqueue - if (domain_runnable(inf->owner)) - __add_to_waitqueue_sort(inf->owner); - else { - //we have a blocked realtime task - inf->absblock = now; - #if (EXTRA > EXTRA_OFF) - if (inf->extra == EXTRA_AWARE) - extraq_del(inf->owner); //remove a blocked domain from the extraq aswell - #endif } + inf->absdead += inf->period; //set next deadline } -check_waitq: + //if (inf->absdeadid,now,inf->absdead); + if (domain_runnable(d)) //add a runnable domain to the waitqueue + __add_to_waitqueue_sort(d); + else { + inf->absblock = now; //we have a blocked realtime task + #if (EXTRA > EXTRA_OFF) + #if (EXTRA == EXTRA_BLOCK_WEIGHT) + if (extraq_on(d,EXTRA_PEN_Q)) extraq_del(d,EXTRA_PEN_Q); + if (extraq_on(d,EXTRA_UTIL_Q)) extraq_del(d,EXTRA_UTIL_Q); + #endif + #endif + } +} + +/* Update all elements on the queues */ +static inline void update_queues(s_time_t now, struct list_head* runq, struct list_head* waitq) { + struct list_head *cur,*tmp; + struct sedf_dom_info *curinf; + + PRINT(3,"Updating waitq..\n"); //check for the first elements of the waitqueue, whether their next period has already started list_for_each_safe(cur,tmp,waitq) { curinf = list_entry(cur,struct sedf_dom_info,list); + PRINT(4,"\tLooking @ dom %i\n",curinf->owner->id); if (PERIOD_BEGIN(curinf) <= now) { __del_from_queue(curinf->owner); __add_to_runqueue_sort(curinf->owner); @@ -426,29 +412,188 @@ check_waitq: break; } - //process the runq + PRINT(3,"Updating runq..\n"); + //process the runq, find domains that are on the runqueue which shouldn't be there list_for_each_safe(cur,tmp,runq) { curinf = list_entry(cur,struct sedf_dom_info,list); - if (unlikely(curinf->slice == 0)) { - //special treatment of elements with empty slice + PRINT(4,"\tLooking @ dom %i\n",curinf->owner->id); + if (unlikely(curinf->slice == 0)) { //ignore domains with empty slice + PRINT(4,"\tUpdating zero-slice domain %i\n",curinf->owner->id); __del_from_queue(curinf->owner); - curinf->absdead += curinf->period; - __add_to_waitqueue_sort(curinf->owner); + curinf->absdead += curinf->period; //move to their next period + __add_to_waitqueue_sort(curinf->owner); //and put them back into the queue } else { if (unlikely((curinf->absdead < now) || (curinf->cputime > curinf->slice))) { //we missed the deadline or the slice was already finished... might hapen because of dom_adj. //printk("Ouch! Domain %i missed deadline %llu\n",curinf->owner->id,curinf->absdead); + PRINT(4,"\tDomain %i exceeded it's deadline/slice (%llu / %llu) now: %llu cputime: %llu\n", + curinf->owner->id, curinf->absdead, curinf->slice, now, curinf->cputime); __del_from_queue(curinf->owner); - curinf->absdead += ((now - curinf->absdead + (curinf->period-1)) / curinf->period) * curinf->period; + curinf->absdead += curinf->period; //common case: we miss one period! + if (unlikely(curinf->absdead < now)) + curinf->absdead += DIV_UP(now - curinf->absdead, curinf->period) * curinf->period; //force start of period to be in future and aligned to period borders! - curinf->cputime = 0; + curinf->cputime = 0; //give a fresh slice __add_to_runqueue_sort(curinf->owner); } else break; } } + PRINT(3,"done updating the queues\n"); +} + +#if (EXTRA > EXTRA_OFF) +/*removes a domain from the head of the according extraQ and requeues it at a specified position: + round-robin extratime: end of extraQ + weighted ext.: insert in sorted list by score + if the domain is blocked / has regained its short-block-loss time it is not put on any queue*/ +static inline void desched_extra_dom(s_time_t now, struct domain* d) { + struct sedf_dom_info *inf = DOM_INFO(d); + int i = extra_get_cur_q(inf); + + #if (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) + unsigned long oldscore; + #endif + + inf->extra &= ~(EXTRA_RUN_PEN | EXTRA_RUN_UTIL); //unset all running flags + inf->cputime = 0; //fresh slice for the next run + inf->extra_time_tot += now - inf->sched_start; //accumulate total extratime + extraq_del(d, i); //remove extradomain from head of the queue + + #if (EXTRA == EXTRA_ROUNDR) + if (domain_runnable(d)) + extraq_add_tail(d, EXTRA_UTIL_Q); //and add to the tail if it is runnable => round-robin + #elif (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) + oldscore = inf->score[i]; //update the score + #if (EXTRA == EXTRA_BLOCK_WEIGHT) + if (i == EXTRA_PEN_Q) { + //domain was running in L0 extraq + //inf->short_block_lost_tot -= EXTRA_QUANTUM; //reduce block lost, probably more sophistication here! + inf->short_block_lost_tot -= now - inf->sched_start; + PRINT(3,"Domain %i: Short_block_lost: %lli\n",inf->owner->id,inf->short_block_lost_tot); + if (inf->short_block_lost_tot <= 0) { + PRINT(4,"Domain %i compensated short block loss!\n"); + inf->short_block_lost_tot = 0; //we have (over-)compensated our block penalty + inf->extra &= ~EXTRA_WANT_PEN_Q; //we don't want a place on the penalty queue anymore! + return; //do not add us on this block extraq again! + } + //we have to go again for another try in the block-extraq + inf->score[EXTRA_PEN_Q] = (inf->period << 10) / inf->short_block_lost_tot; + oldscore = 0; + } else + #endif + { + //domain was running in L1 extraq => score is inverse of utilization and is used somewhat incremental! + inf->score[EXTRA_UTIL_Q] = (inf->period << 10) / inf->slice;//use fixed point arithmetic with 10 bits + } + if (domain_runnable(d)) + extraq_add_sort_update(d, i, oldscore); //add according to score: weighted round robin + else { + inf->absblock = now; + /*if (!__task_on_queue(d)) + printf("Oops... We attempt to remove d %i from the waitq, but it is not on :(\n",d->id);*/ + __del_from_queue(d); //also remove this blocked domain from the waitq! + //make sure that we remove a blocked domain from the other extraq aswell (this caused hours of debugging!) + if (i == EXTRA_PEN_Q) { + if (extraq_on(d,EXTRA_UTIL_Q)) extraq_del(d,EXTRA_UTIL_Q); + } + else { + if (extraq_on(d,EXTRA_PEN_Q)) extraq_del(d,EXTRA_PEN_Q); + } + } + #endif + /*if (!domain_runnable(d)) { + if (extraq_on(d,EXTRA_UTIL_Q)) { + PRINT(0,"domain %i is blocked but still on L1 xq=> HALT\n",d->id); + sedf_dump_cpu_state(0);(*((int*)0))++; + } + if (__task_on_queue(d)) { + PRINT(0,"domain %i is blocked but still on run/waitq=> HALT\n",d->id); + sedf_dump_cpu_state(0);(*((int*)0))++; + } + }*/ +} +#endif + + +static inline task_slice_t sedf_do_extra_schedule(s_time_t now, s_time_t end_xt, struct list_head *extraq[], int cpu) { + task_slice_t ret; + struct sedf_dom_info *runinf; + //TODO write this stuff as a loop and pay attention to normal stuff! + + if (end_xt - now < EXTRA_QUANTUM) + goto return_idle; + + if (!list_empty(extraq[EXTRA_PEN_Q])) { + //we still have elements on the level 0 extraq => let those run first! + runinf = list_entry(extraq[EXTRA_PEN_Q]->next, struct sedf_dom_info, extralist[EXTRA_PEN_Q]); + runinf->extra |= EXTRA_RUN_PEN; + ret.task = runinf->owner; + ret.time = EXTRA_QUANTUM; + runinf->pen_extra_slices++; + } + else if (!list_empty(extraq[EXTRA_UTIL_Q])) { + //use elements from the normal extraqueue + runinf = list_entry(extraq[EXTRA_UTIL_Q]->next,struct sedf_dom_info,extralist[EXTRA_UTIL_Q]); + runinf->extra |= EXTRA_RUN_UTIL; + ret.task = runinf->owner; + ret.time = EXTRA_QUANTUM; + } + else + goto return_idle; + + return ret; + +return_idle: + ret.task = IDLETASK(cpu); + ret.time = end_xt - now; + return ret; +} +/* Main scheduling function + * Reasons for calling this function are: + * -timeslice for the current period used up + * -domain on waitqueue has started it's period + * -and various others ;) in general: determin which domain to run next*/ +static task_slice_t sedf_do_schedule(s_time_t now) +{ + int cpu = current->processor; + struct list_head *runq = RUNQ(cpu); + struct list_head *waitq = WAITQ(cpu); + #if (EXTRA > EXTRA_OFF) + struct sedf_dom_info *inf = DOM_INFO(current); + struct list_head *extraq[] = {EXTRAQ(cpu,EXTRA_PEN_Q),EXTRAQ(cpu, EXTRA_UTIL_Q)}; + #endif + task_slice_t ret; + //int i = 0; + //idle tasks don't need any of the following stuf + if (is_idle_task(current)) + goto check_waitq; //idle task doesn't get moved around on any queues + + #if (EXTRA > EXTRA_OFF) + if (unlikely(extra_runs(inf))) { + //i=1; + desched_extra_dom(now, current); //special treatment of domains running in extra time + } + else + #endif + { + //i=2; + desched_edf_dom(now, current); + } + /*if (!domain_runnable(current)) { + if (extraq_on(current,EXTRA_UTIL_Q)) { + PRINT(0,"domain %i is blocked but still on L1 xq branch %i=> HALT\n",current->id,i); + sedf_dump_cpu_state(0);(*((int*)0))++; + } + if (__task_on_queue(current)) { + PRINT(0,"domain %i is blocked but still on run/waitq branch %i=> HALT\n",current->id,i); + sedf_dump_cpu_state(0);(*((int*)0))++; + } + }*/ +check_waitq: + update_queues(now, runq, waitq); //now simply pick the first domain from the runqueue struct sedf_dom_info *runinf, *waitinf; @@ -464,33 +609,28 @@ check_waitq: else { ret.time = runinf->slice - runinf->cputime; } + goto sched_done; + } + + if (!list_empty(waitq)) { + waitinf = list_entry(waitq->next,struct sedf_dom_info,list); + //we could not find any suitable domain => look for domains that are aware of extratime + #if (EXTRA > EXTRA_OFF) + ret = sedf_do_extra_schedule(now, PERIOD_BEGIN(waitinf), extraq, cpu); + #else + ret.task = IDLETASK(cpu); + ret.time = PERIOD_BEGIN(waitinf) - now; + #endif } else { - if (!list_empty(waitq)) { - waitinf = list_entry(waitq->next,struct sedf_dom_info,list); - //we could not find any suitable domain => look for domains that are aware of extratime - #if (EXTRA > EXTRA_OFF) - if (!list_empty(extraq) && (PERIOD_BEGIN(waitinf) - now >= EXTRA_QUANTUM)) { - runinf = list_entry(extraq->next,struct sedf_dom_info,extralist); - runinf->extra = EXTRA_RUNNING; - ret.task = runinf->owner; - ret.time = EXTRA_QUANTUM; - } - else - #endif - { - //we have an empty run- and extraqueue or too less time => idle task! - ret.task = IDLETASK(cpu); - ret.time = PERIOD_BEGIN(waitinf) - now; - } - } - else { - //this could probably never happen, but one never knows... - //it can... imagine a second CPU, which is pure scifi ATM, but one never knows ;) - ret.task = IDLETASK(cpu); - ret.time = SECONDS(1); - } + //this could probably never happen, but one never knows... + //it can... imagine a second CPU, which is pure scifi ATM, but one never knows ;) + ret.task = IDLETASK(cpu); + ret.time = SECONDS(1); } + +sched_done: + //TODO: Do something USEFUL when this happens and find out, why it still can happen!!! if (ret.time<0) printk("Ouch! We are seriously BEHIND schedule! %lli\n",ret.time); DOM_INFO(ret.task)->sched_start=now; @@ -509,8 +649,12 @@ static void sedf_sleep(struct domain *d) { if ( __task_on_queue(d) ) __del_from_queue(d); #if (EXTRA > EXTRA_OFF) - if (extraq_on(d)) - extraq_del(d); + if (extraq_on(d, EXTRA_UTIL_Q)) + extraq_del(d, EXTRA_UTIL_Q); + #endif + #if (EXTRA == EXTRA_BLOCK_WEIGHT) + if (extraq_on(d, EXTRA_PEN_Q)) + extraq_del(d, EXTRA_PEN_Q); #endif } } @@ -589,7 +733,31 @@ static inline void unblock_short_cons(struct sedf_dom_info* inf, s_time_t now) { else inf->short_cont++; //we let the domain run in the current period } - +static inline void unblock_short_extra_support(struct sedf_dom_info* inf, s_time_t now) { + /*this unblocking scheme tries to support the domain, by assigning it a priority in extratime distribution + according to the loss of time in this slice due to blocking*/ + s_time_t pen; + inf->absdead += inf->period; //no more realtime execution in this period! + if (likely(inf->absblock)) { + //inf->cputime += now - inf->absblock; //treat blocked time as consumed by the domain + pen = (inf->slice - inf->cputime); + if (pen < 0) pen = 0; + //inf->short_block_lost_tot += pen; //calc. penalty because of that + inf->short_block_lost_tot = pen; //set penalty to the current value + //not sure which one is better.. but seems to work well... + + if (inf->short_block_lost_tot) { + inf->score[0] = (inf->period << 10) / inf->short_block_lost_tot; + inf->pen_extra_blocks++; + if (extraq_on(inf->owner, EXTRA_PEN_Q)) + extraq_del(inf->owner, EXTRA_PEN_Q); //remove domain for possible resorting! + else //remember that we want to be on the penalty queue, + inf->extra |= EXTRA_WANT_PEN_Q; //so that we can continue when we (un-)blocked in pen-ext. + extraq_add_sort_update(inf->owner, EXTRA_PEN_Q, 0); //(re-)add domain to the penalty extraq + } + } + inf->cputime = 0; //give it a fresh slice in the next period! +} static inline void unblock_long_vcons(struct sedf_dom_info* inf, s_time_t now) { inf->absdead += ((now - inf->absdead) / inf->period + 1) * inf->period; //very conservative inf->cputime = 0; @@ -655,6 +823,55 @@ static inline void unblock_long_burst(struct sedf_dom_info* inf,s_time_t now) { inf->absunblock = now; } +#define DOMAIN_EDF 1 +#define DOMAIN_EXTRA_PEN 2 +#define DOMAIN_EXTRA_UTIL 3 +#define DOMAIN_IDLE 4 +static inline int get_run_type(struct domain* d) { + struct sedf_dom_info* inf = DOM_INFO(d); + if (is_idle_task(d)) + return DOMAIN_IDLE; + if (inf->extra & EXTRA_RUN_PEN) + return DOMAIN_EXTRA_PEN; + if (inf->extra & EXTRA_RUN_UTIL) + return DOMAIN_EXTRA_UTIL; + return DOMAIN_EDF; +} +/*Compares two domains in the relation of whether the one is allowed to interrupt the others execution. + It returns true (!=0) if a switch to the other domain is good. + Current Priority scheme is as follows: + EDF > L0 (penalty based) extra-time > L1 (utilization) extra-time > blocked domain > idle-domain + In the same class priorities are assigned as following: + EDF: early deadline > late deadline + L0 extra-time: lower score > higher score*/ +static inline int should_switch(struct domain* cur, struct domain* other, s_time_t now) { + struct sedf_dom_info *cur_inf, *other_inf; + cur_inf = DOM_INFO(cur); + other_inf = DOM_INFO(other); + + switch (get_run_type(cur)) { + case DOMAIN_EDF: + //check whether we need to make an earlier sched-decision + if ((PERIOD_BEGIN(other_inf) < schedule_data[other->processor].s_timer.expires) + && (other_inf->absdead < cur_inf->absdead)) + return 1; + else return 0; + case DOMAIN_EXTRA_PEN: + //check whether we need an earlier decision or we also want the L0 ex-q with lower score + if ((PERIOD_BEGIN(other_inf) < schedule_data[other->processor].s_timer.expires) + || ((other_inf->extra & EXTRA_WANT_PEN_Q) && (other_inf->score[EXTRA_PEN_Q] < cur_inf->score[EXTRA_PEN_Q]))) + return 1; + else return 0; + case DOMAIN_EXTRA_UTIL: + //check whether we need an earlier decision or we want the L0 extraq, don't switch if both domains want L1 extraq + if ((PERIOD_BEGIN(other_inf) < schedule_data[other->processor].s_timer.expires) + || (other_inf->extra & EXTRA_WANT_PEN_Q)) + return 1; + else return 0; + case DOMAIN_IDLE: + return 1; + } +} void sedf_wake(struct domain *d) { //for the first try just implement the "very conservative" way of waking domains up s_time_t now = NOW(); @@ -669,7 +886,7 @@ void sedf_wake(struct domain *d) { PRINT(3,"\tdomain %i is already in some queue\n",d->id); return; } - if ( unlikely(extraq_on(d)) ) { + if ( unlikely(extraq_on(d,EXTRA_UTIL_Q) || extraq_on(d,EXTRA_PEN_Q)) ) { PRINT(3,"\tdomain %i is already in the extraQ\n",d->id); } if (unlikely(inf->absdead == 0)) @@ -679,12 +896,18 @@ void sedf_wake(struct domain *d) { inf->block_tot++; if (unlikely(now< PERIOD_BEGIN(inf))) { + PRINT(4,"extratime unblock\n"); //this might happen, imagine unblocking in extra-time! - if (likely(inf->extra == EXTRA_AWARE)) + #if (EXTRA == EXTRA_BLOCK_WEIGHT) + if (inf->extra & EXTRA_WANT_PEN_Q) { //we have a domain that wants compensation + extraq_add_sort_update(d, EXTRA_PEN_Q, 0); + } /*else*/ + #endif + if (inf->extra & EXTRA_AWARE) #if (EXTRA == EXTRA_ROUNDR) - extraq_add_tail(d); //SD: Could extraq_add_head be better? - #elif (EXTRA == EXTRA_SLICE_WEIGHT) - extraq_add_sort_update(d, 0); + extraq_add_tail(d,EXTRA_UTIL_Q); //SD: Could extraq_add_head be better? + #elif (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) + extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); //put in on the weighted extraq #else ; #endif @@ -693,6 +916,7 @@ void sedf_wake(struct domain *d) { } else { if (now < inf->absdead) { + PRINT(4,"short unblocking\n"); //short blocking inf->short_block_tot++; #if (UNBLOCK <= UNBLOCK_ATROPOS) @@ -701,24 +925,27 @@ void sedf_wake(struct domain *d) { unblock_short_cons(inf, now); #elif (UNBLOCK == UNBLOCK_BURST) unblock_short_burst(inf, now); + #elif (UNBLOCK == UNBLOCK_EXTRA_SUPPORT) + unblock_short_extra_support(inf, now); #endif - - if (inf->extra == EXTRA_AWARE) + + if (inf->extra & EXTRA_AWARE) #if (EXTRA == EXTRA_OFF) ; #elif (EXTRA == EXTRA_ROUNDR) - extraq_add_head(d); - #elif (EXTRA == EXTRA_SLICE_WEIGHT) - extraq_add_sort_update(d, 0); + extraq_add_head(d); //Favour domains which got short unblocked + #elif (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) + extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); #endif } else { + PRINT(4,"long unblocking\n"); //long blocking inf->long_block_tot++; //PRINT(3,"old=%llu ",inf->absdead); #if (UNBLOCK == UNBLOCK_ISOCHRONOUS_EDF) unblock_long_vcons(inf, now); - #elif (UNBLOCK == UNBLOCK_EDF) + #elif (UNBLOCK == UNBLOCK_EDF || UNBLOCK == UNBLOCK_EXTRA_SUPPORT) unblock_long_cons_b(inf, now); #elif (UNBLOCK == UNBLOCK_ATROPOS) unblock_long_cons_c(inf, now); @@ -729,17 +956,21 @@ void sedf_wake(struct domain *d) { unblock_long_burst(inf, now); #endif - if (inf->extra == EXTRA_AWARE) + if (inf->extra & EXTRA_AWARE) { #if (EXTRA == EXTRA_OFF) ; #elif (EXTRA == EXTRA_ROUNDR) extraq_add_head(d); - #elif (EXTRA == EXTRA_SLICE_WEIGHT) - extraq_add_sort_update(d,0); + #elif (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) + //PRINT(2,"now try to add domain %i to the extra_util_q\n",d->id); + extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); + //PRINT(2,"added domain\n"); #endif + } + } } - PRINT(3,"waking up domain %i (deadl= %llu period= %llu now= %llu)\n",d->id,inf->absdead,inf->period,now); + PRINT(3,"woke up domain %i (deadl= %llu period= %llu now= %llu)\n",d->id,inf->absdead,inf->period,now); __add_to_waitqueue_sort(d); PRINT(3,"added to waitq\n"); @@ -747,19 +978,15 @@ void sedf_wake(struct domain *d) { if (inf->absblock != 0) { inf->block_time_tot += now - inf->absblock; inf->penalty_time_tot += PERIOD_BEGIN(inf) + inf->cputime - inf->absblock; - /*if (DOM_INFO(d)->block_time_tot) - PRINT(3,"penalty: %lu\n",(DOM_INFO(d)->penalty_time_tot*100)/DOM_INFO(d)->block_time_tot);*/ } - /*if ( is_idle_task(schedule_data[d->processor].curr)) { - cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ); - return; - }*/ - + //sanity check: make sure each extra-aware domain IS on the util-q! + if (inf->extra & EXTRA_AWARE) { + if (!extraq_on(d, EXTRA_UTIL_Q)) + printf("sedf_wake: domain %i is extra-aware, but NOT on L1 extraq!\n",d->id); + } //check whether the awakened task needs to get scheduled before the next sched. decision //and check, whether we are idling and this domain is extratime aware - if ((PERIOD_BEGIN(inf) < schedule_data[d->processor].s_timer.expires) || - (is_idle_task(schedule_data[d->processor].curr) && (now + EXTRA_QUANTUM < schedule_data[d->processor].s_timer.expires) && - (inf->extra == EXTRA_AWARE))) { + if (should_switch(schedule_data[d->processor].curr, d, now)){ #ifdef ADV_SCHED_HISTO adv_sched_hist_start(d->processor); #endif @@ -772,17 +999,18 @@ void sedf_wake(struct domain *d) { static void sedf_dump_domain(struct domain *d) { printk("%u has=%c ", d->id, test_bit(DF_RUNNING, &d->flags) ? 'T':'F'); - printk("p=%llu sl=%llu ddl=%llu w=%u c=%llu sc=%i xtr(%s)=%llu", + printk("p=%llu sl=%llu ddl=%llu w=%hu c=%llu sc=%i xtr(%s)=%llu", DOM_INFO(d)->period, DOM_INFO(d)->slice, DOM_INFO(d)->absdead, DOM_INFO(d)->weight, d->cpu_time, - DOM_INFO(d)->score, DOM_INFO(d)->extra ? "yes" : "no", DOM_INFO(d)->extra_time_tot); + DOM_INFO(d)->score[EXTRA_UTIL_Q], (DOM_INFO(d)->extra & EXTRA_AWARE) ? "yes" : "no", DOM_INFO(d)->extra_time_tot); if (d->cpu_time !=0) printf(" (%lu%)", (DOM_INFO(d)->extra_time_tot * 100) / d->cpu_time); if (DOM_INFO(d)->block_time_tot!=0) printf(" pen=%lu%", (DOM_INFO(d)->penalty_time_tot * 100) / DOM_INFO(d)->block_time_tot); if (DOM_INFO(d)->block_tot!=0) - printf("\n blks=%lu sh=%lu (%lu%) (shc=%lu (%lu%)) l=%lu (%lu%) avg: b=%llu p=%llu", DOM_INFO(d)->block_tot, + printf("\n blks=%lu sh=%lu (%lu%) (shc=%lu (%lu%) shex=%i shexsl=%i) l=%lu (%lu%) avg: b=%llu p=%llu", DOM_INFO(d)->block_tot, DOM_INFO(d)->short_block_tot, (DOM_INFO(d)->short_block_tot * 100) / DOM_INFO(d)->block_tot, DOM_INFO(d)->short_cont, (DOM_INFO(d)->short_cont * 100) / DOM_INFO(d)->block_tot, + DOM_INFO(d)->pen_extra_blocks, DOM_INFO(d)->pen_extra_slices, DOM_INFO(d)->long_block_tot, (DOM_INFO(d)->long_block_tot * 100) / DOM_INFO(d)->block_tot, (DOM_INFO(d)->block_time_tot) / DOM_INFO(d)->block_tot, (DOM_INFO(d)->penalty_time_tot) / DOM_INFO(d)->block_tot); @@ -793,8 +1021,6 @@ static void sedf_dump_cpu_state(int i) { struct list_head *list, *queue, *tmp; int loop = 0; -/* int found = 0; - int id1st = 0;*/ struct sedf_dom_info *d_inf; struct domain* d; @@ -802,8 +1028,7 @@ static void sedf_dump_cpu_state(int i) queue = RUNQ(i); printk("RUNQ rq %lx n: %lx, p: %lx\n", (unsigned long)queue, (unsigned long) queue->next, (unsigned long) queue->prev); - list_for_each_safe ( list, tmp, queue ) - { + list_for_each_safe ( list, tmp, queue ) { printk("%3d: ",loop++); d_inf = list_entry(list, struct sedf_dom_info, list); sedf_dump_domain(d_inf->owner); @@ -812,25 +1037,26 @@ static void sedf_dump_cpu_state(int i) queue = WAITQ(i); loop = 0; printk("\nWAITQ rq %lx n: %lx, p: %lx\n", (unsigned long)queue, (unsigned long) queue->next, (unsigned long) queue->prev); - list_for_each_safe ( list, tmp, queue ) - { + list_for_each_safe ( list, tmp, queue ) { printk("%3d: ",loop++); d_inf = list_entry(list, struct sedf_dom_info, list); sedf_dump_domain(d_inf->owner); } - queue = EXTRAQ(i); loop = 0; - printk("\nEXTRAQ rq %lx n: %lx, p: %lx\n", (unsigned long)queue, + queue = EXTRAQ(i,EXTRA_PEN_Q); loop = 0; + printk("\nEXTRAQ (penalty) rq %lx n: %lx, p: %lx\n", (unsigned long)queue, (unsigned long) queue->next, (unsigned long) queue->prev); - list_for_each_safe ( list, tmp, queue ) - { - d_inf = list_entry(list, struct sedf_dom_info, extralist); - -/* if (found) { - if (id1st == d_inf->owner->id) - break; - } - else { id1st=d_inf->owner->id; found=1;}*/ + list_for_each_safe ( list, tmp, queue ) { + d_inf = list_entry(list, struct sedf_dom_info, extralist[EXTRA_PEN_Q]); + printk("%3d: ",loop++); + sedf_dump_domain(d_inf->owner); + } + + queue = EXTRAQ(i,EXTRA_UTIL_Q); loop = 0; + printk("\nEXTRAQ (utilization) rq %lx n: %lx, p: %lx\n", (unsigned long)queue, + (unsigned long) queue->next, (unsigned long) queue->prev); + list_for_each_safe ( list, tmp, queue ) { + d_inf = list_entry(list, struct sedf_dom_info, extralist[EXTRA_UTIL_Q]); printk("%3d: ",loop++); sedf_dump_domain(d_inf->owner); } @@ -838,7 +1064,7 @@ static void sedf_dump_cpu_state(int i) loop = 0; printk("\nnot on Q\n"); for_each_domain(d) { - if (!extraq_on(d) && !__task_on_queue(d)) { + if (!extraq_on(d,1) && !__task_on_queue(d)) { printk("%3d: ",loop++); sedf_dump_domain(d); } @@ -896,7 +1122,7 @@ static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { } if (sedf_adjust_weights(p,cmd)) return -EINVAL; - DOM_INFO(p)->extra = cmd->u.sedf.extratime; + DOM_INFO(p)->extra = (DOM_INFO(p)-> extra & ~EXTRA_AWARE) | (cmd->u.sedf.extratime & EXTRA_AWARE); DOM_INFO(p)->latency = cmd->u.sedf.latency; extraq_check(p); } @@ -904,7 +1130,7 @@ static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { { cmd->u.sedf.period = DOM_INFO(p)->period; cmd->u.sedf.slice = DOM_INFO(p)->slice; - cmd->u.sedf.extratime = DOM_INFO(p)->extra; + cmd->u.sedf.extratime = DOM_INFO(p)->extra & EXTRA_AWARE; cmd->u.sedf.latency = DOM_INFO(p)->latency; cmd->u.sedf.weight = DOM_INFO(p)->weight; } diff --git a/xen/include/xen/adv_sched_hist.h b/xen/include/xen/adv_sched_hist.h new file mode 100644 index 0000000000..d8d56275d4 --- /dev/null +++ b/xen/include/xen/adv_sched_hist.h @@ -0,0 +1,40 @@ +/* Some functions to suport advanced scheduler histograms + Author: Stephan.Diestelhorst@cl.cam.ac.uk */ +//#include +//#include +#include +#define ADV_SCHED_HISTO +static inline void adv_sched_hist_start(int cpu) { + u64 now; + rdtscll(now); + if (!schedule_data[cpu].save_tsc) + schedule_data[cpu].save_tsc = now; +} +static inline void adv_sched_hist_from_stop(int cpu) { + u64 now; + rdtscll(now); + if (schedule_data[cpu].save_tsc) { + now -= schedule_data[cpu].save_tsc; + now /= 7; + if (now < BUCKETS-1) + schedule_data[cpu].from_hist[now]++; + else + schedule_data[cpu].from_hist[BUCKETS-1]++; + + schedule_data[cpu].save_tsc = 0; + } +} +static inline void adv_sched_hist_to_stop(int cpu) { + u64 now; + rdtscll(now); + if (schedule_data[cpu].save_tsc) { + now -= schedule_data[cpu].save_tsc; + now /= 24; + if (now < BUCKETS-1) + schedule_data[cpu].to_hist[now]++; + else + schedule_data[cpu].to_hist[BUCKETS-1]++; + + schedule_data[cpu].save_tsc = 0; + } +} From 4be324fcbaafe9e775ca138bc17ef3fdb04c226f Mon Sep 17 00:00:00 2001 From: "sd386@font.cl.cam.ac.uk" Date: Wed, 9 Mar 2005 16:10:08 +0000 Subject: [PATCH 06/54] bitkeeper revision 1.1159.170.106 (422f1fe04lkSpzGfJ9fkoHS3KOxslw) Fixed weights on SMP machines. --- xen/common/sched_sedf.c | 70 ++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c index 1509432572..d9816c3ac6 100644 --- a/xen/common/sched_sedf.c +++ b/xen/common/sched_sedf.c @@ -5,14 +5,6 @@ * based on code by Mark Williamson (C) 2004 Intel Research Cambridge */ -/* - TODO: - TESTING! - tracing instead of PRINTs -*/ - - - #include #include #include @@ -75,10 +67,9 @@ struct sedf_dom_info s_time_t period_orig; s_time_t slice_orig; s_time_t latency; - //extra-time status of domain - short extra; - //weights for "Scheduling for beginners/ lazy/ etc." ;) - short weight; + + short extra; //extra-time status of domain + short weight; //weights for "Scheduling for beginners/ lazy/ etc." ;) //Bookkeeping s_time_t absdead; @@ -197,9 +188,14 @@ static inline void extraq_check(struct domain *d) { } else { PRINT(2,"Dom %i is NOT on L1 extraQ\n",d->id); if ((DOM_INFO(d)->extra & EXTRA_AWARE) && domain_runnable(d)) { + #if (EXTRA == EXTRA_ROUNDR) + extraq_add_tail(d, EXTRA_UTIL_Q); //Favour domains which got short unblocked + #elif (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); + #elif + ; + #endif PRINT(2,"Added dom %i to L1 extraQ\n",d->id); - //TODO: add extraq_add_tail } } } @@ -350,9 +346,8 @@ static inline void desched_edf_dom (s_time_t now, struct domain* d) { //current domain is running in real time mode inf->cputime += now - inf->sched_start; //update the domains cputime - //scheduling decisions, which don't remove the running domain from the runq - if ((inf->cputime < inf->slice) && domain_runnable(d)) - return; //there is nothing to do with the running task + if ((inf->cputime < inf->slice) && domain_runnable(d)) //scheduling decisions, which don't remove the running domain from the runq + return; //there is nothing to do with the running task __del_from_queue(d); /*if (__task_on_queue(current)) { @@ -388,8 +383,8 @@ static inline void desched_edf_dom (s_time_t now, struct domain* d) { #if (EXTRA > EXTRA_OFF) #if (EXTRA == EXTRA_BLOCK_WEIGHT) if (extraq_on(d,EXTRA_PEN_Q)) extraq_del(d,EXTRA_PEN_Q); - if (extraq_on(d,EXTRA_UTIL_Q)) extraq_del(d,EXTRA_UTIL_Q); #endif + if (extraq_on(d,EXTRA_UTIL_Q)) extraq_del(d,EXTRA_UTIL_Q); #endif } } @@ -496,12 +491,14 @@ static inline void desched_extra_dom(s_time_t now, struct domain* d) { printf("Oops... We attempt to remove d %i from the waitq, but it is not on :(\n",d->id);*/ __del_from_queue(d); //also remove this blocked domain from the waitq! //make sure that we remove a blocked domain from the other extraq aswell (this caused hours of debugging!) + #if (EXTRA == EXTRA_BLOCK_WEIGHT) if (i == EXTRA_PEN_Q) { if (extraq_on(d,EXTRA_UTIL_Q)) extraq_del(d,EXTRA_UTIL_Q); } else { if (extraq_on(d,EXTRA_PEN_Q)) extraq_del(d,EXTRA_PEN_Q); } + #endif } #endif /*if (!domain_runnable(d)) { @@ -521,7 +518,7 @@ static inline void desched_extra_dom(s_time_t now, struct domain* d) { static inline task_slice_t sedf_do_extra_schedule(s_time_t now, s_time_t end_xt, struct list_head *extraq[], int cpu) { task_slice_t ret; struct sedf_dom_info *runinf; - //TODO write this stuff as a loop and pay attention to normal stuff! + //TODO write this stuff as a loop if (end_xt - now < EXTRA_QUANTUM) goto return_idle; @@ -555,7 +552,7 @@ return_idle: * Reasons for calling this function are: * -timeslice for the current period used up * -domain on waitqueue has started it's period - * -and various others ;) in general: determin which domain to run next*/ + * -and various others ;) in general: determine which domain to run next*/ static task_slice_t sedf_do_schedule(s_time_t now) { int cpu = current->processor; @@ -631,8 +628,10 @@ check_waitq: sched_done: //TODO: Do something USEFUL when this happens and find out, why it still can happen!!! - if (ret.time<0) + if (ret.time<0) { printk("Ouch! We are seriously BEHIND schedule! %lli\n",ret.time); + ret.time = EXTRA_QUANTUM; + } DOM_INFO(ret.task)->sched_start=now; return ret; } @@ -840,7 +839,7 @@ static inline int get_run_type(struct domain* d) { /*Compares two domains in the relation of whether the one is allowed to interrupt the others execution. It returns true (!=0) if a switch to the other domain is good. Current Priority scheme is as follows: - EDF > L0 (penalty based) extra-time > L1 (utilization) extra-time > blocked domain > idle-domain + EDF > L0 (penalty based) extra-time > L1 (utilization) extra-time > idle-domain In the same class priorities are assigned as following: EDF: early deadline > late deadline L0 extra-time: lower score > higher score*/ @@ -933,7 +932,7 @@ void sedf_wake(struct domain *d) { #if (EXTRA == EXTRA_OFF) ; #elif (EXTRA == EXTRA_ROUNDR) - extraq_add_head(d); //Favour domains which got short unblocked + extraq_add_head(d, EXTRA_UTIL_Q); //Favour domains which got short unblocked #elif (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); #endif @@ -960,7 +959,7 @@ void sedf_wake(struct domain *d) { #if (EXTRA == EXTRA_OFF) ; #elif (EXTRA == EXTRA_ROUNDR) - extraq_add_head(d); + extraq_add_head(d, EXTRA_UTIL_Q); #elif (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) //PRINT(2,"now try to add domain %i to the extra_util_q\n",d->id); extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); @@ -980,10 +979,10 @@ void sedf_wake(struct domain *d) { inf->penalty_time_tot += PERIOD_BEGIN(inf) + inf->cputime - inf->absblock; } //sanity check: make sure each extra-aware domain IS on the util-q! - if (inf->extra & EXTRA_AWARE) { + /*if (inf->extra & EXTRA_AWARE) { if (!extraq_on(d, EXTRA_UTIL_Q)) printf("sedf_wake: domain %i is extra-aware, but NOT on L1 extraq!\n",d->id); - } + }*/ //check whether the awakened task needs to get scheduled before the next sched. decision //and check, whether we are idling and this domain is extratime aware if (should_switch(schedule_data[d->processor].curr, d, now)){ @@ -994,8 +993,7 @@ void sedf_wake(struct domain *d) { } } - -/* This could probably be a bit more specific!*/ +/*Print a lot of use-{full, less} information about a domains in the system*/ static void sedf_dump_domain(struct domain *d) { printk("%u has=%c ", d->id, test_bit(DF_RUNNING, &d->flags) ? 'T':'F'); @@ -1017,6 +1015,7 @@ static void sedf_dump_domain(struct domain *d) { printf("\n"); } +/*dumps all domains on hte specified cpu*/ static void sedf_dump_cpu_state(int i) { struct list_head *list, *queue, *tmp; @@ -1064,7 +1063,7 @@ static void sedf_dump_cpu_state(int i) loop = 0; printk("\nnot on Q\n"); for_each_domain(d) { - if (!extraq_on(d,1) && !__task_on_queue(d)) { + if (!__task_on_queue(d) && (d->processor == i)) { printk("%3d: ",loop++); sedf_dump_domain(d); } @@ -1072,19 +1071,24 @@ static void sedf_dump_cpu_state(int i) } //Adjusts periods and slices of the domains accordingly to their weights static inline int sedf_adjust_weights(struct domain *p, struct sched_adjdom_cmd *cmd) { - int sumw = 0; - s_time_t sumt = 0; + int sumw[NR_CPUS]; + s_time_t sumt[NR_CPUS]; + int cpu; + for (cpu=0; cpu < NR_CPUS; cpu++) { + sumw[cpu] = 0; + sumt[cpu] = 0; + } //sum up all weights for_each_domain(p) { if (DOM_INFO(p)->weight) - sumw += DOM_INFO(p)->weight; + sumw[p->processor] += DOM_INFO(p)->weight; else { //don't modify domains who don't have a weight, but sum up //the time they need, projected to a WEIGHT_PERIOD, so that //this time is not given to the weight-driven domains ASSERT((WEIGHT_PERIOD < ULONG_MAX) && (DOM_INFO(p)->slice_orig < ULONG_MAX)); //this results in max. 4s slice/period length - sumt += (WEIGHT_PERIOD * DOM_INFO(p)->slice_orig) / DOM_INFO(p)->period_orig; + sumt[p->processor] += (WEIGHT_PERIOD * DOM_INFO(p)->slice_orig) / DOM_INFO(p)->period_orig; } } //adjust all slices (and periods) to the new weight @@ -1093,7 +1097,7 @@ static inline int sedf_adjust_weights(struct domain *p, struct sched_adjdom_cmd DOM_INFO(p)->period_orig = DOM_INFO(p)->period = WEIGHT_PERIOD; DOM_INFO(p)->slice_orig = - DOM_INFO(p)->slice = (DOM_INFO(p)->weight * (WEIGHT_PERIOD - WEIGHT_SAFETY - sumt)) / sumw; + DOM_INFO(p)->slice = (DOM_INFO(p)->weight * (WEIGHT_PERIOD - WEIGHT_SAFETY - sumt[p->processor])) / sumw[p->processor]; } } return 0; From 94e7002d4975dadf0457f786a7c719e9877d522d Mon Sep 17 00:00:00 2001 From: "sd386@font.cl.cam.ac.uk" Date: Tue, 29 Mar 2005 15:57:43 +0000 Subject: [PATCH 07/54] bitkeeper revision 1.1159.170.107 (42497af7aXKR1tJnN7XlLoXsYCxABQ) cleaned up some statistics code, new domains are now best effort by default, fixed possible bug for best effort domains --- xen/common/sched_sedf.c | 47 +++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c index d9816c3ac6..af8b9ba77b 100644 --- a/xen/common/sched_sedf.c +++ b/xen/common/sched_sedf.c @@ -15,10 +15,15 @@ //#include -#define SEDFLEVEL 2 +//verbosity settings +#define SEDFLEVEL 0 #define PRINT(_f, _a...) \ if ((_f)<=SEDFLEVEL) printk(_a ); +#ifdef DEBUG + #define SEDF_STATS +#endif + //various ways of unblocking domains #define UNBLOCK_ISOCHRONOUS_EDF 1 #define UNBLOCK_EDF 2 @@ -81,15 +86,18 @@ struct sedf_dom_info s_time_t short_block_lost_tot; //Statistics + s_time_t extra_time_tot; + +#ifdef SEDF_STATS s_time_t block_time_tot; s_time_t penalty_time_tot; - s_time_t extra_time_tot; int block_tot; int short_block_tot; int long_block_tot; int short_cont; int pen_extra_blocks; int pen_extra_slices; +#endif }; struct sedf_cpu_info { @@ -181,7 +189,7 @@ static inline void extraq_add_sort_update(struct domain *d, int i, int sub) { static inline void extraq_check(struct domain *d) { if (extraq_on(d, EXTRA_UTIL_Q)) { PRINT(2,"Dom %i is on extraQ\n",d->id); - if (!(DOM_INFO(d)->extra & EXTRA_AWARE)) { + if (!(DOM_INFO(d)->extra & EXTRA_AWARE) && !extra_runs(DOM_INFO(d))) { extraq_del(d, EXTRA_UTIL_Q); PRINT(2,"Removed dom %i from L1 extraQ\n",d->id); } @@ -306,12 +314,12 @@ static void sedf_add_task(struct domain *d) inf->extra = EXTRA_NONE;//EXTRA_AWARE; } else { - //other domains don't get any execution time at all in the beginning! + //other domains run in best effort mode inf->period = MILLISECS(20); inf->slice = 0; inf->absdead = 0; inf->latency = 0; - inf->extra = EXTRA_NONE;//EXTRA_AWARE + inf->extra = EXTRA_AWARE; } inf->period_orig = inf->period; inf->slice_orig = inf->slice; INIT_LIST_HEAD(&(inf->list)); @@ -481,7 +489,10 @@ static inline void desched_extra_dom(s_time_t now, struct domain* d) { #endif { //domain was running in L1 extraq => score is inverse of utilization and is used somewhat incremental! - inf->score[EXTRA_UTIL_Q] = (inf->period << 10) / inf->slice;//use fixed point arithmetic with 10 bits + if (inf->slice) + inf->score[EXTRA_UTIL_Q] = (inf->period << 10) / inf->slice;//use fixed point arithmetic with 10 bits + else + inf->score[EXTRA_UTIL_Q] = 2^10; } if (domain_runnable(d)) extraq_add_sort_update(d, i, oldscore); //add according to score: weighted round robin @@ -529,7 +540,9 @@ static inline task_slice_t sedf_do_extra_schedule(s_time_t now, s_time_t end_xt, runinf->extra |= EXTRA_RUN_PEN; ret.task = runinf->owner; ret.time = EXTRA_QUANTUM; +#ifdef SEDF_STATS runinf->pen_extra_slices++; +#endif } else if (!list_empty(extraq[EXTRA_UTIL_Q])) { //use elements from the normal extraqueue @@ -729,8 +742,10 @@ static inline void unblock_short_cons(struct sedf_dom_info* inf, s_time_t now) { //we don't have a reasonable amount of time in our slice left :( unblock_short_vcons(inf, now); //start in next period! } +#ifdef SEDF_STATS else inf->short_cont++; //we let the domain run in the current period +#endif } static inline void unblock_short_extra_support(struct sedf_dom_info* inf, s_time_t now) { /*this unblocking scheme tries to support the domain, by assigning it a priority in extratime distribution @@ -747,7 +762,9 @@ static inline void unblock_short_extra_support(struct sedf_dom_info* inf, s_time if (inf->short_block_lost_tot) { inf->score[0] = (inf->period << 10) / inf->short_block_lost_tot; +#ifdef SEDF_STATS inf->pen_extra_blocks++; +#endif if (extraq_on(inf->owner, EXTRA_PEN_Q)) extraq_del(inf->owner, EXTRA_PEN_Q); //remove domain for possible resorting! else //remember that we want to be on the penalty queue, @@ -791,7 +808,9 @@ static inline void unblock_short_burst(struct sedf_dom_info* inf, s_time_t now) inf->cputime += now - inf->absblock; //treat blocked time as consumed by the domain if (inf->cputime + EXTRA_QUANTUM <= inf->slice) { +#ifdef SEDF_STATS inf->short_cont++; //we let the domain run in the current period +#endif } else { //we don't have a reasonable amount of time in our slice left => switch to burst mode @@ -851,8 +870,7 @@ static inline int should_switch(struct domain* cur, struct domain* other, s_time switch (get_run_type(cur)) { case DOMAIN_EDF: //check whether we need to make an earlier sched-decision - if ((PERIOD_BEGIN(other_inf) < schedule_data[other->processor].s_timer.expires) - && (other_inf->absdead < cur_inf->absdead)) + if ((PERIOD_BEGIN(other_inf) < schedule_data[other->processor].s_timer.expires)) return 1; else return 0; case DOMAIN_EXTRA_PEN: @@ -892,8 +910,9 @@ void sedf_wake(struct domain *d) { inf->absdead = now + inf->slice; //initial setup of the deadline PRINT(3,"waking up domain %i (deadl= %llu period= %llu now= %llu)\n",d->id,inf->absdead,inf->period,now); - +#ifdef SEDF_STATS inf->block_tot++; +#endif if (unlikely(now< PERIOD_BEGIN(inf))) { PRINT(4,"extratime unblock\n"); //this might happen, imagine unblocking in extra-time! @@ -917,7 +936,9 @@ void sedf_wake(struct domain *d) { if (now < inf->absdead) { PRINT(4,"short unblocking\n"); //short blocking +#ifdef SEDF_STATS inf->short_block_tot++; +#endif #if (UNBLOCK <= UNBLOCK_ATROPOS) unblock_short_vcons(inf, now); #elif (UNBLOCK == UNBLOCK_SHORT_RESUME) @@ -940,7 +961,9 @@ void sedf_wake(struct domain *d) { else { PRINT(4,"long unblocking\n"); //long blocking +#ifdef SEDF_STATS inf->long_block_tot++; +#endif //PRINT(3,"old=%llu ",inf->absdead); #if (UNBLOCK == UNBLOCK_ISOCHRONOUS_EDF) unblock_long_vcons(inf, now); @@ -973,18 +996,22 @@ void sedf_wake(struct domain *d) { __add_to_waitqueue_sort(d); PRINT(3,"added to waitq\n"); +#ifdef SEDF_STATS //do some statistics here... if (inf->absblock != 0) { inf->block_time_tot += now - inf->absblock; inf->penalty_time_tot += PERIOD_BEGIN(inf) + inf->cputime - inf->absblock; } +#endif //sanity check: make sure each extra-aware domain IS on the util-q! /*if (inf->extra & EXTRA_AWARE) { if (!extraq_on(d, EXTRA_UTIL_Q)) printf("sedf_wake: domain %i is extra-aware, but NOT on L1 extraq!\n",d->id); }*/ + //check whether the awakened task needs to get scheduled before the next sched. decision //and check, whether we are idling and this domain is extratime aware + //Save approximation: Always switch to scheduler! if (should_switch(schedule_data[d->processor].curr, d, now)){ #ifdef ADV_SCHED_HISTO adv_sched_hist_start(d->processor); @@ -1002,6 +1029,7 @@ static void sedf_dump_domain(struct domain *d) { DOM_INFO(d)->score[EXTRA_UTIL_Q], (DOM_INFO(d)->extra & EXTRA_AWARE) ? "yes" : "no", DOM_INFO(d)->extra_time_tot); if (d->cpu_time !=0) printf(" (%lu%)", (DOM_INFO(d)->extra_time_tot * 100) / d->cpu_time); +#ifdef SEDF_STATS if (DOM_INFO(d)->block_time_tot!=0) printf(" pen=%lu%", (DOM_INFO(d)->penalty_time_tot * 100) / DOM_INFO(d)->block_time_tot); if (DOM_INFO(d)->block_tot!=0) @@ -1012,6 +1040,7 @@ static void sedf_dump_domain(struct domain *d) { DOM_INFO(d)->long_block_tot, (DOM_INFO(d)->long_block_tot * 100) / DOM_INFO(d)->block_tot, (DOM_INFO(d)->block_time_tot) / DOM_INFO(d)->block_tot, (DOM_INFO(d)->penalty_time_tot) / DOM_INFO(d)->block_tot); +#endif printf("\n"); } From 0e2e29a5d07411344a4e4af1cdf96df1d439da8e Mon Sep 17 00:00:00 2001 From: "sd386@font.cl.cam.ac.uk" Date: Thu, 31 Mar 2005 23:09:27 +0000 Subject: [PATCH 08/54] bitkeeper revision 1.1159.170.108 (424c8327NU4_W8SWKkWXALwnntcq3g) mainly layout changes, but also minor bugfixes along my way --- xen/common/sched_sedf.c | 849 +++++++++++++++++++++++++--------------- 1 file changed, 540 insertions(+), 309 deletions(-) diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c index af8b9ba77b..ab1a0697e5 100644 --- a/xen/common/sched_sedf.c +++ b/xen/common/sched_sedf.c @@ -13,9 +13,9 @@ #include #include -//#include +/*#include */ -//verbosity settings +/*verbosity settings*/ #define SEDFLEVEL 0 #define PRINT(_f, _a...) \ if ((_f)<=SEDFLEVEL) printk(_a ); @@ -24,7 +24,7 @@ if ((_f)<=SEDFLEVEL) printk(_a ); #define SEDF_STATS #endif -//various ways of unblocking domains +/*various ways of unblocking domains*/ #define UNBLOCK_ISOCHRONOUS_EDF 1 #define UNBLOCK_EDF 2 #define UNBLOCK_ATROPOS 3 @@ -33,7 +33,7 @@ if ((_f)<=SEDFLEVEL) printk(_a ); #define UNBLOCK_EXTRA_SUPPORT 6 #define UNBLOCK UNBLOCK_EXTRA_SUPPORT -//various ways of treating extra-time +/*various ways of treating extra-time*/ #define EXTRA_OFF 1 #define EXTRA_ROUNDR 2 #define EXTRA_SLICE_WEIGHT 3 @@ -63,29 +63,35 @@ struct sedf_dom_info struct list_head list; struct list_head extralist[2]; - //Parameters for EDF - s_time_t period; //=(relative deadline) - s_time_t slice; //=worst case execution time + /*Parameters for EDF*/ + s_time_t period; /*=(relative deadline)*/ + s_time_t slice; /*=worst case execution time*/ - //Advaced Parameters - //Latency Scaling + /*Advaced Parameters*/ + /*Latency Scaling*/ s_time_t period_orig; s_time_t slice_orig; s_time_t latency; - short extra; //extra-time status of domain - short weight; //weights for "Scheduling for beginners/ lazy/ etc." ;) + /*extra-time status of domain*/ + short extra; + /*weights for "Scheduling for beginners/ lazy/ etc." ;)*/ + short weight; - //Bookkeeping + /*Bookkeeping*/ s_time_t absdead; s_time_t sched_start; s_time_t cputime; - s_time_t absblock; - s_time_t absunblock; //time the domain unblocked, used by burst mode to determine unblocking intervals - int score[2]; //scores for {util, block penalty}-weighted extratime distribution + s_time_t absblock; + + /*time the domain unblocked, used to determine unblocking intervals*/ + s_time_t absunblock; + + /*scores for {util, block penalty}-weighted extratime distribution*/ + int score[2]; s_time_t short_block_lost_tot; - //Statistics + /*Statistics*/ s_time_t extra_time_tot; #ifdef SEDF_STATS @@ -107,7 +113,7 @@ struct sedf_cpu_info { }; #define DOM_INFO(d) ((struct sedf_dom_info *)((d)->sched_priv)) -#define CPU_INFO(cpu) ((struct sedf_cpu_info *)schedule_data[cpu].sched_priv) +#define CPU_INFO(cpu) ((struct sedf_cpu_info *)schedule_data[cpu].sched_priv) #define LIST(d) (&DOM_INFO(d)->list) #define EXTRALIST(d,i) (&(DOM_INFO(d)->extralist[i])) #define RUNQ(cpu) (&CPU_INFO(cpu)->runnableq) @@ -125,7 +131,8 @@ static xmem_cache_t *dom_info_cache; static void sedf_dump_cpu_state(int i); static inline int extraq_on(struct domain *d, int i) { - return ((EXTRALIST(d,i)->next != NULL) && (EXTRALIST(d,i)->next != EXTRALIST(d,i))); + return ((EXTRALIST(d,i)->next != NULL) && + (EXTRALIST(d,i)->next != EXTRALIST(d,i))); } static inline void extraq_add_head(struct domain *d, int i) @@ -142,7 +149,8 @@ static inline void extraq_del(struct domain *d, int i) { struct list_head *list = EXTRALIST(d,i); /*if (!extraq_on(d,i)) { - PRINT(0,"extraq_del: domain %i is NOT on L%i extraq! HALTING\n",d->id,i); + PRINT(0,"extraq_del: domain %i is NOT on L%i extraq "\ + "HALTING\n",d->id,i); sedf_dump_cpu_state(0);(*((int*)0))++; }*/ PRINT(3, "Removing domain %i from L%i extraq\n", d->id,i); @@ -150,55 +158,67 @@ static inline void extraq_del(struct domain *d, int i) list->next = NULL; } -/* adds a domain to the queue of processes which are aware of extra time. List is sorted by score, - where a lower score means higher priority for an extra slice. It also updates the score, by simply subtracting - a fixed value from each entry, in order to avoid overflow. The algorithm works by simply charging each domain - that recieved extratime with an inverse of its weight. +/* adds a domain to the queue of processes which are aware of extra time. List + is sorted by score, where a lower score means higher priority for an extra + slice. It also updates the score, by simply subtracting a fixed value from + each entry, in order to avoid overflow. The algorithm works by simply + charging each domain that recieved extratime with an inverse of its weight. */ static inline void extraq_add_sort_update(struct domain *d, int i, int sub) { struct list_head *cur; struct sedf_dom_info *curinf; /*if (extraq_on(d,i)) { - PRINT(0,"extraq_add_sort_update: domain %i is already on L%i extraq! HALTING\n",d->id,i); + PRINT(0,"extraq_add_sort_update: domain %i is already on "\ + "L%i extraq! HALTING\n",d->id,i); sedf_dump_cpu_state(0);(*((int*)0))++; }*/ - PRINT(3, "Adding domain %i (score= %i, short_pen= %lli) to L%i extraq\n", d->id, - DOM_INFO(d)->score[i], DOM_INFO(d)->short_block_lost_tot, i); - //iterate through all elements to find our "hole" and on our way update all the other scores + PRINT(3, "Adding domain %i (score= %i, short_pen= %lli) to L%i "\ + "extraq\n", d->id, DOM_INFO(d)->score[i], + DOM_INFO(d)->short_block_lost_tot, i); + /*iterate through all elements to find our "hole" and on our way + update all the other scores*/ list_for_each(cur,EXTRAQ(d->processor,i)){ - curinf = list_entry(cur,struct sedf_dom_info,extralist[i]); + curinf = list_entry(cur,struct sedf_dom_info,extralist[i]); curinf->score[i] -= sub; if (DOM_INFO(d)->score[i] < curinf->score[i]) break; else - PRINT(4,"\tbehind domain %i (score= %i)\n", curinf->owner->id, curinf->score[i]); + PRINT(4,"\tbehind domain %i (score= %i)\n", + curinf->owner->id, curinf->score[i]); } - //cur now contains the element, before which we'll enq ueue + /*cur now contains the element, before which we'll enqueue*/ PRINT(3, "\tlist_add to %x\n", cur->prev); list_add(EXTRALIST(d,i),cur->prev); - //continue updating the extraq - if ((cur != EXTRAQ(d->processor,i)) && sub) - for (cur = cur->next; cur != EXTRAQ(d->processor,i); cur = cur-> next) { - curinf = list_entry(cur,struct sedf_dom_info,extralist[i]); + /*continue updating the extraq*/ + if ((cur != EXTRAQ(d->processor,i)) && sub) + for (cur = cur->next; cur != EXTRAQ(d->processor,i); + cur = cur-> next) { + curinf = list_entry(cur,struct sedf_dom_info, + extralist[i]); curinf->score[i] -= sub; - PRINT(4, "\tupdating domain %i (score= %llu)\n", curinf->owner->id, curinf->score[i]); + PRINT(4, "\tupdating domain %i (score= %llu)\n", + curinf->owner->id, curinf->score[i]); } } static inline void extraq_check(struct domain *d) { if (extraq_on(d, EXTRA_UTIL_Q)) { PRINT(2,"Dom %i is on extraQ\n",d->id); - if (!(DOM_INFO(d)->extra & EXTRA_AWARE) && !extra_runs(DOM_INFO(d))) { + if (!(DOM_INFO(d)->extra & EXTRA_AWARE) && + !extra_runs(DOM_INFO(d))) { extraq_del(d, EXTRA_UTIL_Q); PRINT(2,"Removed dom %i from L1 extraQ\n",d->id); } } else { PRINT(2,"Dom %i is NOT on L1 extraQ\n",d->id); - if ((DOM_INFO(d)->extra & EXTRA_AWARE) && domain_runnable(d)) { + if ((DOM_INFO(d)->extra & EXTRA_AWARE) && domain_runnable(d)) + { #if (EXTRA == EXTRA_ROUNDR) - extraq_add_tail(d, EXTRA_UTIL_Q); //Favour domains which got short unblocked - #elif (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) + /*Favour domains which got short unblocked*/ + extraq_add_tail(d, EXTRA_UTIL_Q); + #elif (EXTRA == EXTRA_SLICE_WEIGHT || \ + EXTRA == EXTRA_BLOCK_WEIGHT) extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); #elif ; @@ -210,52 +230,61 @@ static inline void extraq_check(struct domain *d) { static inline void __del_from_queue(struct domain *d) { struct list_head *list = LIST(d); - PRINT(3,"Removing domain %i (bop= %llu) from runq/waitq\n",d->id,PERIOD_BEGIN(DOM_INFO(d))); + PRINT(3,"Removing domain %i (bop= %llu) from runq/waitq\n", d->id, + PERIOD_BEGIN(DOM_INFO(d))); list_del(list); list->next = NULL; } -/* adds a domain to the queue of processes which wait for the beginning of the next period - * this list is therefore sortet by this time, which is simply absol. deadline - period +/* adds a domain to the queue of processes which wait for the beginning of the + next period; this list is therefore sortet by this time, which is simply + absol. deadline - period */ static inline void __add_to_waitqueue_sort(struct domain *d) { struct list_head *cur; struct sedf_dom_info *curinf; - PRINT(3,"Adding domain %i (bop= %llu) to waitq\n",d->id,PERIOD_BEGIN(DOM_INFO(d))); - //iterate through all elements to find our "hole" + PRINT(3,"Adding domain %i (bop= %llu) to waitq\n", d->id, + PERIOD_BEGIN(DOM_INFO(d))); + + /*iterate through all elements to find our "hole"*/ list_for_each(cur,WAITQ(d->processor)){ curinf = list_entry(cur,struct sedf_dom_info,list); if (PERIOD_BEGIN(DOM_INFO(d)) < PERIOD_BEGIN(curinf)) break; else - PRINT(4,"\tbehind domain %i (bop= %llu)\n",curinf->owner->id,PERIOD_BEGIN(curinf)); + PRINT(4,"\tbehind domain %i (bop= %llu)\n", + curinf->owner->id, PERIOD_BEGIN(curinf)); } - //cur now contains the element, before which we'll enqueue + /*cur now contains the element, before which we'll enqueue*/ PRINT(3,"\tlist_add to %x\n",cur->prev); list_add(LIST(d),cur->prev); } -/* adds a domain to the queue of processes which have started their current period and are - * runnable (i.e. not blocked, dieing,...). The first element on this list is running on the processor, - * if the list is empty the idle task will run. As we are implementing EDF, this list is sorted by - * deadlines. +/* adds a domain to the queue of processes which have started their current + period and are runnable (i.e. not blocked, dieing,...). The first element + on this list is running on the processor, if the list is empty the idle + task will run. As we are implementing EDF, this list is sorted by deadlines. */ static inline void __add_to_runqueue_sort(struct domain *d) { struct list_head *cur; struct sedf_dom_info *curinf; - PRINT(3,"Adding domain %i (deadl= %llu) to runq\n",d->id,DOM_INFO(d)->absdead); - //iterate through all elements to find our "hole" - list_for_each(cur,RUNQ(d->processor)){ - curinf = list_entry(cur,struct sedf_dom_info,list); + PRINT(3,"Adding domain %i (deadl= %llu) to runq\n", d->id, + DOM_INFO(d)->absdead); + + /*iterate through all elements to find our "hole"*/ + list_for_each(cur, RUNQ(d->processor)) { + curinf = list_entry(cur, struct sedf_dom_info, list); if (DOM_INFO(d)->absdead < curinf->absdead) break; else - PRINT(4,"\tbehind domain %i (deadl= %llu)\n",curinf->owner->id,curinf->absdead); + PRINT(4,"\tbehind domain %i (deadl= %llu)\n", + curinf->owner->id, curinf->absdead); } - //cur now contains the element, before which we'll enqueue + + /*cur now contains the element, before which we'll enqueue*/ PRINT(3,"\tlist_add to %x\n",cur->prev); list_add(LIST(d),cur->prev); @@ -270,7 +299,8 @@ static int sedf_init_scheduler() { PRINT(2,"sedf_init_scheduler was called\n"); for ( i = 0; i < NR_CPUS; i++ ) { - schedule_data[i].sched_priv = xmalloc(sizeof(struct sedf_cpu_info)); + schedule_data[i].sched_priv = + xmalloc(sizeof(struct sedf_cpu_info)); if ( schedule_data[i].sched_priv == NULL ) return -1; INIT_LIST_HEAD(WAITQ(i)); @@ -278,14 +308,15 @@ static int sedf_init_scheduler() { INIT_LIST_HEAD(EXTRAQ(i,EXTRA_PEN_Q)); INIT_LIST_HEAD(EXTRAQ(i,EXTRA_UTIL_Q)); } - dom_info_cache = xmem_cache_create("SEDF dom info", sizeof(struct sedf_dom_info), 0, 0, 0, NULL); + dom_info_cache = xmem_cache_create("SEDF dom info", + sizeof(struct sedf_dom_info), 0, 0, 0, NULL); if ( dom_info_cache == NULL ) { printk("Could not allocate SLAB cache.\n"); return -1; } - return 0; + return 0; } /* Allocates memory for per domain private scheduling data*/ @@ -300,21 +331,20 @@ static int sedf_alloc_task(struct domain *d) { /* Setup the sedf_dom_info */ static void sedf_add_task(struct domain *d) { - //s_time_t now=NOW(); struct sedf_dom_info *inf=DOM_INFO(d); inf->owner = d; PRINT(2,"sedf_add_task was called, domain-id %i\n",d->id); if (d->id==0) { - //set dom0 to something useful to boot the machine + /*set dom0 to something useful to boot the machine*/ inf->period = MILLISECS(20); inf->slice = MILLISECS(15); inf->latency = 0; inf->absdead = 0; - inf->extra = EXTRA_NONE;//EXTRA_AWARE; + inf->extra = EXTRA_NONE;/*EXTRA_AWARE; */ } else { - //other domains run in best effort mode + /*other domains run in best effort mode*/ inf->period = MILLISECS(20); inf->slice = 0; inf->absdead = 0; @@ -344,50 +374,64 @@ static int sedf_init_idle_task(struct domain *d) { sedf_add_task(d); DOM_INFO(d)->absdead = 0; set_bit(DF_RUNNING, &d->flags); - //the idle task doesn't have to turn up on any list... + /*the idle task doesn't have to turn up on any list...*/ return 0; } /* handles the rescheduling, bookkeeping of domains running in their realtime-time :)*/ static inline void desched_edf_dom (s_time_t now, struct domain* d) { struct sedf_dom_info* inf = DOM_INFO(d); + /*current domain is running in real time mode*/ - //current domain is running in real time mode - inf->cputime += now - inf->sched_start; //update the domains cputime - if ((inf->cputime < inf->slice) && domain_runnable(d)) //scheduling decisions, which don't remove the running domain from the runq - return; //there is nothing to do with the running task + /*update the domains cputime*/ + inf->cputime += now - inf->sched_start; + + /*scheduling decisions, which don't remove the running domain + from the runq*/ + if ((inf->cputime < inf->slice) && domain_runnable(d)) + return; __del_from_queue(d); /*if (__task_on_queue(current)) { - PRINT(0,"domain %i was removed but still on run/waitq => HALT\n",current->id); + PRINT(0,"domain %i was removed but still on run/waitq => "\ + "HALT\n",current->id); sedf_dump_cpu_state(0);(*((int*)0))++; }*/ - //manage bookkeeping (i.e. calculate next deadline, memorize overun time of slice) of finished domains + /*manage bookkeeping (i.e. calculate next deadline, + memorize overun-time of slice) of finished domains*/ if (inf->cputime >= inf->slice) { inf->cputime -= inf->slice; if (inf->period < inf->period_orig) { - //this domain runs in latency scaling or burst mode + /*this domain runs in latency scaling or burst mode*/ #if (UNBLOCK == UNBLOCK_BURST) if (now - inf->absunblock >= 2 * inf->period) #endif { inf->period *= 2; inf->slice *= 2; - if ((inf->period > inf->period_orig) || (inf->slice > inf->slice_orig)) { - inf->period = inf->period_orig; //update the domains cputime + if ((inf->period > inf->period_orig) || + (inf->slice > inf->slice_orig)) { + /*reset slice & period*/ + inf->period = inf->period_orig; inf->slice = inf->slice_orig; } } } - inf->absdead += inf->period; //set next deadline + /*set next deadline*/ + inf->absdead += inf->period; } - //if (inf->absdeadid,now,inf->absdead); - if (domain_runnable(d)) //add a runnable domain to the waitqueue + /*if (inf->absdeadid, now, + inf->absdead);*/ + + /*add a runnable domain to the waitqueue*/ + if (domain_runnable(d)) __add_to_waitqueue_sort(d); else { - inf->absblock = now; //we have a blocked realtime task + /*we have a blocked realtime task*/ + inf->absblock = now; #if (EXTRA > EXTRA_OFF) #if (EXTRA == EXTRA_BLOCK_WEIGHT) if (extraq_on(d,EXTRA_PEN_Q)) extraq_del(d,EXTRA_PEN_Q); @@ -398,15 +442,17 @@ static inline void desched_edf_dom (s_time_t now, struct domain* d) { } /* Update all elements on the queues */ -static inline void update_queues(s_time_t now, struct list_head* runq, struct list_head* waitq) { +static inline void update_queues( +s_time_t now, struct list_head* runq, struct list_head* waitq) { struct list_head *cur,*tmp; struct sedf_dom_info *curinf; PRINT(3,"Updating waitq..\n"); - //check for the first elements of the waitqueue, whether their next period has already started - list_for_each_safe(cur,tmp,waitq) { - curinf = list_entry(cur,struct sedf_dom_info,list); - PRINT(4,"\tLooking @ dom %i\n",curinf->owner->id); + /*check for the first elements of the waitqueue, whether their + next period has already started*/ + list_for_each_safe(cur, tmp, waitq) { + curinf = list_entry(cur, struct sedf_dom_info, list); + PRINT(4,"\tLooking @ dom %i\n", curinf->owner->id); if (PERIOD_BEGIN(curinf) <= now) { __del_from_queue(curinf->owner); __add_to_runqueue_sort(curinf->owner); @@ -416,29 +462,51 @@ static inline void update_queues(s_time_t now, struct list_head* runq, struct li } PRINT(3,"Updating runq..\n"); - //process the runq, find domains that are on the runqueue which shouldn't be there - list_for_each_safe(cur,tmp,runq) { + /*process the runq, find domains that are on + the runqueue which shouldn't be there*/ + list_for_each_safe(cur, tmp, runq) { curinf = list_entry(cur,struct sedf_dom_info,list); - PRINT(4,"\tLooking @ dom %i\n",curinf->owner->id); - if (unlikely(curinf->slice == 0)) { //ignore domains with empty slice - PRINT(4,"\tUpdating zero-slice domain %i\n",curinf->owner->id); + PRINT(4,"\tLooking @ dom %i\n", curinf->owner->id); + if (unlikely(curinf->slice == 0)) { + /*ignore domains with empty slice*/ + PRINT(4,"\tUpdating zero-slice domain %i\n", + curinf->owner->id); __del_from_queue(curinf->owner); - curinf->absdead += curinf->period; //move to their next period - __add_to_waitqueue_sort(curinf->owner); //and put them back into the queue + + /*move them to their next period*/ + curinf->absdead += curinf->period; + /*and put them back into the queue*/ + __add_to_waitqueue_sort(curinf->owner); } else { - if (unlikely((curinf->absdead < now) || (curinf->cputime > curinf->slice))) { - //we missed the deadline or the slice was already finished... might hapen because of dom_adj. - //printk("Ouch! Domain %i missed deadline %llu\n",curinf->owner->id,curinf->absdead); - PRINT(4,"\tDomain %i exceeded it's deadline/slice (%llu / %llu) now: %llu cputime: %llu\n", - curinf->owner->id, curinf->absdead, curinf->slice, now, curinf->cputime); + if (unlikely((curinf->absdead < now) || + (curinf->cputime > curinf->slice))) { + /*we missed the deadline or the slice was + already finished... might hapen because + of dom_adj.*/ + PRINT(4,"\tDomain %i exceeded it's deadline/"\ + "slice (%llu / %llu) now: %llu "\ + "cputime: %llu\n", curinf->owner->id, + curinf->absdead, curinf->slice, now, + curinf->cputime); __del_from_queue(curinf->owner); - curinf->absdead += curinf->period; //common case: we miss one period! + /*common case: we miss one period!*/ + curinf->absdead += curinf->period; + + /*if we are still behind: modulo arithmetic, + force deadline to be in future and + aligned to period borders!*/ if (unlikely(curinf->absdead < now)) - curinf->absdead += DIV_UP(now - curinf->absdead, curinf->period) * curinf->period; - //force start of period to be in future and aligned to period borders! - curinf->cputime = 0; //give a fresh slice - __add_to_runqueue_sort(curinf->owner); + curinf->absdead += + DIV_UP(now - curinf->absdead, + curinf->period) * curinf->period; + + /*give a fresh slice*/ + curinf->cputime = 0; + if (PERIOD_BEGIN(curinf) < now) + __add_to_waitqueue_sort(curinf->owner); + else + __add_to_runqueue_sort(curinf->owner); } else break; @@ -448,10 +516,12 @@ static inline void update_queues(s_time_t now, struct list_head* runq, struct li } #if (EXTRA > EXTRA_OFF) -/*removes a domain from the head of the according extraQ and requeues it at a specified position: - round-robin extratime: end of extraQ - weighted ext.: insert in sorted list by score - if the domain is blocked / has regained its short-block-loss time it is not put on any queue*/ +/* removes a domain from the head of the according extraQ and + requeues it at a specified position: + round-robin extratime: end of extraQ + weighted ext.: insert in sorted list by score + if the domain is blocked / has regained its short-block-loss + time it is not put on any queue */ static inline void desched_extra_dom(s_time_t now, struct domain* d) { struct sedf_dom_info *inf = DOM_INFO(d); int i = extra_get_cur_q(inf); @@ -459,66 +529,92 @@ static inline void desched_extra_dom(s_time_t now, struct domain* d) { #if (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) unsigned long oldscore; #endif - - inf->extra &= ~(EXTRA_RUN_PEN | EXTRA_RUN_UTIL); //unset all running flags - inf->cputime = 0; //fresh slice for the next run - inf->extra_time_tot += now - inf->sched_start; //accumulate total extratime - extraq_del(d, i); //remove extradomain from head of the queue + + /*unset all running flags*/ + inf->extra &= ~(EXTRA_RUN_PEN | EXTRA_RUN_UTIL); + /*fresh slice for the next run*/ + inf->cputime = 0; + /*accumulate total extratime*/ + inf->extra_time_tot += now - inf->sched_start; + /*remove extradomain from head of the queue*/ + extraq_del(d, i); #if (EXTRA == EXTRA_ROUNDR) if (domain_runnable(d)) - extraq_add_tail(d, EXTRA_UTIL_Q); //and add to the tail if it is runnable => round-robin + /*add to the tail if it is runnable => round-robin*/ + extraq_add_tail(d, EXTRA_UTIL_Q); #elif (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) - oldscore = inf->score[i]; //update the score + /*update the score*/ + oldscore = inf->score[i]; #if (EXTRA == EXTRA_BLOCK_WEIGHT) if (i == EXTRA_PEN_Q) { - //domain was running in L0 extraq - //inf->short_block_lost_tot -= EXTRA_QUANTUM; //reduce block lost, probably more sophistication here! + /*domain was running in L0 extraq*/ + /*reduce block lost, probably more sophistication here!*/ + /*inf->short_block_lost_tot -= EXTRA_QUANTUM;*/ inf->short_block_lost_tot -= now - inf->sched_start; - PRINT(3,"Domain %i: Short_block_lost: %lli\n",inf->owner->id,inf->short_block_lost_tot); + PRINT(3,"Domain %i: Short_block_lost: %lli\n", + inf->owner->id, inf->short_block_lost_tot); if (inf->short_block_lost_tot <= 0) { PRINT(4,"Domain %i compensated short block loss!\n"); - inf->short_block_lost_tot = 0; //we have (over-)compensated our block penalty - inf->extra &= ~EXTRA_WANT_PEN_Q; //we don't want a place on the penalty queue anymore! - return; //do not add us on this block extraq again! + /*we have (over-)compensated our block penalty*/ + inf->short_block_lost_tot = 0; + /*we don't want a place on the penalty queue anymore!*/ + inf->extra &= ~EXTRA_WANT_PEN_Q; + /*do not add us on this block extraq again!*/ + return; } - //we have to go again for another try in the block-extraq - inf->score[EXTRA_PEN_Q] = (inf->period << 10) / inf->short_block_lost_tot; + /*we have to go again for another try in the block-extraq, + the score is not used incremantally here, as this is + already done by recalculating the block_lost*/ + inf->score[EXTRA_PEN_Q] = (inf->period << 10) / + inf->short_block_lost_tot; oldscore = 0; } else #endif { - //domain was running in L1 extraq => score is inverse of utilization and is used somewhat incremental! + /*domain was running in L1 extraq => score is inverse of + utilization and is used somewhat incremental!*/ if (inf->slice) - inf->score[EXTRA_UTIL_Q] = (inf->period << 10) / inf->slice;//use fixed point arithmetic with 10 bits + /*NB: use fixed point arithmetic with 10 bits*/ + inf->score[EXTRA_UTIL_Q] = (inf->period << 10) / + inf->slice; else + /*set best effort domains to the maximum value*/ inf->score[EXTRA_UTIL_Q] = 2^10; } if (domain_runnable(d)) - extraq_add_sort_update(d, i, oldscore); //add according to score: weighted round robin + /*add according to score: weighted round robin*/ + extraq_add_sort_update(d, i, oldscore); else { inf->absblock = now; /*if (!__task_on_queue(d)) - printf("Oops... We attempt to remove d %i from the waitq, but it is not on :(\n",d->id);*/ - __del_from_queue(d); //also remove this blocked domain from the waitq! - //make sure that we remove a blocked domain from the other extraq aswell (this caused hours of debugging!) + printf("Oops... We attempt to remove d %i from the "\ + "waitq, but it is not on :(\n",d->id);*/ + /*remove this blocked domain from the waitq!*/ + __del_from_queue(d); + /*make sure that we remove a blocked domain from the other + extraq aswell (this caused hours of debugging!)*/ #if (EXTRA == EXTRA_BLOCK_WEIGHT) if (i == EXTRA_PEN_Q) { - if (extraq_on(d,EXTRA_UTIL_Q)) extraq_del(d,EXTRA_UTIL_Q); + if (extraq_on(d,EXTRA_UTIL_Q)) + extraq_del(d,EXTRA_UTIL_Q); } else { - if (extraq_on(d,EXTRA_PEN_Q)) extraq_del(d,EXTRA_PEN_Q); + if (extraq_on(d,EXTRA_PEN_Q)) + extraq_del(d,EXTRA_PEN_Q); } #endif } #endif /*if (!domain_runnable(d)) { if (extraq_on(d,EXTRA_UTIL_Q)) { - PRINT(0,"domain %i is blocked but still on L1 xq=> HALT\n",d->id); + PRINT(0,"domain %i is blocked but still on L1 "\ + "xq=> HALT\n",d->id); sedf_dump_cpu_state(0);(*((int*)0))++; } if (__task_on_queue(d)) { - PRINT(0,"domain %i is blocked but still on run/waitq=> HALT\n",d->id); + PRINT(0,"domain %i is blocked but still on run/waitq"\ + "=> HALT\n",d->id); sedf_dump_cpu_state(0);(*((int*)0))++; } }*/ @@ -526,27 +622,31 @@ static inline void desched_extra_dom(s_time_t now, struct domain* d) { #endif -static inline task_slice_t sedf_do_extra_schedule(s_time_t now, s_time_t end_xt, struct list_head *extraq[], int cpu) { +static inline task_slice_t sedf_do_extra_schedule +(s_time_t now, s_time_t end_xt, struct list_head *extraq[], int cpu) { task_slice_t ret; struct sedf_dom_info *runinf; - //TODO write this stuff as a loop if (end_xt - now < EXTRA_QUANTUM) goto return_idle; - +#if (EXTRA == EXTRA_BLOCK_WEIGHT) if (!list_empty(extraq[EXTRA_PEN_Q])) { - //we still have elements on the level 0 extraq => let those run first! - runinf = list_entry(extraq[EXTRA_PEN_Q]->next, struct sedf_dom_info, extralist[EXTRA_PEN_Q]); + /*we still have elements on the level 0 extraq + => let those run first!*/ + runinf = list_entry(extraq[EXTRA_PEN_Q]->next, + struct sedf_dom_info, extralist[EXTRA_PEN_Q]); runinf->extra |= EXTRA_RUN_PEN; ret.task = runinf->owner; ret.time = EXTRA_QUANTUM; #ifdef SEDF_STATS runinf->pen_extra_slices++; #endif - } - else if (!list_empty(extraq[EXTRA_UTIL_Q])) { - //use elements from the normal extraqueue - runinf = list_entry(extraq[EXTRA_UTIL_Q]->next,struct sedf_dom_info,extralist[EXTRA_UTIL_Q]); + } else +#endif + if (!list_empty(extraq[EXTRA_UTIL_Q])) { + /*use elements from the normal extraqueue*/ + runinf = list_entry(extraq[EXTRA_UTIL_Q]->next, + struct sedf_dom_info,extralist[EXTRA_UTIL_Q]); runinf->extra |= EXTRA_RUN_UTIL; ret.task = runinf->owner; ret.time = EXTRA_QUANTUM; @@ -562,10 +662,10 @@ return_idle: return ret; } /* Main scheduling function - * Reasons for calling this function are: - * -timeslice for the current period used up - * -domain on waitqueue has started it's period - * -and various others ;) in general: determine which domain to run next*/ + Reasons for calling this function are: + -timeslice for the current period used up + -domain on waitqueue has started it's period + -and various others ;) in general: determine which domain to run next*/ static task_slice_t sedf_do_schedule(s_time_t now) { int cpu = current->processor; @@ -573,48 +673,56 @@ static task_slice_t sedf_do_schedule(s_time_t now) struct list_head *waitq = WAITQ(cpu); #if (EXTRA > EXTRA_OFF) struct sedf_dom_info *inf = DOM_INFO(current); - struct list_head *extraq[] = {EXTRAQ(cpu,EXTRA_PEN_Q),EXTRAQ(cpu, EXTRA_UTIL_Q)}; + struct list_head *extraq[] = {EXTRAQ(cpu,EXTRA_PEN_Q), + EXTRAQ(cpu, EXTRA_UTIL_Q)}; #endif task_slice_t ret; - //int i = 0; - //idle tasks don't need any of the following stuf + /*int i = 0;*/ + /*idle tasks don't need any of the following stuf*/ if (is_idle_task(current)) - goto check_waitq; //idle task doesn't get moved around on any queues + goto check_waitq; #if (EXTRA > EXTRA_OFF) if (unlikely(extra_runs(inf))) { - //i=1; - desched_extra_dom(now, current); //special treatment of domains running in extra time + /*i=1;*/ + /*special treatment of domains running in extra time*/ + desched_extra_dom(now, current); } else #endif { - //i=2; + /*i=2;*/ desched_edf_dom(now, current); } /*if (!domain_runnable(current)) { if (extraq_on(current,EXTRA_UTIL_Q)) { - PRINT(0,"domain %i is blocked but still on L1 xq branch %i=> HALT\n",current->id,i); + PRINT(0,"domain %i is blocked but still on L1 xq"\ + " branch %i=> HALT\n", current->id, i); sedf_dump_cpu_state(0);(*((int*)0))++; } if (__task_on_queue(current)) { - PRINT(0,"domain %i is blocked but still on run/waitq branch %i=> HALT\n",current->id,i); + PRINT(0,"domain %i is blocked but still on run/waitq"\ + " branch %i=> HALT\n",current->id,i); sedf_dump_cpu_state(0);(*((int*)0))++; } }*/ check_waitq: update_queues(now, runq, waitq); - //now simply pick the first domain from the runqueue + /*now simply pick the first domain from the runqueue*/ struct sedf_dom_info *runinf, *waitinf; if (!list_empty(runq)) { runinf = list_entry(runq->next,struct sedf_dom_info,list); ret.task = runinf->owner; if (!list_empty(waitq)) { - //rerun scheduler, when scheduled domain reaches it's end of slice or the first domain from the waitqueue gets ready - waitinf = list_entry(waitq->next,struct sedf_dom_info,list); - ret.time = MIN(now + runinf->slice - runinf->cputime,PERIOD_BEGIN(waitinf)) - now; + waitinf = list_entry(waitq->next, + struct sedf_dom_info,list); + /*rerun scheduler, when scheduled domain reaches it's + end of slice or the first domain from the waitqueue + gets ready*/ + ret.time = MIN(now + runinf->slice - runinf->cputime, + PERIOD_BEGIN(waitinf)) - now; } else { ret.time = runinf->slice - runinf->cputime; @@ -624,25 +732,30 @@ check_waitq: if (!list_empty(waitq)) { waitinf = list_entry(waitq->next,struct sedf_dom_info,list); - //we could not find any suitable domain => look for domains that are aware of extratime + /*we could not find any suitable domain + => look for domains that are aware of extratime*/ #if (EXTRA > EXTRA_OFF) - ret = sedf_do_extra_schedule(now, PERIOD_BEGIN(waitinf), extraq, cpu); + ret = sedf_do_extra_schedule(now, PERIOD_BEGIN(waitinf), + extraq, cpu); #else ret.task = IDLETASK(cpu); ret.time = PERIOD_BEGIN(waitinf) - now; #endif } else { - //this could probably never happen, but one never knows... - //it can... imagine a second CPU, which is pure scifi ATM, but one never knows ;) + /*this could probably never happen, but one never knows...*/ + /*it can... imagine a second CPU, which is pure scifi ATM, + but one never knows ;)*/ ret.task = IDLETASK(cpu); ret.time = SECONDS(1); } sched_done: - //TODO: Do something USEFUL when this happens and find out, why it still can happen!!! + /*TODO: Do something USEFUL when this happens and find out, why it + still can happen!!!*/ if (ret.time<0) { - printk("Ouch! We are seriously BEHIND schedule! %lli\n",ret.time); + printk("Ouch! We are seriously BEHIND schedule! %lli\n", + ret.time); ret.time = EXTRA_QUANTUM; } DOM_INFO(ret.task)->sched_start=now; @@ -671,13 +784,14 @@ static void sedf_sleep(struct domain *d) { } } -/* This function wakes ifup a domain, i.e. moves them into the waitqueue +/* This function wakes up a domain, i.e. moves them into the waitqueue * things to mention are: admission control is taking place nowhere at * the moment, so we can't be sure, whether it is safe to wake the domain * up at all. Anyway, even if it is safe (total cpu usage <=100%) there are * some considerations on when to allow the domain to wake up and have it's * first deadline... - * I detected 3 cases, which could describe the possible behaviour of the scheduler, + * I detected 3 cases, which could describe the possible behaviour of the + * scheduler, * and I'll try to make them more clear: * * 1. Very conservative @@ -692,150 +806,221 @@ static void sedf_sleep(struct domain *d) { * -deadlines keep occuring isochronous * * 2. Conservative Part 1: Short Unblocking - * -when a domain unblocks in the same period as it was blocked it unblocks and - * may consume the rest of it's original time-slice minus the time it was blocked + * -when a domain unblocks in the same period as it was blocked it + * unblocks and may consume the rest of it's original time-slice minus + * the time it was blocked * (assume period=9, slice=5) * * DRB_UR___DRRRRR___D... * - * -this also doesn't disturb scheduling, but might lead to the fact, that the domain - * can't finish it's workload in the period - * -in addition to that the domain can be treated prioritised when extratime is available - * + * -this also doesn't disturb scheduling, but might lead to the fact, that + * the domain can't finish it's workload in the period + * -in addition to that the domain can be treated prioritised when + * extratime is available + * -addition: experiments hve shown that this may have a HUGE impact on + * performance of other domains, becaus it can lead to excessive context + * switches + * Part2: Long Unblocking * Part 2a - * -it is obvious that such behaviour, applied when then unblocking is happening in - * later periods, works fine aswell - * -the domain is treated as if it would have been running since the start of its new period + * -it is obvious that such accounting of block time, applied when + * unblocking is happening in later periods, works fine aswell + * -the domain is treated as if it would have been running since the start + * of its new period * * DRB______D___UR___D... * * Part 2b - * -if one needs the full slice in the next period, it is necessary to treat the unblocking - * time as the start of the new period, i.e. move the deadline further back (later) - * -this doesn't disturb scheduling as well, because for EDF periods can be treated as minimal - * inter-release times and scheduling stays correct, when deadlines are kept relative to the time - * the process unblocks + * -if one needs the full slice in the next period, it is necessary to + * treat the unblocking time as the start of the new period, i.e. move + * the deadline further back (later) + * -this doesn't disturb scheduling as well, because for EDF periods can + * be treated as minimal inter-release times and scheduling stays + * correct, when deadlines are kept relative to the time the process + * unblocks * - * DRB______D___URRRR___D... - * (D) + * DRB______D___URRRR___D... + * (D) <- old deadline was here * -problem: deadlines don't occur isochronous anymore * Part 2c (Improved Atropos design) - * -when a domain unblocks it is given a very short period (=latency hint) and slice length scaled - * accordingly + * -when a domain unblocks it is given a very short period (=latency hint) + * and slice length scaled accordingly * -both rise again to the original value (e.g. get doubled every period) * * 3. Unconservative (i.e. incorrect) - * -to boost the performance of I/O dependent domains it would be possible to put the domain into - * the runnable queue immediately, and let it run for the remainder of the slice of the current period + * -to boost the performance of I/O dependent domains it would be possible + * to put the domain into the runnable queue immediately, and let it run + * for the remainder of the slice of the current period * (or even worse: allocate a new full slice for the domain) - * -either behaviour can lead to missed deadlines in other domains as opposed to approaches 1,2a,2b + * -either behaviour can lead to missed deadlines in other domains as + * opposed to approaches 1,2a,2b */ -static inline void unblock_short_vcons(struct sedf_dom_info* inf, s_time_t now) { +static inline void unblock_short_vcons +(struct sedf_dom_info* inf, s_time_t now) { inf->absdead += inf->period; inf->cputime = 0; } -static inline void unblock_short_cons(struct sedf_dom_info* inf, s_time_t now) { - inf->cputime += now - inf->absblock; //treat blocked time as consumed by the domain +static inline void unblock_short_cons(struct sedf_dom_info* inf, s_time_t now) +{ + /*treat blocked time as consumed by the domain*/ + inf->cputime += now - inf->absblock; if (inf->cputime + EXTRA_QUANTUM > inf->slice) { - //we don't have a reasonable amount of time in our slice left :( - unblock_short_vcons(inf, now); //start in next period! + /*we don't have a reasonable amount of time in + our slice left :( => start in next period!*/ + unblock_short_vcons(inf, now); } #ifdef SEDF_STATS else - inf->short_cont++; //we let the domain run in the current period + inf->short_cont++; #endif } -static inline void unblock_short_extra_support(struct sedf_dom_info* inf, s_time_t now) { - /*this unblocking scheme tries to support the domain, by assigning it a priority in extratime distribution - according to the loss of time in this slice due to blocking*/ +static inline void unblock_short_extra_support (struct sedf_dom_info* inf, + s_time_t now) { + /*this unblocking scheme tries to support the domain, by assigning it + a priority in extratime distribution according to the loss of time + in this slice due to blocking*/ s_time_t pen; - inf->absdead += inf->period; //no more realtime execution in this period! + + /*no more realtime execution in this period!*/ + inf->absdead += inf->period; if (likely(inf->absblock)) { - //inf->cputime += now - inf->absblock; //treat blocked time as consumed by the domain + //treat blocked time as consumed by the domain*/ + /*inf->cputime += now - inf->absblock;*/ pen = (inf->slice - inf->cputime); if (pen < 0) pen = 0; - //inf->short_block_lost_tot += pen; //calc. penalty because of that - inf->short_block_lost_tot = pen; //set penalty to the current value - //not sure which one is better.. but seems to work well... + /*accumulate all penalties over the periods*/ + /*inf->short_block_lost_tot += pen;*/ + /*set penalty to the current value*/ + inf->short_block_lost_tot = pen; + /*not sure which one is better.. but seems to work well...*/ if (inf->short_block_lost_tot) { - inf->score[0] = (inf->period << 10) / inf->short_block_lost_tot; + inf->score[0] = (inf->period << 10) / + inf->short_block_lost_tot; #ifdef SEDF_STATS inf->pen_extra_blocks++; #endif if (extraq_on(inf->owner, EXTRA_PEN_Q)) - extraq_del(inf->owner, EXTRA_PEN_Q); //remove domain for possible resorting! - else //remember that we want to be on the penalty queue, - inf->extra |= EXTRA_WANT_PEN_Q; //so that we can continue when we (un-)blocked in pen-ext. - extraq_add_sort_update(inf->owner, EXTRA_PEN_Q, 0); //(re-)add domain to the penalty extraq + /*remove domain for possible resorting!*/ + extraq_del(inf->owner, EXTRA_PEN_Q); + else + /*remember that we want to be on the penalty q + so that we can continue when we (un-)block + in penalty-extratime*/ + inf->extra |= EXTRA_WANT_PEN_Q; + + /*(re-)add domain to the penalty extraq*/ + extraq_add_sort_update(inf->owner, + EXTRA_PEN_Q, 0); } } - inf->cputime = 0; //give it a fresh slice in the next period! + /*give it a fresh slice in the next period!*/ + inf->cputime = 0; } -static inline void unblock_long_vcons(struct sedf_dom_info* inf, s_time_t now) { - inf->absdead += ((now - inf->absdead) / inf->period + 1) * inf->period; //very conservative +static inline void unblock_long_vcons(struct sedf_dom_info* inf, s_time_t now) +{ + /* align to next future period */ + inf->absdead += ((now - inf->absdead) / inf->period + 1) + * inf->period; inf->cputime = 0; } -static inline void unblock_long_cons_a(struct sedf_dom_info* inf, s_time_t now) { - inf->cputime = (now - inf->absdead) % inf->period; //treat the time the domain was blocked in the CURRENT - //period as consumed by the domain +static inline void unblock_long_cons_a (struct sedf_dom_info* inf, + s_time_t now) { + /*treat the time the domain was blocked in the + CURRENT period as consumed by the domain*/ + inf->cputime = (now - inf->absdead) % inf->period; if (inf->cputime + EXTRA_QUANTUM > inf->slice) { - //we don't have a reasonable amount of time in our slice left :( - unblock_long_vcons(inf, now); //start in next period! + /*we don't have a reasonable amount of time in our slice + left :( => start in next period!*/ + unblock_long_vcons(inf, now); } } static inline void unblock_long_cons_b(struct sedf_dom_info* inf,s_time_t now) { - inf->absdead = now + inf->period; //Conservative 2b + /*Conservative 2b*/ + /*Treat the unblocking time as a start of a new period */ + inf->absdead = now + inf->period; inf->cputime = 0; } static inline void unblock_long_cons_c(struct sedf_dom_info* inf,s_time_t now) { if (likely(inf->latency)) { - //scale the slice and period accordingly to the latency hint - inf->period = inf->latency; //reduce period temporarily to the latency hint - ASSERT((inf->period < ULONG_MAX) && (inf->slice_orig < ULONG_MAX)); //this results in max. 4s slice/period length - inf->slice = (inf->period * inf->slice_orig) / inf->period_orig; //scale slice accordingly, so that utilisation stays the same + /*scale the slice and period accordingly to the latency hint*/ + /*reduce period temporarily to the latency hint*/ + inf->period = inf->latency; + /*this results in max. 4s slice/period length*/ + ASSERT((inf->period < ULONG_MAX) + && (inf->slice_orig < ULONG_MAX)); + /*scale slice accordingly, so that utilisation stays the same*/ + inf->slice = (inf->period * inf->slice_orig) + / inf->period_orig; + inf->absdead = now + inf->period; + inf->cputime = 0; } else { - //we don't have a latency hint.. use some other technique + /*we don't have a latency hint.. use some other technique*/ unblock_long_cons_b(inf, now); } } -//a new idea of dealing with short blocks: burst period scaling -static inline void unblock_short_burst(struct sedf_dom_info* inf, s_time_t now) { - inf->cputime += now - inf->absblock; //treat blocked time as consumed by the domain +/*a new idea of dealing with short blocks: burst period scaling*/ +static inline void unblock_short_burst(struct sedf_dom_info* inf, s_time_t now) +{ + /*treat blocked time as consumed by the domain*/ + inf->cputime += now - inf->absblock; if (inf->cputime + EXTRA_QUANTUM <= inf->slice) { + /*if we can still use some time in the current slice + then use it!*/ #ifdef SEDF_STATS - inf->short_cont++; //we let the domain run in the current period + /*we let the domain run in the current period*/ + inf->short_cont++; #endif } else { - //we don't have a reasonable amount of time in our slice left => switch to burst mode + /*we don't have a reasonable amount of time in + our slice left => switch to burst mode*/ if (likely(inf->absunblock)) { - inf->period = now - inf->absunblock; //set the period-length to the current blocking interval - ASSERT((inf->period < ULONG_MAX) && (inf->slice_orig < ULONG_MAX));//this results in max. 4s slice/period length - inf->slice = (inf->period * inf->slice_orig) / inf->period_orig;//scale slice accordingly, so that utilisation stays the same + /*set the period-length to the current blocking + interval, possible enhancements: average over last + blocking intervals, user-specified minimum,...*/ + inf->period = now - inf->absunblock; + /*check for overflow on multiplication*/ + ASSERT((inf->period < ULONG_MAX) + && (inf->slice_orig < ULONG_MAX)); + /*scale slice accordingly, so that utilisation + stays the same*/ + inf->slice = (inf->period * inf->slice_orig) + / inf->period_orig; + /*set new (shorter) deadline*/ + inf->absdead += inf->period; } else { - inf->cputime=0; //in Case we haven't unblocked before - inf->absdead += inf->period; //start in next period! + /*in case we haven't unblocked before + start in next period!*/ + inf->cputime=0; + inf->absdead += inf->period; } } inf->absunblock = now; } static inline void unblock_long_burst(struct sedf_dom_info* inf,s_time_t now) { if (unlikely(inf->latency && (inf->period > inf->latency))) { - //sclae the slice and period accordingly to the latency hint - inf->period = inf->latency; //reduce period temporarily to the latency hint - ASSERT((inf->period < ULONG_MAX) && (inf->slice_orig < ULONG_MAX)); //this results in max. 4s slice/period length - inf->slice = (inf->period * inf->slice_orig) / inf->period_orig; //scale slice accordingly, so that utilisation stays the same + /*scale the slice and period accordingly to the latency hint*/ + inf->period = inf->latency; + /*check for overflows on multiplication*/ + ASSERT((inf->period < ULONG_MAX) + && (inf->slice_orig < ULONG_MAX)); + /*scale slice accordingly, so that utilisation stays the same*/ + inf->slice = (inf->period * inf->slice_orig) + / inf->period_orig; + inf->absdead = now + inf->period; + inf->cputime = 0; } else { - //we don't have a latency hint.. or we are currently in "burst mode": use some other technique - //this should be in fact the normal way of operation, when we are in sync with the device! + /*we don't have a latency hint.. or we are currently in + "burst mode": use some other technique + NB: this should be in fact the normal way of operation, + when we are in sync with the device!*/ unblock_long_cons_b(inf, now); } inf->absunblock = now; @@ -855,34 +1040,42 @@ static inline int get_run_type(struct domain* d) { return DOMAIN_EXTRA_UTIL; return DOMAIN_EDF; } -/*Compares two domains in the relation of whether the one is allowed to interrupt the others execution. +/*Compares two domains in the relation of whether the one is allowed to + interrupt the others execution. It returns true (!=0) if a switch to the other domain is good. Current Priority scheme is as follows: - EDF > L0 (penalty based) extra-time > L1 (utilization) extra-time > idle-domain + EDF > L0 (penalty based) extra-time > + L1 (utilization) extra-time > idle-domain In the same class priorities are assigned as following: EDF: early deadline > late deadline L0 extra-time: lower score > higher score*/ -static inline int should_switch(struct domain* cur, struct domain* other, s_time_t now) { +static inline int should_switch(struct domain* cur, struct domain* other, + s_time_t now) { struct sedf_dom_info *cur_inf, *other_inf; cur_inf = DOM_INFO(cur); other_inf = DOM_INFO(other); + /*check whether we need to make an earlier sched-decision*/ + if ((PERIOD_BEGIN(other_inf) < + schedule_data[other->processor].s_timer.expires)) + return 1; + /*no timing-based switches need to be taken into account here*/ switch (get_run_type(cur)) { case DOMAIN_EDF: - //check whether we need to make an earlier sched-decision - if ((PERIOD_BEGIN(other_inf) < schedule_data[other->processor].s_timer.expires)) - return 1; - else return 0; + /* do not interrupt a running EDF domain */ + return 0; case DOMAIN_EXTRA_PEN: - //check whether we need an earlier decision or we also want the L0 ex-q with lower score - if ((PERIOD_BEGIN(other_inf) < schedule_data[other->processor].s_timer.expires) - || ((other_inf->extra & EXTRA_WANT_PEN_Q) && (other_inf->score[EXTRA_PEN_Q] < cur_inf->score[EXTRA_PEN_Q]))) + /*check whether we also want + the L0 ex-q with lower score*/ + if ((other_inf->extra & EXTRA_WANT_PEN_Q) + && (other_inf->score[EXTRA_PEN_Q] < + cur_inf->score[EXTRA_PEN_Q])) return 1; else return 0; case DOMAIN_EXTRA_UTIL: - //check whether we need an earlier decision or we want the L0 extraq, don't switch if both domains want L1 extraq - if ((PERIOD_BEGIN(other_inf) < schedule_data[other->processor].s_timer.expires) - || (other_inf->extra & EXTRA_WANT_PEN_Q)) + /*check whether we want the L0 extraq, don't + switch if both domains want L1 extraq */ + if (other_inf->extra & EXTRA_WANT_PEN_Q) return 1; else return 0; case DOMAIN_IDLE: @@ -890,7 +1083,6 @@ static inline int should_switch(struct domain* cur, struct domain* other, s_time } } void sedf_wake(struct domain *d) { - //for the first try just implement the "very conservative" way of waking domains up s_time_t now = NOW(); struct sedf_dom_info* inf = DOM_INFO(d); @@ -907,35 +1099,44 @@ void sedf_wake(struct domain *d) { PRINT(3,"\tdomain %i is already in the extraQ\n",d->id); } if (unlikely(inf->absdead == 0)) - inf->absdead = now + inf->slice; //initial setup of the deadline + /*initial setup of the deadline*/ + inf->absdead = now + inf->slice; - PRINT(3,"waking up domain %i (deadl= %llu period= %llu now= %llu)\n",d->id,inf->absdead,inf->period,now); + PRINT(3,"waking up domain %i (deadl= %llu period= %llu "\ + "now= %llu)\n",d->id,inf->absdead,inf->period,now); #ifdef SEDF_STATS inf->block_tot++; #endif if (unlikely(now< PERIOD_BEGIN(inf))) { PRINT(4,"extratime unblock\n"); - //this might happen, imagine unblocking in extra-time! + /*this might happen, imagine unblocking in extra-time!*/ #if (EXTRA == EXTRA_BLOCK_WEIGHT) - if (inf->extra & EXTRA_WANT_PEN_Q) { //we have a domain that wants compensation + if (inf->extra & EXTRA_WANT_PEN_Q) { + /*we have a domain that wants compensation + for block penalty and did just block in + its compensation time. Give it another + chance!*/ extraq_add_sort_update(d, EXTRA_PEN_Q, 0); - } /*else*/ + } #endif if (inf->extra & EXTRA_AWARE) #if (EXTRA == EXTRA_ROUNDR) - extraq_add_tail(d,EXTRA_UTIL_Q); //SD: Could extraq_add_head be better? - #elif (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) - extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); //put in on the weighted extraq + extraq_add_tail(d,EXTRA_UTIL_Q); + #elif (EXTRA == EXTRA_SLICE_WEIGHT \ + || EXTRA == EXTRA_BLOCK_WEIGHT) + /*put in on the weighted extraq, + without updating any scores*/ + extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); #else ; #endif - //else - //This is very very unlikely, ie. might even be an error?! + /*else*/ + /*This is very very unlikely, ie. might even be an error?!*/ } else { if (now < inf->absdead) { PRINT(4,"short unblocking\n"); - //short blocking + /*short blocking*/ #ifdef SEDF_STATS inf->short_block_tot++; #endif @@ -953,27 +1154,29 @@ void sedf_wake(struct domain *d) { #if (EXTRA == EXTRA_OFF) ; #elif (EXTRA == EXTRA_ROUNDR) - extraq_add_head(d, EXTRA_UTIL_Q); //Favour domains which got short unblocked - #elif (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) + /*Favour domains which got short unblocked*/ + extraq_add_head(d, EXTRA_UTIL_Q); + #elif (EXTRA == EXTRA_SLICE_WEIGHT \ + || EXTRA == EXTRA_BLOCK_WEIGHT) extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); #endif } else { PRINT(4,"long unblocking\n"); - //long blocking + /*long unblocking*/ #ifdef SEDF_STATS inf->long_block_tot++; #endif - //PRINT(3,"old=%llu ",inf->absdead); #if (UNBLOCK == UNBLOCK_ISOCHRONOUS_EDF) unblock_long_vcons(inf, now); - #elif (UNBLOCK == UNBLOCK_EDF || UNBLOCK == UNBLOCK_EXTRA_SUPPORT) + #elif (UNBLOCK == UNBLOCK_EDF \ + || UNBLOCK == UNBLOCK_EXTRA_SUPPORT) unblock_long_cons_b(inf, now); #elif (UNBLOCK == UNBLOCK_ATROPOS) unblock_long_cons_c(inf, now); #elif (UNBLOCK == UNBLOCK_SHORT_RESUME) unblock_long_cons_b(inf, now); - //unblock_short_cons_c(inf, now); + /*unblock_short_cons_c(inf, now);*/ #elif (UNBLOCK == UNBLOCK_BURST) unblock_long_burst(inf, now); #endif @@ -983,35 +1186,37 @@ void sedf_wake(struct domain *d) { ; #elif (EXTRA == EXTRA_ROUNDR) extraq_add_head(d, EXTRA_UTIL_Q); - #elif (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) - //PRINT(2,"now try to add domain %i to the extra_util_q\n",d->id); + #elif (EXTRA == EXTRA_SLICE_WEIGHT \ + || EXTRA == EXTRA_BLOCK_WEIGHT) extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); - //PRINT(2,"added domain\n"); #endif } } } - PRINT(3,"woke up domain %i (deadl= %llu period= %llu now= %llu)\n",d->id,inf->absdead,inf->period,now); + PRINT(3,"woke up domain %i (deadl= %llu period= %llu "\ + "now= %llu)\n",d->id,inf->absdead,inf->period,now); __add_to_waitqueue_sort(d); PRINT(3,"added to waitq\n"); #ifdef SEDF_STATS - //do some statistics here... + /*do some statistics here...*/ if (inf->absblock != 0) { inf->block_time_tot += now - inf->absblock; - inf->penalty_time_tot += PERIOD_BEGIN(inf) + inf->cputime - inf->absblock; + inf->penalty_time_tot += + PERIOD_BEGIN(inf) + inf->cputime - inf->absblock; } #endif - //sanity check: make sure each extra-aware domain IS on the util-q! + /*sanity check: make sure each extra-aware domain IS on the util-q!*/ /*if (inf->extra & EXTRA_AWARE) { if (!extraq_on(d, EXTRA_UTIL_Q)) - printf("sedf_wake: domain %i is extra-aware, but NOT on L1 extraq!\n",d->id); + printf("sedf_wake: domain %i is extra-aware, "\ + "but NOT on L1 extraq!\n",d->id); }*/ - //check whether the awakened task needs to get scheduled before the next sched. decision - //and check, whether we are idling and this domain is extratime aware - //Save approximation: Always switch to scheduler! + /*check whether the awakened task needs to invoke the do_schedule + routine. Try to avoid unnecessary runs but: + Save approximation: Always switch to scheduler!*/ if (should_switch(schedule_data[d->processor].curr, d, now)){ #ifdef ADV_SCHED_HISTO adv_sched_hist_start(d->processor); @@ -1025,21 +1230,30 @@ static void sedf_dump_domain(struct domain *d) { printk("%u has=%c ", d->id, test_bit(DF_RUNNING, &d->flags) ? 'T':'F'); printk("p=%llu sl=%llu ddl=%llu w=%hu c=%llu sc=%i xtr(%s)=%llu", - DOM_INFO(d)->period, DOM_INFO(d)->slice, DOM_INFO(d)->absdead, DOM_INFO(d)->weight, d->cpu_time, - DOM_INFO(d)->score[EXTRA_UTIL_Q], (DOM_INFO(d)->extra & EXTRA_AWARE) ? "yes" : "no", DOM_INFO(d)->extra_time_tot); + DOM_INFO(d)->period, DOM_INFO(d)->slice, DOM_INFO(d)->absdead, + DOM_INFO(d)->weight, d->cpu_time, DOM_INFO(d)->score[EXTRA_UTIL_Q], + (DOM_INFO(d)->extra & EXTRA_AWARE) ? "yes" : "no", + DOM_INFO(d)->extra_time_tot); if (d->cpu_time !=0) - printf(" (%lu%)", (DOM_INFO(d)->extra_time_tot * 100) / d->cpu_time); + printf(" (%lu%)", (DOM_INFO(d)->extra_time_tot * 100) + / d->cpu_time); #ifdef SEDF_STATS if (DOM_INFO(d)->block_time_tot!=0) - printf(" pen=%lu%", (DOM_INFO(d)->penalty_time_tot * 100) / DOM_INFO(d)->block_time_tot); + printf(" pen=%lu%", (DOM_INFO(d)->penalty_time_tot * 100) / + DOM_INFO(d)->block_time_tot); if (DOM_INFO(d)->block_tot!=0) - printf("\n blks=%lu sh=%lu (%lu%) (shc=%lu (%lu%) shex=%i shexsl=%i) l=%lu (%lu%) avg: b=%llu p=%llu", DOM_INFO(d)->block_tot, - DOM_INFO(d)->short_block_tot, (DOM_INFO(d)->short_block_tot * 100) / DOM_INFO(d)->block_tot, - DOM_INFO(d)->short_cont, (DOM_INFO(d)->short_cont * 100) / DOM_INFO(d)->block_tot, - DOM_INFO(d)->pen_extra_blocks, DOM_INFO(d)->pen_extra_slices, - DOM_INFO(d)->long_block_tot, (DOM_INFO(d)->long_block_tot * 100) / DOM_INFO(d)->block_tot, - (DOM_INFO(d)->block_time_tot) / DOM_INFO(d)->block_tot, - (DOM_INFO(d)->penalty_time_tot) / DOM_INFO(d)->block_tot); + printf("\n blks=%lu sh=%lu (%lu%) (shc=%lu (%lu%) shex=%i "\ + "shexsl=%i) l=%lu (%lu%) avg: b=%llu p=%llu", + DOM_INFO(d)->block_tot, DOM_INFO(d)->short_block_tot, + (DOM_INFO(d)->short_block_tot * 100) + / DOM_INFO(d)->block_tot, DOM_INFO(d)->short_cont, + (DOM_INFO(d)->short_cont * 100) / DOM_INFO(d)->block_tot, + DOM_INFO(d)->pen_extra_blocks, + DOM_INFO(d)->pen_extra_slices, + DOM_INFO(d)->long_block_tot, + (DOM_INFO(d)->long_block_tot * 100) / DOM_INFO(d)->block_tot, + (DOM_INFO(d)->block_time_tot) / DOM_INFO(d)->block_tot, + (DOM_INFO(d)->penalty_time_tot) / DOM_INFO(d)->block_tot); #endif printf("\n"); } @@ -1072,19 +1286,23 @@ static void sedf_dump_cpu_state(int i) } queue = EXTRAQ(i,EXTRA_PEN_Q); loop = 0; - printk("\nEXTRAQ (penalty) rq %lx n: %lx, p: %lx\n", (unsigned long)queue, - (unsigned long) queue->next, (unsigned long) queue->prev); + printk("\nEXTRAQ (penalty) rq %lx n: %lx, p: %lx\n", + (unsigned long)queue, (unsigned long) queue->next, + (unsigned long) queue->prev); list_for_each_safe ( list, tmp, queue ) { - d_inf = list_entry(list, struct sedf_dom_info, extralist[EXTRA_PEN_Q]); + d_inf = list_entry(list, struct sedf_dom_info, + extralist[EXTRA_PEN_Q]); printk("%3d: ",loop++); sedf_dump_domain(d_inf->owner); } queue = EXTRAQ(i,EXTRA_UTIL_Q); loop = 0; - printk("\nEXTRAQ (utilization) rq %lx n: %lx, p: %lx\n", (unsigned long)queue, - (unsigned long) queue->next, (unsigned long) queue->prev); + printk("\nEXTRAQ (utilization) rq %lx n: %lx, p: %lx\n", + (unsigned long)queue, (unsigned long) queue->next, + (unsigned long) queue->prev); list_for_each_safe ( list, tmp, queue ) { - d_inf = list_entry(list, struct sedf_dom_info, extralist[EXTRA_UTIL_Q]); + d_inf = list_entry(list, struct sedf_dom_info, + extralist[EXTRA_UTIL_Q]); printk("%3d: ",loop++); sedf_dump_domain(d_inf->owner); } @@ -1098,8 +1316,9 @@ static void sedf_dump_cpu_state(int i) } } } -//Adjusts periods and slices of the domains accordingly to their weights -static inline int sedf_adjust_weights(struct domain *p, struct sched_adjdom_cmd *cmd) { +/*Adjusts periods and slices of the domains accordingly to their weights*/ +static inline int sedf_adjust_weights(struct domain *p, +struct sched_adjdom_cmd *cmd) { int sumw[NR_CPUS]; s_time_t sumt[NR_CPUS]; int cpu; @@ -1108,25 +1327,31 @@ static inline int sedf_adjust_weights(struct domain *p, struct sched_adjdom_cmd sumw[cpu] = 0; sumt[cpu] = 0; } - //sum up all weights + /*sum up all weights*/ for_each_domain(p) { if (DOM_INFO(p)->weight) sumw[p->processor] += DOM_INFO(p)->weight; else { - //don't modify domains who don't have a weight, but sum up - //the time they need, projected to a WEIGHT_PERIOD, so that - //this time is not given to the weight-driven domains - ASSERT((WEIGHT_PERIOD < ULONG_MAX) && (DOM_INFO(p)->slice_orig < ULONG_MAX)); //this results in max. 4s slice/period length - sumt[p->processor] += (WEIGHT_PERIOD * DOM_INFO(p)->slice_orig) / DOM_INFO(p)->period_orig; + /*don't modify domains who don't have a weight, but sum + up the time they need, projected to a WEIGHT_PERIOD, + so that this time is not given to the weight-driven + domains*/ + /*check for overflows*/ + ASSERT((WEIGHT_PERIOD < ULONG_MAX) + && (DOM_INFO(p)->slice_orig < ULONG_MAX)); + sumt[p->processor] += (WEIGHT_PERIOD * + DOM_INFO(p)->slice_orig) / DOM_INFO(p)->period_orig; } } - //adjust all slices (and periods) to the new weight + /*adjust all slices (and periods) to the new weight*/ for_each_domain(p) { if (DOM_INFO(p)->weight) { DOM_INFO(p)->period_orig = DOM_INFO(p)->period = WEIGHT_PERIOD; DOM_INFO(p)->slice_orig = - DOM_INFO(p)->slice = (DOM_INFO(p)->weight * (WEIGHT_PERIOD - WEIGHT_SAFETY - sumt[p->processor])) / sumw[p->processor]; + DOM_INFO(p)->slice = (DOM_INFO(p)->weight * + (WEIGHT_PERIOD -WEIGHT_SAFETY - + sumt[p->processor])) / sumw[p->processor]; } } return 0; @@ -1134,19 +1359,24 @@ static inline int sedf_adjust_weights(struct domain *p, struct sched_adjdom_cmd /* set or fetch domain scheduling parameters */ static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { - PRINT(2,"sedf_adjdom was called, domain-id %i new period %llu new slice %llu\n" - "latency %llu extra: %s\n",p->id,cmd->u.sedf.period,cmd->u.sedf.slice,cmd->u.sedf.latency,(cmd->u.sedf.extratime)?"yes":"no"); + PRINT(2,"sedf_adjdom was called, domain-id %i new period %llu "\ + "new slice %llu\nlatency %llu extra:%s\n", + p->id, cmd->u.sedf.period, cmd->u.sedf.slice, + cmd->u.sedf.latency, (cmd->u.sedf.extratime)?"yes":"no"); if ( cmd->direction == SCHED_INFO_PUT ) { - if (!cmd->u.sedf.period && !cmd->u.sedf.weight) //check for sane parameters + /*check for sane parameters*/ + if (!cmd->u.sedf.period && !cmd->u.sedf.weight) return -EINVAL; + /*weight driven domains*/ if (cmd->u.sedf.weight) { - DOM_INFO(p)->weight = cmd->u.sedf.weight; //weight driven domains + DOM_INFO(p)->weight = cmd->u.sedf.weight; } else { - //time driven domains + /*time driven domains*/ DOM_INFO(p)->weight = 0; - if(cmd->u.sedf.slice > cmd->u.sedf.period ) /* sanity checking! */ + /* sanity checking! */ + if(cmd->u.sedf.slice > cmd->u.sedf.period ) return -EINVAL; DOM_INFO(p)->period_orig = DOM_INFO(p)->period = cmd->u.sedf.period; @@ -1155,7 +1385,8 @@ static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { } if (sedf_adjust_weights(p,cmd)) return -EINVAL; - DOM_INFO(p)->extra = (DOM_INFO(p)-> extra & ~EXTRA_AWARE) | (cmd->u.sedf.extratime & EXTRA_AWARE); + DOM_INFO(p)->extra = (DOM_INFO(p)-> extra & ~EXTRA_AWARE) + | (cmd->u.sedf.extratime & EXTRA_AWARE); DOM_INFO(p)->latency = cmd->u.sedf.latency; extraq_check(p); } From 60e19526de2a02efa8f66715629b25579f9f3a77 Mon Sep 17 00:00:00 2001 From: "sd386@font.cl.cam.ac.uk" Date: Fri, 1 Apr 2005 13:01:31 +0000 Subject: [PATCH 09/54] bitkeeper revision 1.1159.170.109 (424d462b3t7TNRulCLgZcZNC5I8oew) Added a very brief usage guide on the sedf scheduler. --- .rootkeys | 1 + docs/misc/sedf_scheduler_mini-HOWTO.txt | 44 +++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 docs/misc/sedf_scheduler_mini-HOWTO.txt diff --git a/.rootkeys b/.rootkeys index be0623acf5..6231a0c75c 100644 --- a/.rootkeys +++ b/.rootkeys @@ -17,6 +17,7 @@ 418a3248xjIqmNKo0v_XQSfAvlBGFw docs/html.sty 4022a73cgxX1ryj1HgS-IwwB6NUi2A docs/misc/XenDebugger-HOWTO 412f4bd9sm5mCQ8BkrgKcAKZGadq7Q docs/misc/blkif-drivers-explained.txt +424d462b5GuApQ_NyMsRFt9LbrsWow docs/misc/sedf_scheduler_mini-HOWTO.txt 40d6ccbfKKBq8jE0ula4eHEzBiQuDA docs/misc/xen_config.html 410a4c2bAO_m_l4RsiiPHnZ4ixHWbQ docs/misc/xend.tex 3f9e7d564bWFB-Czjv1qdmE6o0GqNg docs/src/interface.tex diff --git a/docs/misc/sedf_scheduler_mini-HOWTO.txt b/docs/misc/sedf_scheduler_mini-HOWTO.txt new file mode 100644 index 0000000000..ad3cc62e1f --- /dev/null +++ b/docs/misc/sedf_scheduler_mini-HOWTO.txt @@ -0,0 +1,44 @@ +sEDF scheduler +-------------- +Author: + Stephan.Diestelhorst@{cl.cam.ac.uk, inf.tu-dresden.de} + +Overview: + This scheduler provides weighted CPU sharing in an intuitive way and + uses realtime-algorithms to ensure time guarantees. + +Usage: +   -add "sched=sedf" on Xen's boot command-line +   -create domains as usual +   -use "xm sedf " +  Where: +  -period/slice are the normal EDF scheduling parameters in nanosecs +  -latency-hint is the scaled period in case the domain is doing heavy I/O + (unused by the currently compiled version) +  -extra is a flag (0/1), which controls whether the domain can run in + extra-time +  -weight is mutually exclusive with period/slice and specifies another + way of setting a domains cpu slice + +Examples: + normal EDF (20ms/5ms): +  xm sedf 20000000 5000000 0 0 0 + + best-effort domains (i.e. non-realtime): +  xm sedf 20000000 0 0 1 0 +  + normal EDF (20ms/5ms) + share of extra-time: +  xm sedf 20000000 5000000 0 1 0 + + 4 domains with weights 2:3:4:2 +  xm sedf 0 0 0 0 2 +  xm sedf 0 0 0 0 3 +  xm sedf 0 0 0 0 4 +  xm sedf 0 0 0 0 2 + + 1 fully-specified (10ms/3ms) domain, 3 other domains share + available rest in 2:7:3 ratio: +  xm sedf 10000000 3000000 0 0 0 +  xm sedf 0 0 0 0 2 +  xm sedf 0 0 0 0 7 +  xm sedf 0 0 0 0 3 \ No newline at end of file From e803ae0ddc654a3a0f1e4670e07944051642c6e2 Mon Sep 17 00:00:00 2001 From: "sd386@font.cl.cam.ac.uk" Date: Fri, 22 Apr 2005 17:05:34 +0000 Subject: [PATCH 10/54] bitkeeper revision 1.1346.1.2 (42692edeXI3qQBmD6woxfDOQaO7VKg) Finished port of the sEDF scheduler to 3.0. sEDF is a new scheduler for Xen, that provides time guarantees using an EDF like algorithm, and also distributes idle cpu time on a weighted fair share policy. Signed off by: Stephan.Diestelhorst@{cl.cam.ac.uk , inf.tu-dresden.de} --- xen/common/sched_sedf.c | 673 ++++++++++++++++++++++------------------ 1 file changed, 365 insertions(+), 308 deletions(-) diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c index ab1a0697e5..5c2eb80d56 100644 --- a/xen/common/sched_sedf.c +++ b/xen/common/sched_sedf.c @@ -56,10 +56,12 @@ if ((_f)<=SEDFLEVEL) printk(_a ); #define WEIGHT_PERIOD (MILLISECS(100)) #define WEIGHT_SAFETY (MILLISECS(5)) - -struct sedf_dom_info +struct sedf_dom_info { + struct domain *domain; +}; +struct sedf_edom_info { - struct domain *owner; + struct exec_domain *exec_domain; struct list_head list; struct list_head extralist[2]; @@ -79,13 +81,12 @@ struct sedf_dom_info short weight; /*Bookkeeping*/ - s_time_t absdead; - s_time_t sched_start; + s_time_t deadl_abs; + s_time_t sched_start_abs; s_time_t cputime; - s_time_t absblock; - - /*time the domain unblocked, used to determine unblocking intervals*/ - s_time_t absunblock; + /* times the domain un-/blocked */ + s_time_t block_abs; + s_time_t unblock_abs; /*scores for {util, block penalty}-weighted extratime distribution*/ int score[2]; @@ -112,48 +113,47 @@ struct sedf_cpu_info { struct list_head extraq[2]; }; -#define DOM_INFO(d) ((struct sedf_dom_info *)((d)->sched_priv)) +#define EDOM_INFO(d) ((struct sedf_edom_info *)((d)->ed_sched_priv)) #define CPU_INFO(cpu) ((struct sedf_cpu_info *)schedule_data[cpu].sched_priv) -#define LIST(d) (&DOM_INFO(d)->list) -#define EXTRALIST(d,i) (&(DOM_INFO(d)->extralist[i])) +#define LIST(d) (&EDOM_INFO(d)->list) +#define EXTRALIST(d,i) (&(EDOM_INFO(d)->extralist[i])) #define RUNQ(cpu) (&CPU_INFO(cpu)->runnableq) #define WAITQ(cpu) (&CPU_INFO(cpu)->waitq) #define EXTRAQ(cpu,i) (&(CPU_INFO(cpu)->extraq[i])) -#define IDLETASK(cpu) ((struct domain *)schedule_data[cpu].idle) +#define IDLETASK(cpu) ((struct exec_domain *)schedule_data[cpu].idle) -#define PERIOD_BEGIN(inf) ((inf)->absdead - (inf)->period) +#define PERIOD_BEGIN(inf) ((inf)->deadl_abs - (inf)->period) #define MIN(x,y) (((x)<(y))?(x):(y)) #define DIV_UP(x,y) (((x) + (y) - 1) / y) -static xmem_cache_t *dom_info_cache; - static void sedf_dump_cpu_state(int i); -static inline int extraq_on(struct domain *d, int i) { +static inline int extraq_on(struct exec_domain *d, int i) { return ((EXTRALIST(d,i)->next != NULL) && (EXTRALIST(d,i)->next != EXTRALIST(d,i))); } -static inline void extraq_add_head(struct domain *d, int i) +static inline void extraq_add_head(struct exec_domain *d, int i) { list_add(EXTRALIST(d,i), EXTRAQ(d->processor,i)); } -static inline void extraq_add_tail(struct domain *d, int i) +static inline void extraq_add_tail(struct exec_domain *d, int i) { list_add_tail(EXTRALIST(d,i), EXTRAQ(d->processor,i)); } -static inline void extraq_del(struct domain *d, int i) +static inline void extraq_del(struct exec_domain *d, int i) { struct list_head *list = EXTRALIST(d,i); /*if (!extraq_on(d,i)) { - PRINT(0,"extraq_del: domain %i is NOT on L%i extraq "\ - "HALTING\n",d->id,i); + PRINT(0,"extraq_del: domain %i.%i is NOT on L%i extraq "\ + "HALTING\n",d->domain->id, d->eid,i); sedf_dump_cpu_state(0);(*((int*)0))++; }*/ - PRINT(3, "Removing domain %i from L%i extraq\n", d->id,i); + PRINT(3, "Removing domain %i.%i from L%i extraq\n", d->domain->id, + d->eid, i); list_del(list); list->next = NULL; } @@ -164,28 +164,29 @@ static inline void extraq_del(struct domain *d, int i) each entry, in order to avoid overflow. The algorithm works by simply charging each domain that recieved extratime with an inverse of its weight. */ -static inline void extraq_add_sort_update(struct domain *d, int i, int sub) { - struct list_head *cur; - struct sedf_dom_info *curinf; +static inline void extraq_add_sort_update(struct exec_domain *d, int i, int sub) { + struct list_head *cur; + struct sedf_edom_info *curinf; /*if (extraq_on(d,i)) { - PRINT(0,"extraq_add_sort_update: domain %i is already on "\ - "L%i extraq! HALTING\n",d->id,i); + PRINT(0,"extraq_add_sort_update: domain %i.%i is already on "\ + "L%i extraq! HALTING\n",d->domain->id, d->eid, i); sedf_dump_cpu_state(0);(*((int*)0))++; }*/ - PRINT(3, "Adding domain %i (score= %i, short_pen= %lli) to L%i "\ - "extraq\n", d->id, DOM_INFO(d)->score[i], - DOM_INFO(d)->short_block_lost_tot, i); + PRINT(3, "Adding domain %i.%i (score= %i, short_pen= %lli) to L%i "\ + "extraq\n", d->domain->id, d->eid, EDOM_INFO(d)->score[i], + EDOM_INFO(d)->short_block_lost_tot, i); /*iterate through all elements to find our "hole" and on our way update all the other scores*/ list_for_each(cur,EXTRAQ(d->processor,i)){ - curinf = list_entry(cur,struct sedf_dom_info,extralist[i]); + curinf = list_entry(cur,struct sedf_edom_info,extralist[i]); curinf->score[i] -= sub; - if (DOM_INFO(d)->score[i] < curinf->score[i]) + if (EDOM_INFO(d)->score[i] < curinf->score[i]) break; else - PRINT(4,"\tbehind domain %i (score= %i)\n", - curinf->owner->id, curinf->score[i]); + PRINT(4,"\tbehind domain %i.%i (score= %i)\n", + curinf->exec_domain->domain->id, + curinf->exec_domain->eid, curinf->score[i]); } /*cur now contains the element, before which we'll enqueue*/ PRINT(3, "\tlist_add to %x\n", cur->prev); @@ -195,24 +196,27 @@ static inline void extraq_add_sort_update(struct domain *d, int i, int sub) { if ((cur != EXTRAQ(d->processor,i)) && sub) for (cur = cur->next; cur != EXTRAQ(d->processor,i); cur = cur-> next) { - curinf = list_entry(cur,struct sedf_dom_info, + curinf = list_entry(cur,struct sedf_edom_info, extralist[i]); curinf->score[i] -= sub; - PRINT(4, "\tupdating domain %i (score= %llu)\n", - curinf->owner->id, curinf->score[i]); + PRINT(4, "\tupdating domain %i.%i (score= %llu)\n", + curinf->exec_domain->domain->id, + curinf->exec_domain->eid, curinf->score[i]); } } -static inline void extraq_check(struct domain *d) { +static inline void extraq_check(struct exec_domain *d) { if (extraq_on(d, EXTRA_UTIL_Q)) { - PRINT(2,"Dom %i is on extraQ\n",d->id); - if (!(DOM_INFO(d)->extra & EXTRA_AWARE) && - !extra_runs(DOM_INFO(d))) { + PRINT(2,"Dom %i is on extraQ\n",d->domain->id, d->eid); + if (!(EDOM_INFO(d)->extra & EXTRA_AWARE) && + !extra_runs(EDOM_INFO(d))) { extraq_del(d, EXTRA_UTIL_Q); - PRINT(2,"Removed dom %i from L1 extraQ\n",d->id); + PRINT(2,"Removed dom %i.%i from L1 extraQ\n", + d->domain->id, d->eid); } } else { - PRINT(2,"Dom %i is NOT on L1 extraQ\n",d->id); - if ((DOM_INFO(d)->extra & EXTRA_AWARE) && domain_runnable(d)) + PRINT(2,"Dom %i.%i is NOT on L1 extraQ\n",d->domain->id, + d->eid); + if ((EDOM_INFO(d)->extra & EXTRA_AWARE) && domain_runnable(d)) { #if (EXTRA == EXTRA_ROUNDR) /*Favour domains which got short unblocked*/ @@ -223,15 +227,16 @@ static inline void extraq_check(struct domain *d) { #elif ; #endif - PRINT(2,"Added dom %i to L1 extraQ\n",d->id); + PRINT(2,"Added dom %i.%i to L1 extraQ\n",d->domain->id, + d->eid); } } } -static inline void __del_from_queue(struct domain *d) +static inline void __del_from_queue(struct exec_domain *d) { struct list_head *list = LIST(d); - PRINT(3,"Removing domain %i (bop= %llu) from runq/waitq\n", d->id, - PERIOD_BEGIN(DOM_INFO(d))); + PRINT(3,"Removing domain %i.%i (bop= %llu) from runq/waitq\n", d->domain->id, + d->eid, PERIOD_BEGIN(EDOM_INFO(d))); list_del(list); list->next = NULL; } @@ -240,26 +245,26 @@ static inline void __del_from_queue(struct domain *d) next period; this list is therefore sortet by this time, which is simply absol. deadline - period */ -static inline void __add_to_waitqueue_sort(struct domain *d) { +static inline void __add_to_waitqueue_sort(struct exec_domain *d) { struct list_head *cur; - struct sedf_dom_info *curinf; + struct sedf_edom_info *curinf; - PRINT(3,"Adding domain %i (bop= %llu) to waitq\n", d->id, - PERIOD_BEGIN(DOM_INFO(d))); + PRINT(3,"Adding domain %i.%i (bop= %llu) to waitq\n", d->domain->id, + d->eid, PERIOD_BEGIN(EDOM_INFO(d))); /*iterate through all elements to find our "hole"*/ - list_for_each(cur,WAITQ(d->processor)){ - curinf = list_entry(cur,struct sedf_dom_info,list); - if (PERIOD_BEGIN(DOM_INFO(d)) < PERIOD_BEGIN(curinf)) + list_for_each(cur, WAITQ(d->processor)){ + curinf = list_entry(cur,struct sedf_edom_info,list); + if (PERIOD_BEGIN(EDOM_INFO(d)) < PERIOD_BEGIN(curinf)) break; else - PRINT(4,"\tbehind domain %i (bop= %llu)\n", - curinf->owner->id, PERIOD_BEGIN(curinf)); + PRINT(4,"\tbehind domain %i.%i (bop= %llu)\n", + curinf->exec_domain->domain->id, + curinf->exec_domain->eid, PERIOD_BEGIN(curinf)); } /*cur now contains the element, before which we'll enqueue*/ PRINT(3,"\tlist_add to %x\n",cur->prev); list_add(LIST(d),cur->prev); - } /* adds a domain to the queue of processes which have started their current @@ -267,40 +272,40 @@ static inline void __add_to_waitqueue_sort(struct domain *d) { on this list is running on the processor, if the list is empty the idle task will run. As we are implementing EDF, this list is sorted by deadlines. */ -static inline void __add_to_runqueue_sort(struct domain *d) { +static inline void __add_to_runqueue_sort(struct exec_domain *d) { struct list_head *cur; - struct sedf_dom_info *curinf; + struct sedf_edom_info *curinf; - PRINT(3,"Adding domain %i (deadl= %llu) to runq\n", d->id, - DOM_INFO(d)->absdead); + PRINT(3,"Adding domain %i.%i (deadl= %llu) to runq\n", d->domain->id, + d->eid, EDOM_INFO(d)->deadl_abs); /*iterate through all elements to find our "hole"*/ list_for_each(cur, RUNQ(d->processor)) { - curinf = list_entry(cur, struct sedf_dom_info, list); - if (DOM_INFO(d)->absdead < curinf->absdead) + curinf = list_entry(cur, struct sedf_edom_info, list); + if (EDOM_INFO(d)->deadl_abs < curinf->deadl_abs) break; else - PRINT(4,"\tbehind domain %i (deadl= %llu)\n", - curinf->owner->id, curinf->absdead); + PRINT(4,"\tbehind domain %i.%i (deadl= %llu)\n", + curinf->exec_domain->domain->id, + curinf->exec_domain->eid, curinf->deadl_abs); } /*cur now contains the element, before which we'll enqueue*/ PRINT(3,"\tlist_add to %x\n",cur->prev); list_add(LIST(d),cur->prev); - } -static inline int __task_on_queue(struct domain *d) { +static inline int __task_on_queue(struct exec_domain *d) { return (((LIST(d))->next != NULL) && (LIST(d)->next != LIST(d))); } -/* Initialises the queues and creates the domain info cache */ +/* Initialises the queues */ static int sedf_init_scheduler() { int i; PRINT(2,"sedf_init_scheduler was called\n"); for ( i = 0; i < NR_CPUS; i++ ) { schedule_data[i].sched_priv = - xmalloc(sizeof(struct sedf_cpu_info)); + xmalloc(struct sedf_cpu_info); if ( schedule_data[i].sched_priv == NULL ) return -1; INIT_LIST_HEAD(WAITQ(i)); @@ -308,46 +313,56 @@ static int sedf_init_scheduler() { INIT_LIST_HEAD(EXTRAQ(i,EXTRA_PEN_Q)); INIT_LIST_HEAD(EXTRAQ(i,EXTRA_UTIL_Q)); } - dom_info_cache = xmem_cache_create("SEDF dom info", +//TODO: Remove this stuff if things work! + /*dom_info_cache = xmem_cache_create("SEDF dom info", sizeof(struct sedf_dom_info), 0, 0, 0, NULL); if ( dom_info_cache == NULL ) { printk("Could not allocate SLAB cache.\n"); return -1; - } + }*/ return 0; } /* Allocates memory for per domain private scheduling data*/ -static int sedf_alloc_task(struct domain *d) { - PRINT(2,"sedf_alloc_task was called, domain-id %i\n",d->id); - if ( (d->sched_priv = xmem_cache_alloc(dom_info_cache)) == NULL ) +static int sedf_alloc_task(struct exec_domain *d) { + PRINT(2,"sedf_alloc_task was called, domain-id %i.%i\n",d->domain->id, + d->eid); + if (d->domain->sched_priv == NULL) { + if ((d->domain->sched_priv = + xmalloc(struct sedf_dom_info)) == NULL ) return -1; - memset(d->sched_priv, 0, sizeof(struct sedf_dom_info)); + memset(d->domain->sched_priv, 0, sizeof(struct sedf_dom_info)); + } + if ((d->ed_sched_priv = xmalloc(struct sedf_edom_info)) == NULL ) + return -1; + memset(d->ed_sched_priv, 0, sizeof(struct sedf_edom_info)); return 0; } /* Setup the sedf_dom_info */ -static void sedf_add_task(struct domain *d) +static void sedf_add_task(struct exec_domain *d) { - struct sedf_dom_info *inf=DOM_INFO(d); - inf->owner = d; + struct sedf_edom_info *inf=EDOM_INFO(d); + inf->exec_domain = d; - PRINT(2,"sedf_add_task was called, domain-id %i\n",d->id); - if (d->id==0) { + PRINT(2,"sedf_add_task was called, domain-id %i.%i\n",d->domain->id, + d->eid); + + if (d->domain->id==0) { /*set dom0 to something useful to boot the machine*/ inf->period = MILLISECS(20); inf->slice = MILLISECS(15); inf->latency = 0; - inf->absdead = 0; + inf->deadl_abs = 0; inf->extra = EXTRA_NONE;/*EXTRA_AWARE; */ } else { /*other domains run in best effort mode*/ inf->period = MILLISECS(20); inf->slice = 0; - inf->absdead = 0; + inf->deadl_abs = 0; inf->latency = 0; inf->extra = EXTRA_AWARE; } @@ -360,31 +375,39 @@ static void sedf_add_task(struct domain *d) /* Frees memory used by domain info */ static void sedf_free_task(struct domain *d) { + int i; PRINT(2,"sedf_free_task was called, domain-id %i\n",d->id); ASSERT(d->sched_priv != NULL); - xmem_cache_free(dom_info_cache, d->sched_priv); + xfree(d->sched_priv); + + for (i = 0; i < MAX_VIRT_CPUS; i++) + if ( d->exec_domain[i] ) { + ASSERT(d->exec_domain[i]->ed_sched_priv != NULL); + xfree(d->exec_domain[i]->ed_sched_priv); + } } /* Initialises idle task */ -static int sedf_init_idle_task(struct domain *d) { - PRINT(2,"sedf_init_idle_task was called, domain-id %i\n",d->id); +static int sedf_init_idle_task(struct exec_domain *d) { + PRINT(2,"sedf_init_idle_task was called, domain-id %i.%i\n", + d->domain->id, d->eid); if ( sedf_alloc_task(d) < 0 ) return -1; sedf_add_task(d); - DOM_INFO(d)->absdead = 0; - set_bit(DF_RUNNING, &d->flags); + EDOM_INFO(d)->deadl_abs = 0; + set_bit(EDF_RUNNING, &d->ed_flags); /*the idle task doesn't have to turn up on any list...*/ return 0; } /* handles the rescheduling, bookkeeping of domains running in their realtime-time :)*/ -static inline void desched_edf_dom (s_time_t now, struct domain* d) { - struct sedf_dom_info* inf = DOM_INFO(d); +static inline void desched_edf_dom (s_time_t now, struct exec_domain* d) { + struct sedf_edom_info* inf = EDOM_INFO(d); /*current domain is running in real time mode*/ /*update the domains cputime*/ - inf->cputime += now - inf->sched_start; + inf->cputime += now - inf->sched_start_abs; /*scheduling decisions, which don't remove the running domain from the runq*/ @@ -392,9 +415,9 @@ static inline void desched_edf_dom (s_time_t now, struct domain* d) { return; __del_from_queue(d); - /*if (__task_on_queue(current)) { - PRINT(0,"domain %i was removed but still on run/waitq => "\ - "HALT\n",current->id); + /*if (__task_on_queue(d)) { + PRINT(0,"domain %i.%i was removed but still on run/waitq => "\ + "HALT\n",d->domain->id, d->eid); sedf_dump_cpu_state(0);(*((int*)0))++; }*/ @@ -406,7 +429,7 @@ static inline void desched_edf_dom (s_time_t now, struct domain* d) { if (inf->period < inf->period_orig) { /*this domain runs in latency scaling or burst mode*/ #if (UNBLOCK == UNBLOCK_BURST) - if (now - inf->absunblock >= 2 * inf->period) + if (now - inf->unblock_abs >= 2 * inf->period) #endif { inf->period *= 2; inf->slice *= 2; @@ -419,43 +442,44 @@ static inline void desched_edf_dom (s_time_t now, struct domain* d) { } } /*set next deadline*/ - inf->absdead += inf->period; + inf->deadl_abs += inf->period; } - /*if (inf->absdeadid, now, - inf->absdead);*/ + /*if (inf->deadl_abs < now) + printk("Domain %i.%i exceeded it't deadline!!!! "\ + "(now: %llu ddl: %llu)\n", d->domain->id, d->eid, now, + inf->deadl_abs);*/ /*add a runnable domain to the waitqueue*/ if (domain_runnable(d)) __add_to_waitqueue_sort(d); else { - /*we have a blocked realtime task*/ - inf->absblock = now; + /*we have a blocked realtime task -> remove it from exqs too*/ + inf->block_abs = now; #if (EXTRA > EXTRA_OFF) #if (EXTRA == EXTRA_BLOCK_WEIGHT) - if (extraq_on(d,EXTRA_PEN_Q)) extraq_del(d,EXTRA_PEN_Q); + if (extraq_on(d, EXTRA_PEN_Q)) extraq_del(d, EXTRA_PEN_Q); #endif - if (extraq_on(d,EXTRA_UTIL_Q)) extraq_del(d,EXTRA_UTIL_Q); + if (extraq_on(d, EXTRA_UTIL_Q)) extraq_del(d, EXTRA_UTIL_Q); #endif } } /* Update all elements on the queues */ -static inline void update_queues( -s_time_t now, struct list_head* runq, struct list_head* waitq) { +static inline void update_queues(s_time_t now, struct list_head* runq, +struct list_head* waitq) { struct list_head *cur,*tmp; - struct sedf_dom_info *curinf; + struct sedf_edom_info *curinf; PRINT(3,"Updating waitq..\n"); /*check for the first elements of the waitqueue, whether their next period has already started*/ list_for_each_safe(cur, tmp, waitq) { - curinf = list_entry(cur, struct sedf_dom_info, list); - PRINT(4,"\tLooking @ dom %i\n", curinf->owner->id); + curinf = list_entry(cur, struct sedf_edom_info, list); + PRINT(4,"\tLooking @ dom %i.%i\n", + curinf->exec_domain->domain->id, curinf->exec_domain->eid); if (PERIOD_BEGIN(curinf) <= now) { - __del_from_queue(curinf->owner); - __add_to_runqueue_sort(curinf->owner); + __del_from_queue(curinf->exec_domain); + __add_to_runqueue_sort(curinf->exec_domain); } else break; @@ -465,48 +489,52 @@ s_time_t now, struct list_head* runq, struct list_head* waitq) { /*process the runq, find domains that are on the runqueue which shouldn't be there*/ list_for_each_safe(cur, tmp, runq) { - curinf = list_entry(cur,struct sedf_dom_info,list); - PRINT(4,"\tLooking @ dom %i\n", curinf->owner->id); + curinf = list_entry(cur,struct sedf_edom_info,list); + PRINT(4,"\tLooking @ dom %i.%i\n", + curinf->exec_domain->domain->id, curinf->exec_domain->eid); if (unlikely(curinf->slice == 0)) { /*ignore domains with empty slice*/ - PRINT(4,"\tUpdating zero-slice domain %i\n", - curinf->owner->id); - __del_from_queue(curinf->owner); + PRINT(4,"\tUpdating zero-slice domain %i.%i\n", + curinf->exec_domain->domain->id, + curinf->exec_domain->eid); + __del_from_queue(curinf->exec_domain); /*move them to their next period*/ - curinf->absdead += curinf->period; + curinf->deadl_abs += curinf->period; /*and put them back into the queue*/ - __add_to_waitqueue_sort(curinf->owner); + __add_to_waitqueue_sort(curinf->exec_domain); } else { - if (unlikely((curinf->absdead < now) || + if (unlikely((curinf->deadl_abs < now) || (curinf->cputime > curinf->slice))) { /*we missed the deadline or the slice was already finished... might hapen because of dom_adj.*/ - PRINT(4,"\tDomain %i exceeded it's deadline/"\ + PRINT(4,"\tDomain %i.%i exceeded it's deadline/"\ "slice (%llu / %llu) now: %llu "\ - "cputime: %llu\n", curinf->owner->id, - curinf->absdead, curinf->slice, now, + "cputime: %llu\n", + curinf->exec_domain->domain->id, + curinf->exec_domain->eid, + curinf->deadl_abs, curinf->slice, now, curinf->cputime); - __del_from_queue(curinf->owner); + __del_from_queue(curinf->exec_domain); /*common case: we miss one period!*/ - curinf->absdead += curinf->period; + curinf->deadl_abs += curinf->period; /*if we are still behind: modulo arithmetic, force deadline to be in future and aligned to period borders!*/ - if (unlikely(curinf->absdead < now)) - curinf->absdead += - DIV_UP(now - curinf->absdead, + if (unlikely(curinf->deadl_abs < now)) + curinf->deadl_abs += + DIV_UP(now - curinf->deadl_abs, curinf->period) * curinf->period; - + ASSERT(curinf->deadl_abs > now); /*give a fresh slice*/ curinf->cputime = 0; - if (PERIOD_BEGIN(curinf) < now) - __add_to_waitqueue_sort(curinf->owner); + if (PERIOD_BEGIN(curinf) > now) + __add_to_waitqueue_sort(curinf->exec_domain); else - __add_to_runqueue_sort(curinf->owner); + __add_to_runqueue_sort(curinf->exec_domain); } else break; @@ -522,8 +550,8 @@ s_time_t now, struct list_head* runq, struct list_head* waitq) { weighted ext.: insert in sorted list by score if the domain is blocked / has regained its short-block-loss time it is not put on any queue */ -static inline void desched_extra_dom(s_time_t now, struct domain* d) { - struct sedf_dom_info *inf = DOM_INFO(d); +static inline void desched_extra_dom(s_time_t now, struct exec_domain* d) { + struct sedf_edom_info *inf = EDOM_INFO(d); int i = extra_get_cur_q(inf); #if (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) @@ -535,7 +563,7 @@ static inline void desched_extra_dom(s_time_t now, struct domain* d) { /*fresh slice for the next run*/ inf->cputime = 0; /*accumulate total extratime*/ - inf->extra_time_tot += now - inf->sched_start; + inf->extra_time_tot += now - inf->sched_start_abs; /*remove extradomain from head of the queue*/ extraq_del(d, i); @@ -551,11 +579,13 @@ static inline void desched_extra_dom(s_time_t now, struct domain* d) { /*domain was running in L0 extraq*/ /*reduce block lost, probably more sophistication here!*/ /*inf->short_block_lost_tot -= EXTRA_QUANTUM;*/ - inf->short_block_lost_tot -= now - inf->sched_start; - PRINT(3,"Domain %i: Short_block_lost: %lli\n", - inf->owner->id, inf->short_block_lost_tot); + inf->short_block_lost_tot -= now - inf->sched_start_abs; + PRINT(3,"Domain %i.%i: Short_block_loss: %lli\n", + inf->exec_domain->domain->id, inf->exec_domain->eid, + inf->short_block_lost_tot); if (inf->short_block_lost_tot <= 0) { - PRINT(4,"Domain %i compensated short block loss!\n"); + PRINT(4,"Domain %i.%i compensated short block loss!\n", + inf->exec_domain->domain->id, inf->exec_domain->eid); /*we have (over-)compensated our block penalty*/ inf->short_block_lost_tot = 0; /*we don't want a place on the penalty queue anymore!*/ @@ -574,6 +604,7 @@ static inline void desched_extra_dom(s_time_t now, struct domain* d) { { /*domain was running in L1 extraq => score is inverse of utilization and is used somewhat incremental!*/ +//TODO: Check for weights => use them for calculating the score! if (inf->slice) /*NB: use fixed point arithmetic with 10 bits*/ inf->score[EXTRA_UTIL_Q] = (inf->period << 10) / @@ -586,47 +617,47 @@ static inline void desched_extra_dom(s_time_t now, struct domain* d) { /*add according to score: weighted round robin*/ extraq_add_sort_update(d, i, oldscore); else { - inf->absblock = now; + inf->block_abs = now; /*if (!__task_on_queue(d)) - printf("Oops... We attempt to remove d %i from the "\ - "waitq, but it is not on :(\n",d->id);*/ + printf("Oops... We attempt to remove d %i.%i from the "\ + "waitq, but it is not on :(\n", d->domain->id, + d->eid);*/ /*remove this blocked domain from the waitq!*/ __del_from_queue(d); /*make sure that we remove a blocked domain from the other extraq aswell (this caused hours of debugging!)*/ #if (EXTRA == EXTRA_BLOCK_WEIGHT) if (i == EXTRA_PEN_Q) { - if (extraq_on(d,EXTRA_UTIL_Q)) - extraq_del(d,EXTRA_UTIL_Q); + if (extraq_on(d, EXTRA_UTIL_Q)) + extraq_del(d, EXTRA_UTIL_Q); } else { - if (extraq_on(d,EXTRA_PEN_Q)) - extraq_del(d,EXTRA_PEN_Q); + if (extraq_on(d, EXTRA_PEN_Q)) + extraq_del(d, EXTRA_PEN_Q); } #endif } #endif /*if (!domain_runnable(d)) { - if (extraq_on(d,EXTRA_UTIL_Q)) { - PRINT(0,"domain %i is blocked but still on L1 "\ - "xq=> HALT\n",d->id); + if (extraq_on(d, EXTRA_UTIL_Q)) { + PRINT(0,"domain %i.%i is blocked but still on L1 "\ + "xq=> HALT\n",d->domain->id, d->eid); sedf_dump_cpu_state(0);(*((int*)0))++; } if (__task_on_queue(d)) { - PRINT(0,"domain %i is blocked but still on run/waitq"\ - "=> HALT\n",d->id); + PRINT(0,"domain %i.%i is blocked but still on run/waitq"\ + "=> HALT\n",d->domain->id, d->eid); sedf_dump_cpu_state(0);(*((int*)0))++; } }*/ } #endif - -static inline task_slice_t sedf_do_extra_schedule -(s_time_t now, s_time_t end_xt, struct list_head *extraq[], int cpu) { - task_slice_t ret; - struct sedf_dom_info *runinf; +static inline struct task_slice sedf_do_extra_schedule (s_time_t now, s_time_t end_xt, struct list_head *extraq[], int cpu) { + struct task_slice ret; + struct sedf_edom_info *runinf; + /* Enough time left to use for extratime? */ if (end_xt - now < EXTRA_QUANTUM) goto return_idle; #if (EXTRA == EXTRA_BLOCK_WEIGHT) @@ -634,9 +665,9 @@ static inline task_slice_t sedf_do_extra_schedule /*we still have elements on the level 0 extraq => let those run first!*/ runinf = list_entry(extraq[EXTRA_PEN_Q]->next, - struct sedf_dom_info, extralist[EXTRA_PEN_Q]); + struct sedf_edom_info, extralist[EXTRA_PEN_Q]); runinf->extra |= EXTRA_RUN_PEN; - ret.task = runinf->owner; + ret.task = runinf->exec_domain; ret.time = EXTRA_QUANTUM; #ifdef SEDF_STATS runinf->pen_extra_slices++; @@ -646,9 +677,9 @@ static inline task_slice_t sedf_do_extra_schedule if (!list_empty(extraq[EXTRA_UTIL_Q])) { /*use elements from the normal extraqueue*/ runinf = list_entry(extraq[EXTRA_UTIL_Q]->next, - struct sedf_dom_info,extralist[EXTRA_UTIL_Q]); + struct sedf_edom_info, extralist[EXTRA_UTIL_Q]); runinf->extra |= EXTRA_RUN_UTIL; - ret.task = runinf->owner; + ret.task = runinf->exec_domain; ret.time = EXTRA_QUANTUM; } else @@ -666,20 +697,20 @@ return_idle: -timeslice for the current period used up -domain on waitqueue has started it's period -and various others ;) in general: determine which domain to run next*/ -static task_slice_t sedf_do_schedule(s_time_t now) +static struct task_slice sedf_do_schedule(s_time_t now) { int cpu = current->processor; struct list_head *runq = RUNQ(cpu); struct list_head *waitq = WAITQ(cpu); #if (EXTRA > EXTRA_OFF) - struct sedf_dom_info *inf = DOM_INFO(current); - struct list_head *extraq[] = {EXTRAQ(cpu,EXTRA_PEN_Q), + struct sedf_edom_info *inf = EDOM_INFO(current); + struct list_head *extraq[] = {EXTRAQ(cpu, EXTRA_PEN_Q), EXTRAQ(cpu, EXTRA_UTIL_Q)}; #endif - task_slice_t ret; + struct task_slice ret; /*int i = 0;*/ /*idle tasks don't need any of the following stuf*/ - if (is_idle_task(current)) + if (is_idle_task(current->domain)) goto check_waitq; #if (EXTRA > EXTRA_OFF) @@ -696,28 +727,31 @@ static task_slice_t sedf_do_schedule(s_time_t now) } /*if (!domain_runnable(current)) { if (extraq_on(current,EXTRA_UTIL_Q)) { - PRINT(0,"domain %i is blocked but still on L1 xq"\ - " branch %i=> HALT\n", current->id, i); + PRINT(0,"domain %i.%i is blocked but still on L1 xq"\ + " branch %i=> HALT\n", current->domain->id, + current->eid, i); sedf_dump_cpu_state(0);(*((int*)0))++; } if (__task_on_queue(current)) { - PRINT(0,"domain %i is blocked but still on run/waitq"\ - " branch %i=> HALT\n",current->id,i); + PRINT(0,"domain %i.%i is blocked but still on run/waitq"\ + " branch %i=> HALT\n",current->domain->id, + d->eid,i); sedf_dump_cpu_state(0);(*((int*)0))++; } }*/ check_waitq: update_queues(now, runq, waitq); - /*now simply pick the first domain from the runqueue*/ - struct sedf_dom_info *runinf, *waitinf; + /*now simply pick the first domain from the runqueue, which has the + earliest deadline, because the list is sorted*/ + struct sedf_edom_info *runinf, *waitinf; if (!list_empty(runq)) { - runinf = list_entry(runq->next,struct sedf_dom_info,list); - ret.task = runinf->owner; + runinf = list_entry(runq->next,struct sedf_edom_info,list); + ret.task = runinf->exec_domain; if (!list_empty(waitq)) { waitinf = list_entry(waitq->next, - struct sedf_dom_info,list); + struct sedf_edom_info,list); /*rerun scheduler, when scheduled domain reaches it's end of slice or the first domain from the waitqueue gets ready*/ @@ -727,11 +761,12 @@ check_waitq: else { ret.time = runinf->slice - runinf->cputime; } + ASSERT(ret.time > now); goto sched_done; } if (!list_empty(waitq)) { - waitinf = list_entry(waitq->next,struct sedf_dom_info,list); + waitinf = list_entry(waitq->next,struct sedf_edom_info, list); /*we could not find any suitable domain => look for domains that are aware of extratime*/ #if (EXTRA > EXTRA_OFF) @@ -741,6 +776,7 @@ check_waitq: ret.task = IDLETASK(cpu); ret.time = PERIOD_BEGIN(waitinf) - now; #endif + ASSERT(ret.time > now); } else { /*this could probably never happen, but one never knows...*/ @@ -758,13 +794,13 @@ sched_done: ret.time); ret.time = EXTRA_QUANTUM; } - DOM_INFO(ret.task)->sched_start=now; + EDOM_INFO(ret.task)->sched_start_abs = now; return ret; } -static void sedf_sleep(struct domain *d) { - PRINT(2,"sedf_sleep was called, domain-id %i\n",d->id); - if ( test_bit(DF_RUNNING, &d->flags) ) { +static void sedf_sleep(struct exec_domain *d) { + PRINT(2,"sedf_sleep was called, domain-id %i.%i\n",d->domain->id, d->eid); + if ( test_bit(EDF_RUNNING, &d->ed_flags) ) { #ifdef ADV_SCHED_HISTO adv_sched_hist_start(d->processor); #endif @@ -856,15 +892,15 @@ static void sedf_sleep(struct domain *d) { * opposed to approaches 1,2a,2b */ static inline void unblock_short_vcons -(struct sedf_dom_info* inf, s_time_t now) { - inf->absdead += inf->period; +(struct sedf_edom_info* inf, s_time_t now) { + inf->deadl_abs += inf->period; inf->cputime = 0; } -static inline void unblock_short_cons(struct sedf_dom_info* inf, s_time_t now) +static inline void unblock_short_cons(struct sedf_edom_info* inf, s_time_t now) { /*treat blocked time as consumed by the domain*/ - inf->cputime += now - inf->absblock; + inf->cputime += now - inf->block_abs; if (inf->cputime + EXTRA_QUANTUM > inf->slice) { /*we don't have a reasonable amount of time in our slice left :( => start in next period!*/ @@ -875,7 +911,7 @@ static inline void unblock_short_cons(struct sedf_dom_info* inf, s_time_t now) inf->short_cont++; #endif } -static inline void unblock_short_extra_support (struct sedf_dom_info* inf, +static inline void unblock_short_extra_support (struct sedf_edom_info* inf, s_time_t now) { /*this unblocking scheme tries to support the domain, by assigning it a priority in extratime distribution according to the loss of time @@ -883,10 +919,12 @@ static inline void unblock_short_extra_support (struct sedf_dom_info* inf, s_time_t pen; /*no more realtime execution in this period!*/ - inf->absdead += inf->period; - if (likely(inf->absblock)) { + inf->deadl_abs += inf->period; + if (likely(inf->block_abs)) { //treat blocked time as consumed by the domain*/ - /*inf->cputime += now - inf->absblock;*/ + /*inf->cputime += now - inf->block_abs;*/ + /*penalty is time the domain would have + had if it continued to run */ pen = (inf->slice - inf->cputime); if (pen < 0) pen = 0; /*accumulate all penalties over the periods*/ @@ -901,9 +939,9 @@ static inline void unblock_short_extra_support (struct sedf_dom_info* inf, #ifdef SEDF_STATS inf->pen_extra_blocks++; #endif - if (extraq_on(inf->owner, EXTRA_PEN_Q)) + if (extraq_on(inf->exec_domain, EXTRA_PEN_Q)) /*remove domain for possible resorting!*/ - extraq_del(inf->owner, EXTRA_PEN_Q); + extraq_del(inf->exec_domain, EXTRA_PEN_Q); else /*remember that we want to be on the penalty q so that we can continue when we (un-)block @@ -911,39 +949,39 @@ static inline void unblock_short_extra_support (struct sedf_dom_info* inf, inf->extra |= EXTRA_WANT_PEN_Q; /*(re-)add domain to the penalty extraq*/ - extraq_add_sort_update(inf->owner, + extraq_add_sort_update(inf->exec_domain, EXTRA_PEN_Q, 0); } } /*give it a fresh slice in the next period!*/ inf->cputime = 0; } -static inline void unblock_long_vcons(struct sedf_dom_info* inf, s_time_t now) +static inline void unblock_long_vcons(struct sedf_edom_info* inf, s_time_t now) { /* align to next future period */ - inf->absdead += ((now - inf->absdead) / inf->period + 1) + inf->deadl_abs += (DIV_UP(now - inf->deadl_abs, inf->period) +1) * inf->period; inf->cputime = 0; } -static inline void unblock_long_cons_a (struct sedf_dom_info* inf, +static inline void unblock_long_cons_a (struct sedf_edom_info* inf, s_time_t now) { /*treat the time the domain was blocked in the CURRENT period as consumed by the domain*/ - inf->cputime = (now - inf->absdead) % inf->period; + inf->cputime = (now - inf->deadl_abs) % inf->period; if (inf->cputime + EXTRA_QUANTUM > inf->slice) { /*we don't have a reasonable amount of time in our slice left :( => start in next period!*/ unblock_long_vcons(inf, now); } } -static inline void unblock_long_cons_b(struct sedf_dom_info* inf,s_time_t now) { +static inline void unblock_long_cons_b(struct sedf_edom_info* inf,s_time_t now) { /*Conservative 2b*/ /*Treat the unblocking time as a start of a new period */ - inf->absdead = now + inf->period; + inf->deadl_abs = now + inf->period; inf->cputime = 0; } -static inline void unblock_long_cons_c(struct sedf_dom_info* inf,s_time_t now) { +static inline void unblock_long_cons_c(struct sedf_edom_info* inf,s_time_t now) { if (likely(inf->latency)) { /*scale the slice and period accordingly to the latency hint*/ /*reduce period temporarily to the latency hint*/ @@ -954,7 +992,7 @@ static inline void unblock_long_cons_c(struct sedf_dom_info* inf,s_time_t now) { /*scale slice accordingly, so that utilisation stays the same*/ inf->slice = (inf->period * inf->slice_orig) / inf->period_orig; - inf->absdead = now + inf->period; + inf->deadl_abs = now + inf->period; inf->cputime = 0; } else { @@ -963,10 +1001,10 @@ static inline void unblock_long_cons_c(struct sedf_dom_info* inf,s_time_t now) { } } /*a new idea of dealing with short blocks: burst period scaling*/ -static inline void unblock_short_burst(struct sedf_dom_info* inf, s_time_t now) +static inline void unblock_short_burst(struct sedf_edom_info* inf, s_time_t now) { /*treat blocked time as consumed by the domain*/ - inf->cputime += now - inf->absblock; + inf->cputime += now - inf->block_abs; if (inf->cputime + EXTRA_QUANTUM <= inf->slice) { /*if we can still use some time in the current slice @@ -979,11 +1017,11 @@ static inline void unblock_short_burst(struct sedf_dom_info* inf, s_time_t now) else { /*we don't have a reasonable amount of time in our slice left => switch to burst mode*/ - if (likely(inf->absunblock)) { + if (likely(inf->unblock_abs)) { /*set the period-length to the current blocking interval, possible enhancements: average over last blocking intervals, user-specified minimum,...*/ - inf->period = now - inf->absunblock; + inf->period = now - inf->unblock_abs; /*check for overflow on multiplication*/ ASSERT((inf->period < ULONG_MAX) && (inf->slice_orig < ULONG_MAX)); @@ -992,18 +1030,18 @@ static inline void unblock_short_burst(struct sedf_dom_info* inf, s_time_t now) inf->slice = (inf->period * inf->slice_orig) / inf->period_orig; /*set new (shorter) deadline*/ - inf->absdead += inf->period; + inf->deadl_abs += inf->period; } else { /*in case we haven't unblocked before start in next period!*/ inf->cputime=0; - inf->absdead += inf->period; + inf->deadl_abs += inf->period; } } - inf->absunblock = now; + inf->unblock_abs = now; } -static inline void unblock_long_burst(struct sedf_dom_info* inf,s_time_t now) { +static inline void unblock_long_burst(struct sedf_edom_info* inf, s_time_t now) { if (unlikely(inf->latency && (inf->period > inf->latency))) { /*scale the slice and period accordingly to the latency hint*/ inf->period = inf->latency; @@ -1013,7 +1051,7 @@ static inline void unblock_long_burst(struct sedf_dom_info* inf,s_time_t now) { /*scale slice accordingly, so that utilisation stays the same*/ inf->slice = (inf->period * inf->slice_orig) / inf->period_orig; - inf->absdead = now + inf->period; + inf->deadl_abs = now + inf->period; inf->cputime = 0; } else { @@ -1023,16 +1061,16 @@ static inline void unblock_long_burst(struct sedf_dom_info* inf,s_time_t now) { when we are in sync with the device!*/ unblock_long_cons_b(inf, now); } - inf->absunblock = now; + inf->unblock_abs = now; } #define DOMAIN_EDF 1 #define DOMAIN_EXTRA_PEN 2 #define DOMAIN_EXTRA_UTIL 3 #define DOMAIN_IDLE 4 -static inline int get_run_type(struct domain* d) { - struct sedf_dom_info* inf = DOM_INFO(d); - if (is_idle_task(d)) +static inline int get_run_type(struct exec_domain* d) { + struct sedf_edom_info* inf = EDOM_INFO(d); + if (is_idle_task(d->domain)) return DOMAIN_IDLE; if (inf->extra & EXTRA_RUN_PEN) return DOMAIN_EXTRA_PEN; @@ -1049,11 +1087,11 @@ static inline int get_run_type(struct domain* d) { In the same class priorities are assigned as following: EDF: early deadline > late deadline L0 extra-time: lower score > higher score*/ -static inline int should_switch(struct domain* cur, struct domain* other, - s_time_t now) { - struct sedf_dom_info *cur_inf, *other_inf; - cur_inf = DOM_INFO(cur); - other_inf = DOM_INFO(other); +static inline int should_switch(struct exec_domain* cur, + struct exec_domain* other, s_time_t now) { + struct sedf_edom_info *cur_inf, *other_inf; + cur_inf = EDOM_INFO(cur); + other_inf = EDOM_INFO(other); /*check whether we need to make an earlier sched-decision*/ if ((PERIOD_BEGIN(other_inf) < @@ -1082,32 +1120,35 @@ static inline int should_switch(struct domain* cur, struct domain* other, return 1; } } -void sedf_wake(struct domain *d) { +void sedf_wake(struct exec_domain *d) { s_time_t now = NOW(); - struct sedf_dom_info* inf = DOM_INFO(d); + struct sedf_edom_info* inf = EDOM_INFO(d); - PRINT(3,"sedf_wake was called, domain-id %i\n",d->id); + PRINT(3,"sedf_wake was called, domain-id %i.%i\n",d->domain->id, d->eid); - if (unlikely(is_idle_task(d))) + if (unlikely(is_idle_task(d->domain))) return; if ( unlikely(__task_on_queue(d)) ) { - PRINT(3,"\tdomain %i is already in some queue\n",d->id); + PRINT(3,"\tdomain %i.%i is already in some queue\n", + d->domain->id, d->eid); return; } if ( unlikely(extraq_on(d,EXTRA_UTIL_Q) || extraq_on(d,EXTRA_PEN_Q)) ) { - PRINT(3,"\tdomain %i is already in the extraQ\n",d->id); + PRINT(3,"\tdomain %i.%i is already in the extraQ\n", + d->domain->id, d->eid); } - if (unlikely(inf->absdead == 0)) + if (unlikely(inf->deadl_abs == 0)) /*initial setup of the deadline*/ - inf->absdead = now + inf->slice; + inf->deadl_abs = now + inf->slice; - PRINT(3,"waking up domain %i (deadl= %llu period= %llu "\ - "now= %llu)\n",d->id,inf->absdead,inf->period,now); + PRINT(3,"waking up domain %i.%i (deadl= %llu period= %llu "\ + "now= %llu)\n", d->domain->id, d->eid, inf->deadl_abs, + inf->period, now); #ifdef SEDF_STATS inf->block_tot++; #endif - if (unlikely(now< PERIOD_BEGIN(inf))) { + if (unlikely(now < PERIOD_BEGIN(inf))) { PRINT(4,"extratime unblock\n"); /*this might happen, imagine unblocking in extra-time!*/ #if (EXTRA == EXTRA_BLOCK_WEIGHT) @@ -1134,7 +1175,7 @@ void sedf_wake(struct domain *d) { /*This is very very unlikely, ie. might even be an error?!*/ } else { - if (now < inf->absdead) { + if (now < inf->deadl_abs) { PRINT(4,"short unblocking\n"); /*short blocking*/ #ifdef SEDF_STATS @@ -1194,24 +1235,25 @@ void sedf_wake(struct domain *d) { } } - PRINT(3,"woke up domain %i (deadl= %llu period= %llu "\ - "now= %llu)\n",d->id,inf->absdead,inf->period,now); + PRINT(3,"woke up domain %i.%i (deadl= %llu period= %llu "\ + "now= %llu)\n", d->domain->id, d->eid, inf->deadl_abs, + inf->period, now); __add_to_waitqueue_sort(d); PRINT(3,"added to waitq\n"); #ifdef SEDF_STATS /*do some statistics here...*/ - if (inf->absblock != 0) { - inf->block_time_tot += now - inf->absblock; + if (inf->block_abs != 0) { + inf->block_time_tot += now - inf->block_abs; inf->penalty_time_tot += - PERIOD_BEGIN(inf) + inf->cputime - inf->absblock; + PERIOD_BEGIN(inf) + inf->cputime - inf->block_abs; } #endif /*sanity check: make sure each extra-aware domain IS on the util-q!*/ /*if (inf->extra & EXTRA_AWARE) { if (!extraq_on(d, EXTRA_UTIL_Q)) - printf("sedf_wake: domain %i is extra-aware, "\ - "but NOT on L1 extraq!\n",d->id); + printf("sedf_wake: domain %i.%i is extra-aware, "\ + "but NOT on L1 extraq!\n",d->domain->id, d->eid); }*/ /*check whether the awakened task needs to invoke the do_schedule @@ -1226,34 +1268,34 @@ void sedf_wake(struct domain *d) { } /*Print a lot of use-{full, less} information about a domains in the system*/ -static void sedf_dump_domain(struct domain *d) { - printk("%u has=%c ", d->id, - test_bit(DF_RUNNING, &d->flags) ? 'T':'F'); +static void sedf_dump_domain(struct exec_domain *d) { + printk("%i.%i has=%c ", d->domain->id, d->eid, + test_bit(EDF_RUNNING, &d->ed_flags) ? 'T':'F'); printk("p=%llu sl=%llu ddl=%llu w=%hu c=%llu sc=%i xtr(%s)=%llu", - DOM_INFO(d)->period, DOM_INFO(d)->slice, DOM_INFO(d)->absdead, - DOM_INFO(d)->weight, d->cpu_time, DOM_INFO(d)->score[EXTRA_UTIL_Q], - (DOM_INFO(d)->extra & EXTRA_AWARE) ? "yes" : "no", - DOM_INFO(d)->extra_time_tot); + EDOM_INFO(d)->period, EDOM_INFO(d)->slice, EDOM_INFO(d)->deadl_abs, + EDOM_INFO(d)->weight, d->cpu_time, EDOM_INFO(d)->score[EXTRA_UTIL_Q], + (EDOM_INFO(d)->extra & EXTRA_AWARE) ? "yes" : "no", + EDOM_INFO(d)->extra_time_tot); if (d->cpu_time !=0) - printf(" (%lu%)", (DOM_INFO(d)->extra_time_tot * 100) + printf(" (%lu%)", (EDOM_INFO(d)->extra_time_tot * 100) / d->cpu_time); #ifdef SEDF_STATS - if (DOM_INFO(d)->block_time_tot!=0) - printf(" pen=%lu%", (DOM_INFO(d)->penalty_time_tot * 100) / - DOM_INFO(d)->block_time_tot); - if (DOM_INFO(d)->block_tot!=0) + if (EDOM_INFO(d)->block_time_tot!=0) + printf(" pen=%lu%", (EDOM_INFO(d)->penalty_time_tot * 100) / + EDOM_INFO(d)->block_time_tot); + if (EDOM_INFO(d)->block_tot!=0) printf("\n blks=%lu sh=%lu (%lu%) (shc=%lu (%lu%) shex=%i "\ "shexsl=%i) l=%lu (%lu%) avg: b=%llu p=%llu", - DOM_INFO(d)->block_tot, DOM_INFO(d)->short_block_tot, - (DOM_INFO(d)->short_block_tot * 100) - / DOM_INFO(d)->block_tot, DOM_INFO(d)->short_cont, - (DOM_INFO(d)->short_cont * 100) / DOM_INFO(d)->block_tot, - DOM_INFO(d)->pen_extra_blocks, - DOM_INFO(d)->pen_extra_slices, - DOM_INFO(d)->long_block_tot, - (DOM_INFO(d)->long_block_tot * 100) / DOM_INFO(d)->block_tot, - (DOM_INFO(d)->block_time_tot) / DOM_INFO(d)->block_tot, - (DOM_INFO(d)->penalty_time_tot) / DOM_INFO(d)->block_tot); + EDOM_INFO(d)->block_tot, EDOM_INFO(d)->short_block_tot, + (EDOM_INFO(d)->short_block_tot * 100) + / EDOM_INFO(d)->block_tot, EDOM_INFO(d)->short_cont, + (EDOM_INFO(d)->short_cont * 100) / EDOM_INFO(d)->block_tot, + EDOM_INFO(d)->pen_extra_blocks, + EDOM_INFO(d)->pen_extra_slices, + EDOM_INFO(d)->long_block_tot, + (EDOM_INFO(d)->long_block_tot * 100) / EDOM_INFO(d)->block_tot, + (EDOM_INFO(d)->block_time_tot) / EDOM_INFO(d)->block_tot, + (EDOM_INFO(d)->penalty_time_tot) / EDOM_INFO(d)->block_tot); #endif printf("\n"); } @@ -1261,10 +1303,11 @@ static void sedf_dump_domain(struct domain *d) { /*dumps all domains on hte specified cpu*/ static void sedf_dump_cpu_state(int i) { - struct list_head *list, *queue, *tmp; + struct list_head *list, *queue, *tmp; + struct sedf_edom_info *d_inf; + struct domain *d; + struct exec_domain *ed; int loop = 0; - struct sedf_dom_info *d_inf; - struct domain* d; printk("now=%llu\n",NOW()); queue = RUNQ(i); @@ -1272,8 +1315,8 @@ static void sedf_dump_cpu_state(int i) (unsigned long) queue->next, (unsigned long) queue->prev); list_for_each_safe ( list, tmp, queue ) { printk("%3d: ",loop++); - d_inf = list_entry(list, struct sedf_dom_info, list); - sedf_dump_domain(d_inf->owner); + d_inf = list_entry(list, struct sedf_edom_info, list); + sedf_dump_domain(d_inf->exec_domain); } queue = WAITQ(i); loop = 0; @@ -1281,8 +1324,8 @@ static void sedf_dump_cpu_state(int i) (unsigned long) queue->next, (unsigned long) queue->prev); list_for_each_safe ( list, tmp, queue ) { printk("%3d: ",loop++); - d_inf = list_entry(list, struct sedf_dom_info, list); - sedf_dump_domain(d_inf->owner); + d_inf = list_entry(list, struct sedf_edom_info, list); + sedf_dump_domain(d_inf->exec_domain); } queue = EXTRAQ(i,EXTRA_PEN_Q); loop = 0; @@ -1290,10 +1333,10 @@ static void sedf_dump_cpu_state(int i) (unsigned long)queue, (unsigned long) queue->next, (unsigned long) queue->prev); list_for_each_safe ( list, tmp, queue ) { - d_inf = list_entry(list, struct sedf_dom_info, + d_inf = list_entry(list, struct sedf_edom_info, extralist[EXTRA_PEN_Q]); printk("%3d: ",loop++); - sedf_dump_domain(d_inf->owner); + sedf_dump_domain(d_inf->exec_domain); } queue = EXTRAQ(i,EXTRA_UTIL_Q); loop = 0; @@ -1301,36 +1344,40 @@ static void sedf_dump_cpu_state(int i) (unsigned long)queue, (unsigned long) queue->next, (unsigned long) queue->prev); list_for_each_safe ( list, tmp, queue ) { - d_inf = list_entry(list, struct sedf_dom_info, + d_inf = list_entry(list, struct sedf_edom_info, extralist[EXTRA_UTIL_Q]); printk("%3d: ",loop++); - sedf_dump_domain(d_inf->owner); + sedf_dump_domain(d_inf->exec_domain); } loop = 0; printk("\nnot on Q\n"); - for_each_domain(d) { - if (!__task_on_queue(d) && (d->processor == i)) { - printk("%3d: ",loop++); - sedf_dump_domain(d); + for_each_domain(d) + for_each_exec_domain(d, ed) + { + if (!__task_on_queue(ed) && (ed->processor == i)) { + printk("%3d: ",loop++); + sedf_dump_domain(ed); + } } - } } /*Adjusts periods and slices of the domains accordingly to their weights*/ -static inline int sedf_adjust_weights(struct domain *p, -struct sched_adjdom_cmd *cmd) { - int sumw[NR_CPUS]; - s_time_t sumt[NR_CPUS]; - int cpu; +static inline int sedf_adjust_weights(struct sched_adjdom_cmd *cmd) { + struct exec_domain *p; + struct domain *d; + int sumw[NR_CPUS]; + s_time_t sumt[NR_CPUS]; + int cpu; for (cpu=0; cpu < NR_CPUS; cpu++) { sumw[cpu] = 0; sumt[cpu] = 0; } /*sum up all weights*/ - for_each_domain(p) { - if (DOM_INFO(p)->weight) - sumw[p->processor] += DOM_INFO(p)->weight; + for_each_domain(d) + for_each_exec_domain(d, p) { + if (EDOM_INFO(p)->weight) + sumw[p->processor] += EDOM_INFO(p)->weight; else { /*don't modify domains who don't have a weight, but sum up the time they need, projected to a WEIGHT_PERIOD, @@ -1338,18 +1385,19 @@ struct sched_adjdom_cmd *cmd) { domains*/ /*check for overflows*/ ASSERT((WEIGHT_PERIOD < ULONG_MAX) - && (DOM_INFO(p)->slice_orig < ULONG_MAX)); + && (EDOM_INFO(p)->slice_orig < ULONG_MAX)); sumt[p->processor] += (WEIGHT_PERIOD * - DOM_INFO(p)->slice_orig) / DOM_INFO(p)->period_orig; + EDOM_INFO(p)->slice_orig) / EDOM_INFO(p)->period_orig; } } /*adjust all slices (and periods) to the new weight*/ - for_each_domain(p) { - if (DOM_INFO(p)->weight) { - DOM_INFO(p)->period_orig = - DOM_INFO(p)->period = WEIGHT_PERIOD; - DOM_INFO(p)->slice_orig = - DOM_INFO(p)->slice = (DOM_INFO(p)->weight * + for_each_domain(d) + for_each_exec_domain(d, p) { + if (EDOM_INFO(p)->weight) { + EDOM_INFO(p)->period_orig = + EDOM_INFO(p)->period = WEIGHT_PERIOD; + EDOM_INFO(p)->slice_orig = + EDOM_INFO(p)->slice = (EDOM_INFO(p)->weight * (WEIGHT_PERIOD -WEIGHT_SAFETY - sumt[p->processor])) / sumw[p->processor]; } @@ -1359,6 +1407,8 @@ struct sched_adjdom_cmd *cmd) { /* set or fetch domain scheduling parameters */ static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { + struct exec_domain *ed; + PRINT(2,"sedf_adjdom was called, domain-id %i new period %llu "\ "new slice %llu\nlatency %llu extra:%s\n", p->id, cmd->u.sedf.period, cmd->u.sedf.slice, @@ -1370,33 +1420,40 @@ static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { return -EINVAL; /*weight driven domains*/ if (cmd->u.sedf.weight) { - DOM_INFO(p)->weight = cmd->u.sedf.weight; + for_each_exec_domain(p, ed) + EDOM_INFO(ed)->weight = cmd->u.sedf.weight; } else { /*time driven domains*/ - DOM_INFO(p)->weight = 0; - /* sanity checking! */ - if(cmd->u.sedf.slice > cmd->u.sedf.period ) - return -EINVAL; - DOM_INFO(p)->period_orig = - DOM_INFO(p)->period = cmd->u.sedf.period; - DOM_INFO(p)->slice_orig = - DOM_INFO(p)->slice = cmd->u.sedf.slice; + for_each_exec_domain(p, ed) { + /* sanity checking! */ + if(cmd->u.sedf.slice > cmd->u.sedf.period ) + return -EINVAL; + EDOM_INFO(ed)->weight = 0; + EDOM_INFO(ed)->period_orig = + EDOM_INFO(ed)->period = cmd->u.sedf.period; + EDOM_INFO(ed)->slice_orig = + EDOM_INFO(ed)->slice = cmd->u.sedf.slice; + } } - if (sedf_adjust_weights(p,cmd)) + if (sedf_adjust_weights(cmd)) return -EINVAL; - DOM_INFO(p)->extra = (DOM_INFO(p)-> extra & ~EXTRA_AWARE) - | (cmd->u.sedf.extratime & EXTRA_AWARE); - DOM_INFO(p)->latency = cmd->u.sedf.latency; - extraq_check(p); + + for_each_exec_domain(p, ed) { + EDOM_INFO(ed)->extra = (EDOM_INFO(ed)->extra & + ~EXTRA_AWARE) | (cmd->u.sedf.extratime & EXTRA_AWARE); + EDOM_INFO(ed)->latency = cmd->u.sedf.latency; + extraq_check(ed); + } } else if ( cmd->direction == SCHED_INFO_GET ) { - cmd->u.sedf.period = DOM_INFO(p)->period; - cmd->u.sedf.slice = DOM_INFO(p)->slice; - cmd->u.sedf.extratime = DOM_INFO(p)->extra & EXTRA_AWARE; - cmd->u.sedf.latency = DOM_INFO(p)->latency; - cmd->u.sedf.weight = DOM_INFO(p)->weight; + cmd->u.sedf.period = EDOM_INFO(p->exec_domain[0])->period; + cmd->u.sedf.slice = EDOM_INFO(p->exec_domain[0])->slice; + cmd->u.sedf.extratime = EDOM_INFO(p->exec_domain[0])->extra + & EXTRA_AWARE; + cmd->u.sedf.latency = EDOM_INFO(p->exec_domain[0])->latency; + cmd->u.sedf.weight = EDOM_INFO(p->exec_domain[0])->weight; } PRINT(2,"sedf_adjdom_finished\n"); return 0; From 155e2fe95d7dfe6bf60fafce3e8ebcf3e8fd6105 Mon Sep 17 00:00:00 2001 From: "sd386@font.cl.cam.ac.uk" Date: Mon, 2 May 2005 15:49:43 +0000 Subject: [PATCH 11/54] bitkeeper revision 1.1346.1.3 (42764c17j3s2X1M-F05_xvwcUN6KPA) Port of the sedf scheduler to unstable tree. Signed-off: Stephan.Diestelhorst@{cl.cam.ac.uk , inf.tu-dresden.de} --- xen/common/sched_sedf.c | 497 ++++++++++++++++++++-------------------- xen/common/schedule.c | 45 +++- 2 files changed, 291 insertions(+), 251 deletions(-) diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c index 5c2eb80d56..893f861c89 100644 --- a/xen/common/sched_sedf.c +++ b/xen/common/sched_sedf.c @@ -1,4 +1,4 @@ -/**************************************************************************** +/******************************************************************************* * Simple EDF scheduler for xen * * by Stephan Diestelhorst (C) 2004 Cambridge University @@ -20,8 +20,13 @@ #define PRINT(_f, _a...) \ if ((_f)<=SEDFLEVEL) printk(_a ); -#ifdef DEBUG +#ifndef NDEBUG #define SEDF_STATS + #define CHECK(_p) if ( !(_p) ) \ + { printk("Check '%s' failed, line %d, file %s\n", #_p , __LINE__,\ + __FILE__);} +#else + #define CHECK(_p) ((void)0) #endif /*various ways of unblocking domains*/ @@ -48,14 +53,16 @@ if ((_f)<=SEDFLEVEL) printk(_a ); #define EXTRA_WANT_PEN_Q (8) #define EXTRA_PEN_Q (0) #define EXTRA_UTIL_Q (1) - -#define extra_runs(inf) ((inf->extra) & 6) -#define extra_get_cur_q(inf) (((inf->extra & 6) >> 1)-1) +#define SEDF_ASLEEP (16) #define EXTRA_QUANTUM (MICROSECS(500)) #define WEIGHT_PERIOD (MILLISECS(100)) #define WEIGHT_SAFETY (MILLISECS(5)) +#define IMPLY(a, b) (!(a) || (b)) +#define EQ(a, b) ((!!(a)) == (!!(b))) + + struct sedf_dom_info { struct domain *domain; }; @@ -75,12 +82,12 @@ struct sedf_edom_info s_time_t slice_orig; s_time_t latency; - /*extra-time status of domain*/ - short extra; + /*status of domain*/ + int status; /*weights for "Scheduling for beginners/ lazy/ etc." ;)*/ short weight; - - /*Bookkeeping*/ + short extraweight; + /*Bookkeeping*/ s_time_t deadl_abs; s_time_t sched_start_abs; s_time_t cputime; @@ -127,6 +134,11 @@ struct sedf_cpu_info { #define MIN(x,y) (((x)<(y))?(x):(y)) #define DIV_UP(x,y) (((x) + (y) - 1) / y) +#define extra_runs(inf) ((inf->status) & 6) +#define extra_get_cur_q(inf) (((inf->status & 6) >> 1)-1) +#define sedf_runnable(edom) (!(EDOM_INFO(edom)->status & SEDF_ASLEEP)) + + static void sedf_dump_cpu_state(int i); static inline int extraq_on(struct exec_domain *d, int i) { @@ -137,25 +149,24 @@ static inline int extraq_on(struct exec_domain *d, int i) { static inline void extraq_add_head(struct exec_domain *d, int i) { list_add(EXTRALIST(d,i), EXTRAQ(d->processor,i)); + ASSERT(extraq_on(d, i)); } static inline void extraq_add_tail(struct exec_domain *d, int i) { list_add_tail(EXTRALIST(d,i), EXTRAQ(d->processor,i)); + ASSERT(extraq_on(d, i)); } static inline void extraq_del(struct exec_domain *d, int i) { struct list_head *list = EXTRALIST(d,i); - /*if (!extraq_on(d,i)) { - PRINT(0,"extraq_del: domain %i.%i is NOT on L%i extraq "\ - "HALTING\n",d->domain->id, d->eid,i); - sedf_dump_cpu_state(0);(*((int*)0))++; - }*/ + ASSERT(extraq_on(d,i)); PRINT(3, "Removing domain %i.%i from L%i extraq\n", d->domain->id, d->eid, i); list_del(list); list->next = NULL; + ASSERT(!extraq_on(d, i)); } /* adds a domain to the queue of processes which are aware of extra time. List @@ -168,11 +179,7 @@ static inline void extraq_add_sort_update(struct exec_domain *d, int i, int sub) struct list_head *cur; struct sedf_edom_info *curinf; - /*if (extraq_on(d,i)) { - PRINT(0,"extraq_add_sort_update: domain %i.%i is already on "\ - "L%i extraq! HALTING\n",d->domain->id, d->eid, i); - sedf_dump_cpu_state(0);(*((int*)0))++; - }*/ + ASSERT(!extraq_on(d,i)); PRINT(3, "Adding domain %i.%i (score= %i, short_pen= %lli) to L%i "\ "extraq\n", d->domain->id, d->eid, EDOM_INFO(d)->score[i], EDOM_INFO(d)->short_block_lost_tot, i); @@ -203,11 +210,12 @@ static inline void extraq_add_sort_update(struct exec_domain *d, int i, int sub) curinf->exec_domain->domain->id, curinf->exec_domain->eid, curinf->score[i]); } + ASSERT(extraq_on(d,i)); } static inline void extraq_check(struct exec_domain *d) { if (extraq_on(d, EXTRA_UTIL_Q)) { - PRINT(2,"Dom %i is on extraQ\n",d->domain->id, d->eid); - if (!(EDOM_INFO(d)->extra & EXTRA_AWARE) && + PRINT(2,"Dom %i.%i is on L1 extraQ\n",d->domain->id, d->eid); + if (!(EDOM_INFO(d)->status & EXTRA_AWARE) && !extra_runs(EDOM_INFO(d))) { extraq_del(d, EXTRA_UTIL_Q); PRINT(2,"Removed dom %i.%i from L1 extraQ\n", @@ -216,10 +224,9 @@ static inline void extraq_check(struct exec_domain *d) { } else { PRINT(2,"Dom %i.%i is NOT on L1 extraQ\n",d->domain->id, d->eid); - if ((EDOM_INFO(d)->extra & EXTRA_AWARE) && domain_runnable(d)) + if ((EDOM_INFO(d)->status & EXTRA_AWARE) && sedf_runnable(d)) { #if (EXTRA == EXTRA_ROUNDR) - /*Favour domains which got short unblocked*/ extraq_add_tail(d, EXTRA_UTIL_Q); #elif (EXTRA == EXTRA_SLICE_WEIGHT || \ EXTRA == EXTRA_BLOCK_WEIGHT) @@ -232,39 +239,78 @@ static inline void extraq_check(struct exec_domain *d) { } } } + +static inline void extraq_check_add_unblocked(struct exec_domain *d, + int priority) { + struct sedf_edom_info *inf = EDOM_INFO(d); + if (inf->status & EXTRA_AWARE) + #if (EXTRA == EXTRA_ROUNDR) + if (priority) + extraq_add_head(d,EXTRA_UTIL_Q); + else + extraq_add_tail(d,EXTRA_UTIL_Q); + #elif (EXTRA == EXTRA_SLICE_WEIGHT \ + || EXTRA == EXTRA_BLOCK_WEIGHT) + /*put in on the weighted extraq, + without updating any scores*/ + extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); + #else + ; + #endif +} + +static inline int __task_on_queue(struct exec_domain *d) { + return (((LIST(d))->next != NULL) && (LIST(d)->next != LIST(d))); +} static inline void __del_from_queue(struct exec_domain *d) { struct list_head *list = LIST(d); + ASSERT(__task_on_queue(d)); PRINT(3,"Removing domain %i.%i (bop= %llu) from runq/waitq\n", d->domain->id, d->eid, PERIOD_BEGIN(EDOM_INFO(d))); list_del(list); list->next = NULL; + ASSERT(!__task_on_queue(d)); } +typedef int(*list_comparer)(struct list_head* el1, struct list_head* el2); + +static inline void list_insert_sort(struct list_head *list, + struct list_head *element, list_comparer comp) { + struct list_head *cur; + /*iterate through all elements to find our "hole"*/ + list_for_each(cur,list){ + if (comp(element, cur) < 0) + break; + } + /*cur now contains the element, before which we'll enqueue*/ + PRINT(3,"\tlist_add to %x\n",cur->prev); + list_add(element, cur->prev); +} +#define DOMAIN_COMPARER(name, field, comp1, comp2) \ +int name##_comp(struct list_head* el1, struct list_head* el2) \ +{ \ + struct sedf_edom_info *d1, *d2; \ + d1 = list_entry(el1,struct sedf_edom_info, field); \ + d2 = list_entry(el2,struct sedf_edom_info, field); \ + if ((comp1) == (comp2)) \ + return 0; \ + if ((comp1) < (comp2)) \ + return -1; \ + else \ + return 1; \ +} /* adds a domain to the queue of processes which wait for the beginning of the next period; this list is therefore sortet by this time, which is simply absol. deadline - period */ +DOMAIN_COMPARER(waitq, list, PERIOD_BEGIN(d1), PERIOD_BEGIN(d2)) static inline void __add_to_waitqueue_sort(struct exec_domain *d) { - struct list_head *cur; - struct sedf_edom_info *curinf; - + ASSERT(!__task_on_queue(d)); PRINT(3,"Adding domain %i.%i (bop= %llu) to waitq\n", d->domain->id, - d->eid, PERIOD_BEGIN(EDOM_INFO(d))); - - /*iterate through all elements to find our "hole"*/ - list_for_each(cur, WAITQ(d->processor)){ - curinf = list_entry(cur,struct sedf_edom_info,list); - if (PERIOD_BEGIN(EDOM_INFO(d)) < PERIOD_BEGIN(curinf)) - break; - else - PRINT(4,"\tbehind domain %i.%i (bop= %llu)\n", - curinf->exec_domain->domain->id, - curinf->exec_domain->eid, PERIOD_BEGIN(curinf)); - } - /*cur now contains the element, before which we'll enqueue*/ - PRINT(3,"\tlist_add to %x\n",cur->prev); - list_add(LIST(d),cur->prev); + d->eid, PERIOD_BEGIN(EDOM_INFO(d))); + list_insert_sort(WAITQ(d->processor), LIST(d), waitq_comp); + ASSERT(__task_on_queue(d)); } /* adds a domain to the queue of processes which have started their current @@ -272,30 +318,11 @@ static inline void __add_to_waitqueue_sort(struct exec_domain *d) { on this list is running on the processor, if the list is empty the idle task will run. As we are implementing EDF, this list is sorted by deadlines. */ +DOMAIN_COMPARER(runq, list, d1->deadl_abs, d2->deadl_abs) static inline void __add_to_runqueue_sort(struct exec_domain *d) { - struct list_head *cur; - struct sedf_edom_info *curinf; - PRINT(3,"Adding domain %i.%i (deadl= %llu) to runq\n", d->domain->id, - d->eid, EDOM_INFO(d)->deadl_abs); - - /*iterate through all elements to find our "hole"*/ - list_for_each(cur, RUNQ(d->processor)) { - curinf = list_entry(cur, struct sedf_edom_info, list); - if (EDOM_INFO(d)->deadl_abs < curinf->deadl_abs) - break; - else - PRINT(4,"\tbehind domain %i.%i (deadl= %llu)\n", - curinf->exec_domain->domain->id, - curinf->exec_domain->eid, curinf->deadl_abs); - } - - /*cur now contains the element, before which we'll enqueue*/ - PRINT(3,"\tlist_add to %x\n",cur->prev); - list_add(LIST(d),cur->prev); -} -static inline int __task_on_queue(struct exec_domain *d) { - return (((LIST(d))->next != NULL) && (LIST(d)->next != LIST(d))); + d->eid, EDOM_INFO(d)->deadl_abs); + list_insert_sort(RUNQ(d->processor), LIST(d), runq_comp); } /* Initialises the queues */ @@ -313,15 +340,6 @@ static int sedf_init_scheduler() { INIT_LIST_HEAD(EXTRAQ(i,EXTRA_PEN_Q)); INIT_LIST_HEAD(EXTRAQ(i,EXTRA_UTIL_Q)); } -//TODO: Remove this stuff if things work! - /*dom_info_cache = xmem_cache_create("SEDF dom info", - sizeof(struct sedf_dom_info), 0, 0, 0, NULL); - if ( dom_info_cache == NULL ) - { - printk("Could not allocate SLAB cache.\n"); - return -1; - }*/ - return 0; } @@ -344,7 +362,7 @@ static int sedf_alloc_task(struct exec_domain *d) { /* Setup the sedf_dom_info */ static void sedf_add_task(struct exec_domain *d) { - struct sedf_edom_info *inf=EDOM_INFO(d); + struct sedf_edom_info *inf = EDOM_INFO(d); inf->exec_domain = d; PRINT(2,"sedf_add_task was called, domain-id %i.%i\n",d->domain->id, @@ -356,20 +374,25 @@ static void sedf_add_task(struct exec_domain *d) inf->slice = MILLISECS(15); inf->latency = 0; inf->deadl_abs = 0; - inf->extra = EXTRA_NONE;/*EXTRA_AWARE; */ + inf->status = EXTRA_NONE | SEDF_ASLEEP;/*EXTRA_AWARE; */ } else { /*other domains run in best effort mode*/ - inf->period = MILLISECS(20); + inf->period = WEIGHT_PERIOD; inf->slice = 0; inf->deadl_abs = 0; inf->latency = 0; - inf->extra = EXTRA_AWARE; + inf->status = EXTRA_AWARE | SEDF_ASLEEP; + inf->extraweight = 1; } inf->period_orig = inf->period; inf->slice_orig = inf->slice; INIT_LIST_HEAD(&(inf->list)); INIT_LIST_HEAD(&(inf->extralist[EXTRA_PEN_Q])); INIT_LIST_HEAD(&(inf->extralist[EXTRA_UTIL_Q])); + + if (d->domain->id != IDLE_DOMAIN_ID) { + extraq_check(d); + } } /* Frees memory used by domain info */ @@ -396,6 +419,7 @@ static int sedf_init_idle_task(struct exec_domain *d) { sedf_add_task(d); EDOM_INFO(d)->deadl_abs = 0; + EDOM_INFO(d)->status &= ~SEDF_ASLEEP; set_bit(EDF_RUNNING, &d->ed_flags); /*the idle task doesn't have to turn up on any list...*/ return 0; @@ -406,21 +430,17 @@ static inline void desched_edf_dom (s_time_t now, struct exec_domain* d) { struct sedf_edom_info* inf = EDOM_INFO(d); /*current domain is running in real time mode*/ + ASSERT(__task_on_queue(d)); /*update the domains cputime*/ inf->cputime += now - inf->sched_start_abs; /*scheduling decisions, which don't remove the running domain from the runq*/ - if ((inf->cputime < inf->slice) && domain_runnable(d)) + if ((inf->cputime < inf->slice) && sedf_runnable(d)) return; __del_from_queue(d); - /*if (__task_on_queue(d)) { - PRINT(0,"domain %i.%i was removed but still on run/waitq => "\ - "HALT\n",d->domain->id, d->eid); - sedf_dump_cpu_state(0);(*((int*)0))++; - }*/ - + /*manage bookkeeping (i.e. calculate next deadline, memorize overun-time of slice) of finished domains*/ if (inf->cputime >= inf->slice) { @@ -429,6 +449,8 @@ static inline void desched_edf_dom (s_time_t now, struct exec_domain* d) { if (inf->period < inf->period_orig) { /*this domain runs in latency scaling or burst mode*/ #if (UNBLOCK == UNBLOCK_BURST) + /*if we are runnig in burst scaling wait for two periods + before scaling periods up again*/ if (now - inf->unblock_abs >= 2 * inf->period) #endif { @@ -444,17 +466,12 @@ static inline void desched_edf_dom (s_time_t now, struct exec_domain* d) { /*set next deadline*/ inf->deadl_abs += inf->period; } - /*if (inf->deadl_abs < now) - printk("Domain %i.%i exceeded it't deadline!!!! "\ - "(now: %llu ddl: %llu)\n", d->domain->id, d->eid, now, - inf->deadl_abs);*/ - + /*add a runnable domain to the waitqueue*/ - if (domain_runnable(d)) + if (sedf_runnable(d)) __add_to_waitqueue_sort(d); else { /*we have a blocked realtime task -> remove it from exqs too*/ - inf->block_abs = now; #if (EXTRA > EXTRA_OFF) #if (EXTRA == EXTRA_BLOCK_WEIGHT) if (extraq_on(d, EXTRA_PEN_Q)) extraq_del(d, EXTRA_PEN_Q); @@ -462,6 +479,9 @@ static inline void desched_edf_dom (s_time_t now, struct exec_domain* d) { if (extraq_on(d, EXTRA_UTIL_Q)) extraq_del(d, EXTRA_UTIL_Q); #endif } + ASSERT(EQ(sedf_runnable(d), __task_on_queue(d))); + ASSERT(IMPLY(extraq_on(d, EXTRA_UTIL_Q) || extraq_on(d, EXTRA_PEN_Q), + sedf_runnable(d))); } /* Update all elements on the queues */ @@ -503,42 +523,41 @@ struct list_head* waitq) { curinf->deadl_abs += curinf->period; /*and put them back into the queue*/ __add_to_waitqueue_sort(curinf->exec_domain); + continue; } - else { - if (unlikely((curinf->deadl_abs < now) || - (curinf->cputime > curinf->slice))) { - /*we missed the deadline or the slice was - already finished... might hapen because - of dom_adj.*/ - PRINT(4,"\tDomain %i.%i exceeded it's deadline/"\ - "slice (%llu / %llu) now: %llu "\ - "cputime: %llu\n", - curinf->exec_domain->domain->id, - curinf->exec_domain->eid, - curinf->deadl_abs, curinf->slice, now, - curinf->cputime); - __del_from_queue(curinf->exec_domain); - /*common case: we miss one period!*/ - curinf->deadl_abs += curinf->period; - - /*if we are still behind: modulo arithmetic, - force deadline to be in future and - aligned to period borders!*/ - if (unlikely(curinf->deadl_abs < now)) - curinf->deadl_abs += - DIV_UP(now - curinf->deadl_abs, - curinf->period) * curinf->period; - ASSERT(curinf->deadl_abs > now); - /*give a fresh slice*/ - curinf->cputime = 0; - if (PERIOD_BEGIN(curinf) > now) - __add_to_waitqueue_sort(curinf->exec_domain); - else - __add_to_runqueue_sort(curinf->exec_domain); - } + if (unlikely((curinf->deadl_abs < now) || + (curinf->cputime > curinf->slice))) { + /*we missed the deadline or the slice was + already finished... might hapen because + of dom_adj.*/ + PRINT(4,"\tDomain %i.%i exceeded it's deadline/"\ + "slice (%llu / %llu) now: %llu "\ + "cputime: %llu\n", + curinf->exec_domain->domain->id, + curinf->exec_domain->eid, + curinf->deadl_abs, curinf->slice, now, + curinf->cputime); + __del_from_queue(curinf->exec_domain); + /*common case: we miss one period!*/ + curinf->deadl_abs += curinf->period; + + /*if we are still behind: modulo arithmetic, + force deadline to be in future and + aligned to period borders!*/ + if (unlikely(curinf->deadl_abs < now)) + curinf->deadl_abs += + DIV_UP(now - curinf->deadl_abs, + curinf->period) * curinf->period; + ASSERT(curinf->deadl_abs > now); + /*give a fresh slice*/ + curinf->cputime = 0; + if (PERIOD_BEGIN(curinf) > now) + __add_to_waitqueue_sort(curinf->exec_domain); else - break; + __add_to_runqueue_sort(curinf->exec_domain); } + else + break; } PRINT(3,"done updating the queues\n"); } @@ -554,12 +573,12 @@ static inline void desched_extra_dom(s_time_t now, struct exec_domain* d) { struct sedf_edom_info *inf = EDOM_INFO(d); int i = extra_get_cur_q(inf); - #if (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) +#if (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) unsigned long oldscore; - #endif - +#endif + ASSERT(extraq_on(d, i)); /*unset all running flags*/ - inf->extra &= ~(EXTRA_RUN_PEN | EXTRA_RUN_UTIL); + inf->status &= ~(EXTRA_RUN_PEN | EXTRA_RUN_UTIL); /*fresh slice for the next run*/ inf->cputime = 0; /*accumulate total extratime*/ @@ -567,14 +586,14 @@ static inline void desched_extra_dom(s_time_t now, struct exec_domain* d) { /*remove extradomain from head of the queue*/ extraq_del(d, i); - #if (EXTRA == EXTRA_ROUNDR) - if (domain_runnable(d)) +#if (EXTRA == EXTRA_ROUNDR) + if (sedf_runnable(d) && (inf->status & EXTRA_AWARE)) /*add to the tail if it is runnable => round-robin*/ extraq_add_tail(d, EXTRA_UTIL_Q); - #elif (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) +#elif (EXTRA == EXTRA_SLICE_WEIGHT || EXTRA == EXTRA_BLOCK_WEIGHT) /*update the score*/ oldscore = inf->score[i]; - #if (EXTRA == EXTRA_BLOCK_WEIGHT) +#if (EXTRA == EXTRA_BLOCK_WEIGHT) if (i == EXTRA_PEN_Q) { /*domain was running in L0 extraq*/ /*reduce block lost, probably more sophistication here!*/ @@ -589,9 +608,8 @@ static inline void desched_extra_dom(s_time_t now, struct exec_domain* d) { /*we have (over-)compensated our block penalty*/ inf->short_block_lost_tot = 0; /*we don't want a place on the penalty queue anymore!*/ - inf->extra &= ~EXTRA_WANT_PEN_Q; - /*do not add us on this block extraq again!*/ - return; + inf->status &= ~EXTRA_WANT_PEN_Q; + goto check_extra_queues; } /*we have to go again for another try in the block-extraq, the score is not used incremantally here, as this is @@ -600,33 +618,32 @@ static inline void desched_extra_dom(s_time_t now, struct exec_domain* d) { inf->short_block_lost_tot; oldscore = 0; } else - #endif +#endif { /*domain was running in L1 extraq => score is inverse of utilization and is used somewhat incremental!*/ -//TODO: Check for weights => use them for calculating the score! - if (inf->slice) + if (!inf->extraweight) /*NB: use fixed point arithmetic with 10 bits*/ inf->score[EXTRA_UTIL_Q] = (inf->period << 10) / inf->slice; else - /*set best effort domains to the maximum value*/ - inf->score[EXTRA_UTIL_Q] = 2^10; + /*give a domain w/ exweight = 1 as much as a domain with + util = 1/128*/ + inf->score[EXTRA_UTIL_Q] = (1<<17) / inf->extraweight; } - if (domain_runnable(d)) +check_extra_queues: + /* Adding a runnable domain to the right queue and removing blocked ones*/ + if (sedf_runnable(d)) { /*add according to score: weighted round robin*/ - extraq_add_sort_update(d, i, oldscore); + if (inf->status & (EXTRA_AWARE | EXTRA_WANT_PEN_Q)) + extraq_add_sort_update(d, i, oldscore); + } else { - inf->block_abs = now; - /*if (!__task_on_queue(d)) - printf("Oops... We attempt to remove d %i.%i from the "\ - "waitq, but it is not on :(\n", d->domain->id, - d->eid);*/ /*remove this blocked domain from the waitq!*/ - __del_from_queue(d); + __del_from_queue(d); +#if (EXTRA == EXTRA_BLOCK_WEIGHT) /*make sure that we remove a blocked domain from the other - extraq aswell (this caused hours of debugging!)*/ - #if (EXTRA == EXTRA_BLOCK_WEIGHT) + extraq too*/ if (i == EXTRA_PEN_Q) { if (extraq_on(d, EXTRA_UTIL_Q)) extraq_del(d, EXTRA_UTIL_Q); @@ -635,25 +652,17 @@ static inline void desched_extra_dom(s_time_t now, struct exec_domain* d) { if (extraq_on(d, EXTRA_PEN_Q)) extraq_del(d, EXTRA_PEN_Q); } - #endif +#endif } - #endif - /*if (!domain_runnable(d)) { - if (extraq_on(d, EXTRA_UTIL_Q)) { - PRINT(0,"domain %i.%i is blocked but still on L1 "\ - "xq=> HALT\n",d->domain->id, d->eid); - sedf_dump_cpu_state(0);(*((int*)0))++; - } - if (__task_on_queue(d)) { - PRINT(0,"domain %i.%i is blocked but still on run/waitq"\ - "=> HALT\n",d->domain->id, d->eid); - sedf_dump_cpu_state(0);(*((int*)0))++; - } - }*/ +#endif + ASSERT(EQ(sedf_runnable(d), __task_on_queue(d))); + ASSERT(IMPLY(extraq_on(d, EXTRA_UTIL_Q) || extraq_on(d, EXTRA_PEN_Q), + sedf_runnable(d))); } #endif -static inline struct task_slice sedf_do_extra_schedule (s_time_t now, s_time_t end_xt, struct list_head *extraq[], int cpu) { +static inline struct task_slice sedf_do_extra_schedule (s_time_t now, + s_time_t end_xt, struct list_head *extraq[], int cpu) { struct task_slice ret; struct sedf_edom_info *runinf; @@ -666,7 +675,7 @@ static inline struct task_slice sedf_do_extra_schedule (s_time_t now, s_time_t e => let those run first!*/ runinf = list_entry(extraq[EXTRA_PEN_Q]->next, struct sedf_edom_info, extralist[EXTRA_PEN_Q]); - runinf->extra |= EXTRA_RUN_PEN; + runinf->status |= EXTRA_RUN_PEN; ret.task = runinf->exec_domain; ret.time = EXTRA_QUANTUM; #ifdef SEDF_STATS @@ -678,18 +687,22 @@ static inline struct task_slice sedf_do_extra_schedule (s_time_t now, s_time_t e /*use elements from the normal extraqueue*/ runinf = list_entry(extraq[EXTRA_UTIL_Q]->next, struct sedf_edom_info, extralist[EXTRA_UTIL_Q]); - runinf->extra |= EXTRA_RUN_UTIL; + runinf->status |= EXTRA_RUN_UTIL; ret.task = runinf->exec_domain; ret.time = EXTRA_QUANTUM; } else goto return_idle; + ASSERT(ret.time > 0); + ASSERT(sedf_runnable(ret.task)); return ret; return_idle: ret.task = IDLETASK(cpu); ret.time = end_xt - now; + ASSERT(ret.time > 0); + ASSERT(sedf_runnable(ret.task)); return ret; } /* Main scheduling function @@ -713,32 +726,25 @@ static struct task_slice sedf_do_schedule(s_time_t now) if (is_idle_task(current->domain)) goto check_waitq; + /* create local state of the status of the domain, in order to avoid + inconsistent state during scheduling decisions, because data for + domain_runnable is not protected by the scheduling lock!*/ + if(!domain_runnable(current)) + inf->status |= SEDF_ASLEEP; + + if (inf->status & SEDF_ASLEEP) + inf->block_abs = now; + #if (EXTRA > EXTRA_OFF) if (unlikely(extra_runs(inf))) { - /*i=1;*/ /*special treatment of domains running in extra time*/ desched_extra_dom(now, current); } else #endif { - /*i=2;*/ desched_edf_dom(now, current); } - /*if (!domain_runnable(current)) { - if (extraq_on(current,EXTRA_UTIL_Q)) { - PRINT(0,"domain %i.%i is blocked but still on L1 xq"\ - " branch %i=> HALT\n", current->domain->id, - current->eid, i); - sedf_dump_cpu_state(0);(*((int*)0))++; - } - if (__task_on_queue(current)) { - PRINT(0,"domain %i.%i is blocked but still on run/waitq"\ - " branch %i=> HALT\n",current->domain->id, - d->eid,i); - sedf_dump_cpu_state(0);(*((int*)0))++; - } - }*/ check_waitq: update_queues(now, runq, waitq); @@ -761,7 +767,7 @@ check_waitq: else { ret.time = runinf->slice - runinf->cputime; } - ASSERT(ret.time > now); + CHECK(ret.time > 0); goto sched_done; } @@ -776,7 +782,7 @@ check_waitq: ret.task = IDLETASK(cpu); ret.time = PERIOD_BEGIN(waitinf) - now; #endif - ASSERT(ret.time > now); + CHECK(ret.time > 0); } else { /*this could probably never happen, but one never knows...*/ @@ -795,11 +801,19 @@ sched_done: ret.time = EXTRA_QUANTUM; } EDOM_INFO(ret.task)->sched_start_abs = now; + CHECK(ret.time > 0); + ASSERT(sedf_runnable(ret.task)); return ret; } static void sedf_sleep(struct exec_domain *d) { PRINT(2,"sedf_sleep was called, domain-id %i.%i\n",d->domain->id, d->eid); + + if (is_idle_task(d->domain)) + return; + + EDOM_INFO(d)->status |= SEDF_ASLEEP; + if ( test_bit(EDF_RUNNING, &d->ed_flags) ) { #ifdef ADV_SCHED_HISTO adv_sched_hist_start(d->processor); @@ -946,7 +960,7 @@ static inline void unblock_short_extra_support (struct sedf_edom_info* inf, /*remember that we want to be on the penalty q so that we can continue when we (un-)block in penalty-extratime*/ - inf->extra |= EXTRA_WANT_PEN_Q; + inf->status |= EXTRA_WANT_PEN_Q; /*(re-)add domain to the penalty extraq*/ extraq_add_sort_update(inf->exec_domain, @@ -1072,9 +1086,9 @@ static inline int get_run_type(struct exec_domain* d) { struct sedf_edom_info* inf = EDOM_INFO(d); if (is_idle_task(d->domain)) return DOMAIN_IDLE; - if (inf->extra & EXTRA_RUN_PEN) + if (inf->status & EXTRA_RUN_PEN) return DOMAIN_EXTRA_PEN; - if (inf->extra & EXTRA_RUN_UTIL) + if (inf->status & EXTRA_RUN_UTIL) return DOMAIN_EXTRA_UTIL; return DOMAIN_EDF; } @@ -1105,7 +1119,7 @@ static inline int should_switch(struct exec_domain* cur, case DOMAIN_EXTRA_PEN: /*check whether we also want the L0 ex-q with lower score*/ - if ((other_inf->extra & EXTRA_WANT_PEN_Q) + if ((other_inf->status & EXTRA_WANT_PEN_Q) && (other_inf->score[EXTRA_PEN_Q] < cur_inf->score[EXTRA_PEN_Q])) return 1; @@ -1113,31 +1127,33 @@ static inline int should_switch(struct exec_domain* cur, case DOMAIN_EXTRA_UTIL: /*check whether we want the L0 extraq, don't switch if both domains want L1 extraq */ - if (other_inf->extra & EXTRA_WANT_PEN_Q) + if (other_inf->status & EXTRA_WANT_PEN_Q) return 1; else return 0; case DOMAIN_IDLE: return 1; } + return 1; } void sedf_wake(struct exec_domain *d) { s_time_t now = NOW(); struct sedf_edom_info* inf = EDOM_INFO(d); - PRINT(3,"sedf_wake was called, domain-id %i.%i\n",d->domain->id, d->eid); + PRINT(3, "sedf_wake was called, domain-id %i.%i\n",d->domain->id, d->eid); if (unlikely(is_idle_task(d->domain))) return; - + if ( unlikely(__task_on_queue(d)) ) { PRINT(3,"\tdomain %i.%i is already in some queue\n", d->domain->id, d->eid); return; } - if ( unlikely(extraq_on(d,EXTRA_UTIL_Q) || extraq_on(d,EXTRA_PEN_Q)) ) { - PRINT(3,"\tdomain %i.%i is already in the extraQ\n", - d->domain->id, d->eid); - } + ASSERT(!sedf_runnable(d)); + inf->status &= ~SEDF_ASLEEP; + ASSERT(!extraq_on(d, EXTRA_UTIL_Q)); + ASSERT(!extraq_on(d, EXTRA_PEN_Q)); + if (unlikely(inf->deadl_abs == 0)) /*initial setup of the deadline*/ inf->deadl_abs = now + inf->slice; @@ -1150,9 +1166,9 @@ void sedf_wake(struct exec_domain *d) { #endif if (unlikely(now < PERIOD_BEGIN(inf))) { PRINT(4,"extratime unblock\n"); - /*this might happen, imagine unblocking in extra-time!*/ + /* unblocking in extra-time! */ #if (EXTRA == EXTRA_BLOCK_WEIGHT) - if (inf->extra & EXTRA_WANT_PEN_Q) { + if (inf->status & EXTRA_WANT_PEN_Q) { /*we have a domain that wants compensation for block penalty and did just block in its compensation time. Give it another @@ -1160,19 +1176,7 @@ void sedf_wake(struct exec_domain *d) { extraq_add_sort_update(d, EXTRA_PEN_Q, 0); } #endif - if (inf->extra & EXTRA_AWARE) - #if (EXTRA == EXTRA_ROUNDR) - extraq_add_tail(d,EXTRA_UTIL_Q); - #elif (EXTRA == EXTRA_SLICE_WEIGHT \ - || EXTRA == EXTRA_BLOCK_WEIGHT) - /*put in on the weighted extraq, - without updating any scores*/ - extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); - #else - ; - #endif - /*else*/ - /*This is very very unlikely, ie. might even be an error?!*/ + extraq_check_add_unblocked(d, 0); } else { if (now < inf->deadl_abs) { @@ -1191,16 +1195,7 @@ void sedf_wake(struct exec_domain *d) { unblock_short_extra_support(inf, now); #endif - if (inf->extra & EXTRA_AWARE) - #if (EXTRA == EXTRA_OFF) - ; - #elif (EXTRA == EXTRA_ROUNDR) - /*Favour domains which got short unblocked*/ - extraq_add_head(d, EXTRA_UTIL_Q); - #elif (EXTRA == EXTRA_SLICE_WEIGHT \ - || EXTRA == EXTRA_BLOCK_WEIGHT) - extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); - #endif + extraq_check_add_unblocked(d, 1); } else { PRINT(4,"long unblocking\n"); @@ -1221,25 +1216,21 @@ void sedf_wake(struct exec_domain *d) { #elif (UNBLOCK == UNBLOCK_BURST) unblock_long_burst(inf, now); #endif - - if (inf->extra & EXTRA_AWARE) { - #if (EXTRA == EXTRA_OFF) - ; - #elif (EXTRA == EXTRA_ROUNDR) - extraq_add_head(d, EXTRA_UTIL_Q); - #elif (EXTRA == EXTRA_SLICE_WEIGHT \ - || EXTRA == EXTRA_BLOCK_WEIGHT) - extraq_add_sort_update(d, EXTRA_UTIL_Q, 0); - #endif - } - + + extraq_check_add_unblocked(d, 1); } } PRINT(3,"woke up domain %i.%i (deadl= %llu period= %llu "\ "now= %llu)\n", d->domain->id, d->eid, inf->deadl_abs, inf->period, now); - __add_to_waitqueue_sort(d); - PRINT(3,"added to waitq\n"); + if (PERIOD_BEGIN(inf) > now) { + __add_to_waitqueue_sort(d); + PRINT(3,"added to waitq\n"); + } + else { + __add_to_runqueue_sort(d); + PRINT(3,"added to runq\n"); + } #ifdef SEDF_STATS /*do some statistics here...*/ @@ -1250,12 +1241,8 @@ void sedf_wake(struct exec_domain *d) { } #endif /*sanity check: make sure each extra-aware domain IS on the util-q!*/ - /*if (inf->extra & EXTRA_AWARE) { - if (!extraq_on(d, EXTRA_UTIL_Q)) - printf("sedf_wake: domain %i.%i is extra-aware, "\ - "but NOT on L1 extraq!\n",d->domain->id, d->eid); - }*/ - + ASSERT(IMPLY(inf->status & EXTRA_AWARE, extraq_on(d, EXTRA_UTIL_Q))); + ASSERT(__task_on_queue(d)); /*check whether the awakened task needs to invoke the do_schedule routine. Try to avoid unnecessary runs but: Save approximation: Always switch to scheduler!*/ @@ -1271,11 +1258,11 @@ void sedf_wake(struct exec_domain *d) { static void sedf_dump_domain(struct exec_domain *d) { printk("%i.%i has=%c ", d->domain->id, d->eid, test_bit(EDF_RUNNING, &d->ed_flags) ? 'T':'F'); - printk("p=%llu sl=%llu ddl=%llu w=%hu c=%llu sc=%i xtr(%s)=%llu", + printk("p=%llu sl=%llu ddl=%llu w=%hu c=%llu sc=%i xtr(%s)=%llu ew=%hu", EDOM_INFO(d)->period, EDOM_INFO(d)->slice, EDOM_INFO(d)->deadl_abs, EDOM_INFO(d)->weight, d->cpu_time, EDOM_INFO(d)->score[EXTRA_UTIL_Q], - (EDOM_INFO(d)->extra & EXTRA_AWARE) ? "yes" : "no", - EDOM_INFO(d)->extra_time_tot); + (EDOM_INFO(d)->status & EXTRA_AWARE) ? "yes" : "no", + EDOM_INFO(d)->extra_time_tot, EDOM_INFO(d)->extraweight); if (d->cpu_time !=0) printf(" (%lu%)", (EDOM_INFO(d)->extra_time_tot * 100) / d->cpu_time); @@ -1408,7 +1395,7 @@ static inline int sedf_adjust_weights(struct sched_adjdom_cmd *cmd) { /* set or fetch domain scheduling parameters */ static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { struct exec_domain *ed; - + PRINT(2,"sedf_adjdom was called, domain-id %i new period %llu "\ "new slice %llu\nlatency %llu extra:%s\n", p->id, cmd->u.sedf.period, cmd->u.sedf.slice, @@ -1418,10 +1405,21 @@ static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { /*check for sane parameters*/ if (!cmd->u.sedf.period && !cmd->u.sedf.weight) return -EINVAL; - /*weight driven domains*/ if (cmd->u.sedf.weight) { - for_each_exec_domain(p, ed) - EDOM_INFO(ed)->weight = cmd->u.sedf.weight; + if ((cmd->u.sedf.extratime & EXTRA_AWARE) && + (! cmd->u.sedf.period)) { + /*weight driven domains with xtime ONLY!*/ + for_each_exec_domain(p, ed) { + EDOM_INFO(ed)->extraweight = cmd->u.sedf.weight; + EDOM_INFO(ed)->weight = 0; + EDOM_INFO(ed)->slice = 0; + EDOM_INFO(ed)->period = WEIGHT_PERIOD; + } + } else { + /*weight driven domains with real-time execution*/ + for_each_exec_domain(p, ed) + EDOM_INFO(ed)->weight = cmd->u.sedf.weight; + } } else { /*time driven domains*/ @@ -1430,6 +1428,7 @@ static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { if(cmd->u.sedf.slice > cmd->u.sedf.period ) return -EINVAL; EDOM_INFO(ed)->weight = 0; + EDOM_INFO(ed)->extraweight = 0; EDOM_INFO(ed)->period_orig = EDOM_INFO(ed)->period = cmd->u.sedf.period; EDOM_INFO(ed)->slice_orig = @@ -1440,7 +1439,7 @@ static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { return -EINVAL; for_each_exec_domain(p, ed) { - EDOM_INFO(ed)->extra = (EDOM_INFO(ed)->extra & + EDOM_INFO(ed)->status = (EDOM_INFO(ed)->status & ~EXTRA_AWARE) | (cmd->u.sedf.extratime & EXTRA_AWARE); EDOM_INFO(ed)->latency = cmd->u.sedf.latency; extraq_check(ed); @@ -1450,7 +1449,7 @@ static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { { cmd->u.sedf.period = EDOM_INFO(p->exec_domain[0])->period; cmd->u.sedf.slice = EDOM_INFO(p->exec_domain[0])->slice; - cmd->u.sedf.extratime = EDOM_INFO(p->exec_domain[0])->extra + cmd->u.sedf.extratime = EDOM_INFO(p->exec_domain[0])->status & EXTRA_AWARE; cmd->u.sedf.latency = EDOM_INFO(p->exec_domain[0])->latency; cmd->u.sedf.weight = EDOM_INFO(p->exec_domain[0])->weight; diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 697d8a3757..5a38a07507 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -338,7 +338,19 @@ long sched_ctl(struct sched_ctl_cmd *cmd) long sched_adjdom(struct sched_adjdom_cmd *cmd) { struct domain *d; + struct exec_domain *ed; + int cpu; +#if NR_CPUS <=32 + unsigned long have_lock; + #else + unsigned long long have_lock; +#endif + int succ; + #define __set_cpu_bit(cpu, data) data |= ((typeof(data))1)<sched_id != ops.sched_id ) return -EINVAL; @@ -349,9 +361,38 @@ long sched_adjdom(struct sched_adjdom_cmd *cmd) if ( d == NULL ) return -ESRCH; - spin_lock_irq(&schedule_data[d->exec_domain[0]->processor].schedule_lock); + /* acquire locks on all CPUs on which exec_domains of this domain run */ + do { + succ = 0; + __clear_cpu_bits(have_lock); + for_each_exec_domain(d, ed) { + cpu = ed->processor; + if (!__get_cpu_bit(cpu, have_lock)) { + /* if we don't have a lock on this CPU: acquire it*/ + if (!spin_trylock(&schedule_data[cpu].schedule_lock)) { + /*we have this lock!*/ + __set_cpu_bit(cpu, have_lock); + succ = 1; + } else { + /*we didn,t get this lock -> free all other locks too!*/ + for (cpu = 0; cpu < NR_CPUS; cpu++) + if (__get_cpu_bit(cpu, have_lock)) + spin_unlock(&schedule_data[cpu].schedule_lock); + /* and start from the beginning! */ + succ = 0; + /* leave the "for_each_domain_loop" */ + break; + } + } + } + } while (!succ); + //spin_lock_irq(&schedule_data[d->exec_domain[0]->processor].schedule_lock); SCHED_OP(adjdom, d, cmd); - spin_unlock_irq(&schedule_data[d->exec_domain[0]->processor].schedule_lock); + //spin_unlock_irq(&schedule_data[d->exec_domain[0]->processor].schedule_lock); + for (cpu = 0; cpu < NR_CPUS; cpu++) + if (__get_cpu_bit(cpu, have_lock)) + spin_unlock(&schedule_data[cpu].schedule_lock); + __clear_cpu_bits(have_lock); TRACE_1D(TRC_SCHED_ADJDOM, d->id); put_domain(d); From 7570401dfac55eb779e4482a7fe8f4e9e17b23d7 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Tue, 3 May 2005 14:41:52 +0000 Subject: [PATCH 12/54] bitkeeper revision 1.1389.4.1 (42778db0fg1Gd_OZr6N8_onX23xy3g) Patch to allow vcpu hotplugging in domU Signed-off-by: Ryan Harper Signed-off-by: Christian Limpach From: Ryan Harper Two config changes are required to use this change: 1) CONFIG_SMP=y 2) CONFIG_HOTPLUG_CPU=y I've tested unplugging/plugging cpus in domU via the sysfs interface that the patch provides. hungerforce:~# grep processor /proc/cpuinfo processor : 0 processor : 1 processor : 2 processor : 3 hungerforce:~# cd /sys/devices/system/cpu/ hungerforce:/sys/devices/system/cpu# echo 0 > cpu3/online hungerforce:/sys/devices/system/cpu# grep processor /proc/cpuinfo processor : 0 processor : 1 processor : 2 hungerforce:/sys/devices/system/cpu# echo 1 > cpu3/online hungerforce:/sys/devices/system/cpu# grep processor /proc/cpuinfo processor : 0 processor : 1 processor : 2 processor : 3 It seems that all processors besides cpu0 can be removed. I've not done any investigation nor optimization of the hotplug patch. I attempted to unplug cpus in dom0, but this resulted in Xen rebooting. Makefile, Kconfig, smpboot.c, smp.c, process.c, irq.c: Fix hotplug cpu support. Makefile: Setup reach-over build of topology.o. i386-cpu-hotplug-updated-for-mm.patch: Add i386 hotplug patch from: ftp://ftp.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/2.6.11-rc5/2.6.11-rc5-mm1/broken-out/i386-cpu-hotplug-updated-for-mm.patch i386-cpu-hotplug-updated-for-mm.patch, Makefile: new file traps.c, smpboot.c, smp.c, process.c, irq.c, Kconfig: Merge changes from hotplug patch. --- .rootkeys | 2 + linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig | 10 + .../arch/xen/i386/Makefile | 1 + .../arch/xen/i386/kernel/irq.c | 65 +- .../arch/xen/i386/kernel/process.c | 34 + .../arch/xen/i386/kernel/smp.c | 24 +- .../arch/xen/i386/kernel/smpboot.c | 103 ++- .../arch/xen/i386/kernel/traps.c | 8 + .../arch/xen/i386/mach-default/Makefile | 12 + .../i386-cpu-hotplug-updated-for-mm.patch | 656 ++++++++++++++++++ 10 files changed, 888 insertions(+), 27 deletions(-) create mode 100644 linux-2.6.11-xen-sparse/arch/xen/i386/mach-default/Makefile create mode 100644 patches/linux-2.6.11/i386-cpu-hotplug-updated-for-mm.patch diff --git a/.rootkeys b/.rootkeys index cd12228470..ca9b9fa559 100644 --- a/.rootkeys +++ b/.rootkeys @@ -244,6 +244,7 @@ 40f562389xNa78YBZciUibQjyRU_Lg linux-2.6.11-xen-sparse/arch/xen/i386/kernel/traps.c 40f56238JypKAUG01ZojFwH7qnZ5uA linux-2.6.11-xen-sparse/arch/xen/i386/kernel/vsyscall.S 40f56238wi6AdNQjm0RT57bSkwb6hg linux-2.6.11-xen-sparse/arch/xen/i386/kernel/vsyscall.lds +427245dboQBkhq841wIPqlRD-AG9Jw linux-2.6.11-xen-sparse/arch/xen/i386/mach-default/Makefile 40f56238a3w6-byOzexIlMgni76Lcg linux-2.6.11-xen-sparse/arch/xen/i386/mm/Makefile 40f56238ILx8xlbywNbzTdv5Zr4xXQ linux-2.6.11-xen-sparse/arch/xen/i386/mm/fault.c 4118cc35CbY8rfGVspF5O-7EkXBEAA linux-2.6.11-xen-sparse/arch/xen/i386/mm/highmem.c @@ -461,6 +462,7 @@ 422e4430-gOD358H8nGGnNWes08Nng netbsd-2.0-xen-sparse/sys/miscfs/kernfs/kernfs_vnops.c 413cb3b53nyOv1OIeDSsCXhBFDXvJA netbsd-2.0-xen-sparse/sys/nfs/files.nfs 413aa1d0oNP8HXLvfPuMe6cSroUfSA patches/linux-2.6.11/agpgart.patch +427261074Iy1MkbbqIV6zdZDWWx_Jg patches/linux-2.6.11/i386-cpu-hotplug-updated-for-mm.patch 42372652KCUP-IOH9RN19YQmGhs4aA patches/linux-2.6.11/iomap.patch 424f001e_M1Tnxc52rDrmCLelnDWMQ patches/linux-2.6.11/x86_64-linux.patch 3f776bd1Hy9rn69ntXBhPReUFw9IEA tools/Makefile diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig b/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig index a6416ed5ed..0fad9a4f33 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig @@ -668,6 +668,16 @@ config X86_LOCAL_APIC depends on (X86_VISWS || SMP) && !X86_VOYAGER default n +config HOTPLUG_CPU + bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" + depends on SMP && HOTPLUG && EXPERIMENTAL + ---help--- + Say Y here to experiment with turning CPUs off and on. CPUs + can be controlled through /sys/devices/system/cpu. + + Say N. + + if XEN_PHYSDEV_ACCESS menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)" diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/Makefile b/linux-2.6.11-xen-sparse/arch/xen/i386/Makefile index 8af1059853..053c0984ac 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/Makefile +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/Makefile @@ -72,6 +72,7 @@ head-y := arch/xen/i386/kernel/head.o arch/xen/i386/kernel/init_task.o libs-y += arch/i386/lib/ core-y += arch/xen/i386/kernel/ \ arch/xen/i386/mm/ \ + arch/xen/i386/mach-default/ \ arch/i386/crypto/ # \ # arch/xen/$(mcore-y)/ diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/irq.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/irq.c index 6cd16ccfdc..f31697ecb1 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/irq.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/irq.c @@ -15,6 +15,9 @@ #include #include #include +#include +#include +#include #ifndef CONFIG_X86_LOCAL_APIC /* @@ -207,9 +210,8 @@ int show_interrupts(struct seq_file *p, void *v) if (i == 0) { seq_printf(p, " "); - for (j=0; jtypename); seq_printf(p, " %s", action->name); @@ -237,16 +238,13 @@ skip: spin_unlock_irqrestore(&irq_desc[i].lock, flags); } else if (i == NR_IRQS) { seq_printf(p, "NMI: "); - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", nmi_count(j)); + for_each_cpu(j) + seq_printf(p, "%10u ", nmi_count(j)); seq_putc(p, '\n'); #ifdef CONFIG_X86_LOCAL_APIC seq_printf(p, "LOC: "); - for (j = 0; j < NR_CPUS; j++) - if (cpu_online(j)) - seq_printf(p, "%10u ", - irq_stat[j].apic_timer_irqs); + for_each_cpu(j) + seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs); seq_putc(p, '\n'); #endif seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); @@ -256,3 +254,44 @@ skip: } return 0; } + +#ifdef CONFIG_HOTPLUG_CPU + +void fixup_irqs(cpumask_t map) +{ + unsigned int irq; + static int warned; + + for (irq = 0; irq < NR_IRQS; irq++) { + cpumask_t mask; + if (irq == 2) + continue; + + cpus_and(mask, irq_affinity[irq], map); + if (any_online_cpu(mask) == NR_CPUS) { + printk("Breaking affinity for irq %i\n", irq); + mask = map; + } + if (irq_desc[irq].handler->set_affinity) + irq_desc[irq].handler->set_affinity(irq, mask); + else if (irq_desc[irq].action && !(warned++)) + printk("Cannot set affinity for irq %i\n", irq); + } + +#if 0 + barrier(); + /* Ingo Molnar says: "after the IO-APIC masks have been redirected + [note the nop - the interrupt-enable boundary on x86 is two + instructions from sti] - to flush out pending hardirqs and + IPIs. After this point nothing is supposed to reach this CPU." */ + __asm__ __volatile__("sti; nop; cli"); + barrier(); +#else + /* That doesn't seem sufficient. Give it 1ms. */ + local_irq_enable(); + mdelay(1); + local_irq_disable(); +#endif +} +#endif + diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c index 0f9a2eed70..9061053081 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/process.c @@ -13,6 +13,7 @@ #include +#include #include #include #include @@ -54,6 +55,9 @@ #include #include +#include +#include + asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); int hlt_counter; @@ -112,6 +116,33 @@ void xen_idle(void) } } +#ifdef CONFIG_HOTPLUG_CPU +#include +/* We don't actually take CPU down, just spin without interrupts. */ +static inline void play_dead(void) +{ + /* Ack it */ + __get_cpu_var(cpu_state) = CPU_DEAD; + + /* We shouldn't have to disable interrupts while dead, but + * some interrupts just don't seem to go away, and this makes + * it "work" for testing purposes. */ + /* Death loop */ + while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) + HYPERVISOR_yield(); + + local_irq_disable(); + __flush_tlb_all(); + cpu_set(smp_processor_id(), cpu_online_map); + local_irq_enable(); +} +#else +static inline void play_dead(void) +{ + BUG(); +} +#endif /* CONFIG_HOTPLUG_CPU */ + /* * The idle thread. There's no useful work to be * done, so just try to conserve power and have a @@ -130,6 +161,9 @@ void cpu_idle (void) cpu_clear(cpu, cpu_idle_map); rmb(); + if (cpu_is_offline(cpu)) + play_dead(); + irq_stat[cpu].idle_timestamp = jiffies; xen_idle(); } diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smp.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smp.c index 915034b36d..fddadbba25 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smp.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smp.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -185,6 +186,7 @@ void send_IPI_mask_bitmask(cpumask_t mask, int vector) unsigned int cpu; local_irq_save(flags); + WARN_ON(cpus_addr(mask)[0] & ~cpus_addr(cpu_online_map)[0]); for (cpu = 0; cpu < NR_CPUS; ++cpu) { if (cpu_isset(cpu, mask)) { @@ -320,21 +322,21 @@ out: static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, unsigned long va) { - cpumask_t tmp; /* * A couple of (to be removed) sanity checks: * - * - we do not send IPIs to not-yet booted CPUs. * - current CPU must not be in mask * - mask must exist :) */ BUG_ON(cpus_empty(cpumask)); - - cpus_and(tmp, cpumask, cpu_online_map); - BUG_ON(!cpus_equal(cpumask, tmp)); BUG_ON(cpu_isset(smp_processor_id(), cpumask)); BUG_ON(!mm); + /* If a CPU which we ran on has gone down, OK. */ + cpus_and(cpumask, cpumask, cpu_online_map); + if (cpus_empty(cpumask)) + return; + /* * i'm not happy about this global shared spinlock in the * MM hot path, but we'll see how contended it is. @@ -465,6 +467,7 @@ void flush_tlb_all(void) */ void smp_send_reschedule(int cpu) { + WARN_ON(cpu_is_offline(cpu)); send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR); } @@ -505,10 +508,16 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, */ { struct call_data_struct data; - int cpus = num_online_cpus()-1; + int cpus; - if (!cpus) + /* Holding any lock stops cpus from going down. */ + spin_lock(&call_lock); + cpus = num_online_cpus()-1; + + if (!cpus) { + spin_unlock(&call_lock); return 0; + } /* Can deadlock when called with interrupts disabled */ WARN_ON(irqs_disabled()); @@ -520,7 +529,6 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic, if (wait) atomic_set(&data.finished, 0); - spin_lock(&call_lock); call_data = &data; mb(); diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c index ec1b3b9dea..34570a9398 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c @@ -44,6 +44,9 @@ #include #include #include +#include +#include +#include #include #include @@ -93,7 +96,14 @@ extern unsigned char trampoline_data []; extern unsigned char trampoline_end []; static unsigned char *trampoline_base; static int trampoline_exec; +#endif +#ifdef CONFIG_HOTPLUG_CPU +/* State of each CPU. */ +DEFINE_PER_CPU(int, cpu_state) = { 0 }; +#endif + +#if 0 /* * Currently trivial. Write the real->protected mode * bootstrap into the page concerned. The caller @@ -500,6 +510,7 @@ static int __init start_secondary(void *unused) } } cpu_idle(); + return 0; } /* @@ -1284,6 +1295,9 @@ static void __init smp_boot_cpus(unsigned int max_cpus) who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */ void __init smp_prepare_cpus(unsigned int max_cpus) { + smp_commenced_mask = cpumask_of_cpu(0); + cpu_callin_map = cpumask_of_cpu(0); + mb(); smp_boot_cpus(max_cpus); } @@ -1293,20 +1307,97 @@ void __devinit smp_prepare_boot_cpu(void) cpu_set(smp_processor_id(), cpu_callout_map); } +#ifdef CONFIG_HOTPLUG_CPU + +/* must be called with the cpucontrol mutex held */ +static int __devinit cpu_enable(unsigned int cpu) +{ + /* get the target out of its holding state */ + per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; + wmb(); + + /* wait for the processor to ack it. timeout? */ + while (!cpu_online(cpu)) + cpu_relax(); + + fixup_irqs(cpu_online_map); + /* counter the disable in fixup_irqs() */ + local_irq_enable(); + return 0; +} + +int __cpu_disable(void) +{ + cpumask_t map = cpu_online_map; + int cpu = smp_processor_id(); + + /* + * Perhaps use cpufreq to drop frequency, but that could go + * into generic code. + * + * We won't take down the boot processor on i386 due to some + * interrupts only being able to be serviced by the BSP. + * Especially so if we're not using an IOAPIC -zwane + */ + if (cpu == 0) + return -EBUSY; + + /* Allow any queued timer interrupts to get serviced */ + local_irq_enable(); + mdelay(1); + local_irq_disable(); + + cpu_clear(cpu, map); + fixup_irqs(map); + /* It's now safe to remove this processor from the online map */ + cpu_clear(cpu, cpu_online_map); + return 0; +} + +void __cpu_die(unsigned int cpu) +{ + /* We don't do anything here: idle task is faking death itself. */ + unsigned int i; + + for (i = 0; i < 10; i++) { + /* They ack this in play_dead by setting CPU_DEAD */ + if (per_cpu(cpu_state, cpu) == CPU_DEAD) + return; + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ/10); + } + printk(KERN_ERR "CPU %u didn't die...\n", cpu); +} +#else /* ... !CONFIG_HOTPLUG_CPU */ +int __cpu_disable(void) +{ + return -ENOSYS; +} + +void __cpu_die(unsigned int cpu) +{ + /* We said "no" in __cpu_disable */ + BUG(); +} +#endif /* CONFIG_HOTPLUG_CPU */ + int __devinit __cpu_up(unsigned int cpu) { - /* This only works at boot for x86. See "rewrite" above. */ - if (cpu_isset(cpu, smp_commenced_mask)) { - local_irq_enable(); - return -ENOSYS; - } - /* In case one didn't come up */ if (!cpu_isset(cpu, cpu_callin_map)) { + printk(KERN_DEBUG "skipping cpu%d, didn't come online\n", cpu); local_irq_enable(); return -EIO; } +#ifdef CONFIG_HOTPLUG_CPU + /* Already up, and in cpu_quiescent now? */ + if (cpu_isset(cpu, smp_commenced_mask)) { + cpu_enable(cpu); + return 0; + } +#endif + local_irq_enable(); /* Unleash the CPU! */ cpu_set(cpu, smp_commenced_mask); diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/traps.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/traps.c index a6615b7e18..d0718b5299 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/traps.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/traps.c @@ -609,6 +609,14 @@ fastcall void do_nmi(struct pt_regs * regs, long error_code) nmi_enter(); cpu = smp_processor_id(); + +#ifdef CONFIG_HOTPLUG_CPU + if (!cpu_online(cpu)) { + nmi_exit(); + return; + } +#endif + ++nmi_count(cpu); if (!nmi_callback(regs, cpu)) diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/mach-default/Makefile b/linux-2.6.11-xen-sparse/arch/xen/i386/mach-default/Makefile new file mode 100644 index 0000000000..7d50b2926e --- /dev/null +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/mach-default/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for the linux kernel. +# + +c-obj-y := topology.o + +$(patsubst %.o,$(obj)/%.c,$(c-obj-y)): + @ln -fsn $(srctree)/arch/i386/mach-default/$(notdir $@) $@ + +obj-y += $(c-obj-y) + +clean-files += $(patsubst %.o,%.c,$(c-obj-y) $(c-obj-)) diff --git a/patches/linux-2.6.11/i386-cpu-hotplug-updated-for-mm.patch b/patches/linux-2.6.11/i386-cpu-hotplug-updated-for-mm.patch new file mode 100644 index 0000000000..ec39143743 --- /dev/null +++ b/patches/linux-2.6.11/i386-cpu-hotplug-updated-for-mm.patch @@ -0,0 +1,656 @@ + +From: Zwane Mwaikambo + +Find attached the i386 cpu hotplug patch updated for Ingo's latest round of +goodies. In order to avoid dumping cpu hotplug code into kernel/irq/* i +dropped the cpu_online check in do_IRQ() by modifying fixup_irqs(). The +difference being that on cpu offline, fixup_irqs() is called before we +clear the cpu from cpu_online_map and a long delay in order to ensure that +we never have any queued external interrupts on the APICs. Due to my usual +test victims being in boxes a continent away this hasn't been tested, but +i'll cover bug reports (nudge, Nathan! ;) + +1) Add CONFIG_HOTPLUG_CPU +2) disable local APIC timer on dead cpus. +3) Disable preempt around irq balancing to prevent CPUs going down. +4) Print irq stats for all possible cpus. +5) Debugging check for interrupts on offline cpus. +6) Hacky fixup_irqs() to redirect irqs when cpus go off/online. +7) play_dead() for offline cpus to spin inside. +8) Handle offline cpus set in flush_tlb_others(). +9) Grab lock earlier in smp_call_function() to prevent CPUs going down. +10) Implement __cpu_disable() and __cpu_die(). +11) Enable local interrupts in cpu_enable() after fixup_irqs() +12) Don't fiddle with NMI on dead cpu, but leave intact on other cpus. +13) Program IRQ affinity whilst cpu is still in cpu_online_map on offline. + +Signed-off-by: Zwane Mwaikambo +DESC +ppc64: fix hotplug cpu +EDESC +From: Zwane Mwaikambo + +I seem to have broken this when I moved the clearing of the dying cpu to +arch specific code. + +Signed-off-by: Zwane Mwaikambo +Signed-off-by: Andrew Morton +--- + + 25-akpm/arch/i386/Kconfig | 9 ++ + 25-akpm/arch/i386/kernel/apic.c | 3 + 25-akpm/arch/i386/kernel/io_apic.c | 2 + 25-akpm/arch/i386/kernel/irq.c | 66 +++++++++++++++++---- + 25-akpm/arch/i386/kernel/msr.c | 2 + 25-akpm/arch/i386/kernel/process.c | 35 +++++++++++ + 25-akpm/arch/i386/kernel/smp.c | 25 +++++--- + 25-akpm/arch/i386/kernel/smpboot.c | 98 ++++++++++++++++++++++++++++++-- + 25-akpm/arch/i386/kernel/traps.c | 8 ++ + 25-akpm/arch/ia64/kernel/smpboot.c | 3 + 25-akpm/arch/ppc64/kernel/pSeries_smp.c | 5 + + 25-akpm/arch/s390/kernel/smp.c | 4 - + 25-akpm/include/asm-i386/cpu.h | 2 + 25-akpm/include/asm-i386/irq.h | 4 + + 25-akpm/include/asm-i386/smp.h | 3 + 25-akpm/kernel/cpu.c | 14 +--- + arch/ppc64/kernel/smp.c | 0 + 17 files changed, 242 insertions(+), 41 deletions(-) + +diff -puN arch/i386/Kconfig~i386-cpu-hotplug-updated-for-mm arch/i386/Kconfig +--- 25/arch/i386/Kconfig~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/Kconfig 2005-02-23 02:20:06.000000000 -0800 +@@ -1205,6 +1205,15 @@ config SCx200 + This support is also available as a module. If compiled as a + module, it will be called scx200. + ++config HOTPLUG_CPU ++ bool "Support for hot-pluggable CPUs (EXPERIMENTAL)" ++ depends on SMP && HOTPLUG && EXPERIMENTAL ++ ---help--- ++ Say Y here to experiment with turning CPUs off and on. CPUs ++ can be controlled through /sys/devices/system/cpu. ++ ++ Say N. ++ + source "drivers/pcmcia/Kconfig" + + source "drivers/pci/hotplug/Kconfig" +diff -puN arch/i386/kernel/apic.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/apic.c +--- 25/arch/i386/kernel/apic.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/kernel/apic.c 2005-02-23 02:20:06.000000000 -0800 +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1048,7 +1049,7 @@ void __init setup_secondary_APIC_clock(v + setup_APIC_timer(calibration_result); + } + +-void __init disable_APIC_timer(void) ++void __devinit disable_APIC_timer(void) + { + if (using_apic_timer) { + unsigned long v; +diff -puN arch/i386/kernel/io_apic.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/io_apic.c +--- 25/arch/i386/kernel/io_apic.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/kernel/io_apic.c 2005-02-23 02:20:06.000000000 -0800 +@@ -576,9 +576,11 @@ static int balanced_irq(void *unused) + try_to_freeze(PF_FREEZE); + if (time_after(jiffies, + prev_balance_time+balanced_irq_interval)) { ++ preempt_disable(); + do_irq_balance(); + prev_balance_time = jiffies; + time_remaining = balanced_irq_interval; ++ preempt_enable(); + } + } + return 0; +diff -puN arch/i386/kernel/irq.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/irq.c +--- 25/arch/i386/kernel/irq.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/kernel/irq.c 2005-02-23 02:20:06.000000000 -0800 +@@ -15,6 +15,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #ifndef CONFIG_X86_LOCAL_APIC + /* +@@ -209,9 +212,8 @@ int show_interrupts(struct seq_file *p, + + if (i == 0) { + seq_printf(p, " "); +- for (j=0; jtypename); + seq_printf(p, " %s", action->name); +@@ -239,16 +240,13 @@ skip: + spin_unlock_irqrestore(&irq_desc[i].lock, flags); + } else if (i == NR_IRQS) { + seq_printf(p, "NMI: "); +- for (j = 0; j < NR_CPUS; j++) +- if (cpu_online(j)) +- seq_printf(p, "%10u ", nmi_count(j)); ++ for_each_cpu(j) ++ seq_printf(p, "%10u ", nmi_count(j)); + seq_putc(p, '\n'); + #ifdef CONFIG_X86_LOCAL_APIC + seq_printf(p, "LOC: "); +- for (j = 0; j < NR_CPUS; j++) +- if (cpu_online(j)) +- seq_printf(p, "%10u ", +- irq_stat[j].apic_timer_irqs); ++ for_each_cpu(j) ++ seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs); + seq_putc(p, '\n'); + #endif + seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); +@@ -258,3 +256,45 @@ skip: + } + return 0; + } ++ ++#ifdef CONFIG_HOTPLUG_CPU ++#include ++ ++void fixup_irqs(cpumask_t map) ++{ ++ unsigned int irq; ++ static int warned; ++ ++ for (irq = 0; irq < NR_IRQS; irq++) { ++ cpumask_t mask; ++ if (irq == 2) ++ continue; ++ ++ cpus_and(mask, irq_affinity[irq], map); ++ if (any_online_cpu(mask) == NR_CPUS) { ++ printk("Breaking affinity for irq %i\n", irq); ++ mask = map; ++ } ++ if (irq_desc[irq].handler->set_affinity) ++ irq_desc[irq].handler->set_affinity(irq, mask); ++ else if (irq_desc[irq].action && !(warned++)) ++ printk("Cannot set affinity for irq %i\n", irq); ++ } ++ ++#if 0 ++ barrier(); ++ /* Ingo Molnar says: "after the IO-APIC masks have been redirected ++ [note the nop - the interrupt-enable boundary on x86 is two ++ instructions from sti] - to flush out pending hardirqs and ++ IPIs. After this point nothing is supposed to reach this CPU." */ ++ __asm__ __volatile__("sti; nop; cli"); ++ barrier(); ++#else ++ /* That doesn't seem sufficient. Give it 1ms. */ ++ local_irq_enable(); ++ mdelay(1); ++ local_irq_disable(); ++#endif ++} ++#endif ++ +diff -puN arch/i386/kernel/msr.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/msr.c +--- 25/arch/i386/kernel/msr.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/kernel/msr.c 2005-02-23 02:20:06.000000000 -0800 +@@ -260,7 +260,7 @@ static struct file_operations msr_fops = + .open = msr_open, + }; + +-static int msr_class_simple_device_add(int i) ++static int __devinit msr_class_simple_device_add(int i) + { + int err = 0; + struct class_device *class_err; +diff -puN arch/i386/kernel/process.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/process.c +--- 25/arch/i386/kernel/process.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/kernel/process.c 2005-02-23 02:20:06.000000000 -0800 +@@ -13,6 +13,7 @@ + + #include + ++#include + #include + #include + #include +@@ -55,6 +56,9 @@ + #include + #include + ++#include ++#include ++ + asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); + + int hlt_counter; +@@ -139,6 +143,34 @@ static void poll_idle (void) + } + } + ++#ifdef CONFIG_HOTPLUG_CPU ++#include ++/* We don't actually take CPU down, just spin without interrupts. */ ++static inline void play_dead(void) ++{ ++ /* Ack it */ ++ __get_cpu_var(cpu_state) = CPU_DEAD; ++ ++ /* We shouldn't have to disable interrupts while dead, but ++ * some interrupts just don't seem to go away, and this makes ++ * it "work" for testing purposes. */ ++ /* Death loop */ ++ while (__get_cpu_var(cpu_state) != CPU_UP_PREPARE) ++ cpu_relax(); ++ ++ local_irq_disable(); ++ __flush_tlb_all(); ++ cpu_set(smp_processor_id(), cpu_online_map); ++ enable_APIC_timer(); ++ local_irq_enable(); ++} ++#else ++static inline void play_dead(void) ++{ ++ BUG(); ++} ++#endif /* CONFIG_HOTPLUG_CPU */ ++ + /* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a +@@ -162,6 +194,9 @@ void cpu_idle (void) + if (!idle) + idle = default_idle; + ++ if (cpu_is_offline(cpu)) ++ play_dead(); ++ + irq_stat[cpu].idle_timestamp = jiffies; + idle(); + } +diff -puN arch/i386/kernel/smpboot.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/smpboot.c +--- 25/arch/i386/kernel/smpboot.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/kernel/smpboot.c 2005-02-23 02:20:06.000000000 -0800 +@@ -44,6 +44,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #include + #include +@@ -89,6 +92,9 @@ extern unsigned char trampoline_end []; + static unsigned char *trampoline_base; + static int trampoline_exec; + ++/* State of each CPU. */ ++DEFINE_PER_CPU(int, cpu_state) = { 0 }; ++ + /* + * Currently trivial. Write the real->protected mode + * bootstrap into the page concerned. The caller +@@ -1095,6 +1101,9 @@ static void __init smp_boot_cpus(unsigne + who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */ + void __init smp_prepare_cpus(unsigned int max_cpus) + { ++ smp_commenced_mask = cpumask_of_cpu(0); ++ cpu_callin_map = cpumask_of_cpu(0); ++ mb(); + smp_boot_cpus(max_cpus); + } + +@@ -1104,20 +1113,99 @@ void __devinit smp_prepare_boot_cpu(void + cpu_set(smp_processor_id(), cpu_callout_map); + } + +-int __devinit __cpu_up(unsigned int cpu) ++#ifdef CONFIG_HOTPLUG_CPU ++ ++/* must be called with the cpucontrol mutex held */ ++static int __devinit cpu_enable(unsigned int cpu) + { +- /* This only works at boot for x86. See "rewrite" above. */ +- if (cpu_isset(cpu, smp_commenced_mask)) { +- local_irq_enable(); +- return -ENOSYS; ++ /* get the target out of its holding state */ ++ per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; ++ wmb(); ++ ++ /* wait for the processor to ack it. timeout? */ ++ while (!cpu_online(cpu)) ++ cpu_relax(); ++ ++ fixup_irqs(cpu_online_map); ++ /* counter the disable in fixup_irqs() */ ++ local_irq_enable(); ++ return 0; ++} ++ ++int __cpu_disable(void) ++{ ++ cpumask_t map = cpu_online_map; ++ int cpu = smp_processor_id(); ++ ++ /* ++ * Perhaps use cpufreq to drop frequency, but that could go ++ * into generic code. ++ * ++ * We won't take down the boot processor on i386 due to some ++ * interrupts only being able to be serviced by the BSP. ++ * Especially so if we're not using an IOAPIC -zwane ++ */ ++ if (cpu == 0) ++ return -EBUSY; ++ ++ /* We enable the timer again on the exit path of the death loop */ ++ disable_APIC_timer(); ++ /* Allow any queued timer interrupts to get serviced */ ++ local_irq_enable(); ++ mdelay(1); ++ local_irq_disable(); ++ ++ cpu_clear(cpu, map); ++ fixup_irqs(map); ++ /* It's now safe to remove this processor from the online map */ ++ cpu_clear(cpu, cpu_online_map); ++ return 0; ++} ++ ++void __cpu_die(unsigned int cpu) ++{ ++ /* We don't do anything here: idle task is faking death itself. */ ++ unsigned int i; ++ ++ for (i = 0; i < 10; i++) { ++ /* They ack this in play_dead by setting CPU_DEAD */ ++ if (per_cpu(cpu_state, cpu) == CPU_DEAD) ++ return; ++ current->state = TASK_UNINTERRUPTIBLE; ++ schedule_timeout(HZ/10); + } ++ printk(KERN_ERR "CPU %u didn't die...\n", cpu); ++} ++#else /* ... !CONFIG_HOTPLUG_CPU */ ++int __cpu_disable(void) ++{ ++ return -ENOSYS; ++} + ++void __cpu_die(unsigned int cpu) ++{ ++ /* We said "no" in __cpu_disable */ ++ BUG(); ++} ++#endif /* CONFIG_HOTPLUG_CPU */ ++ ++int __devinit __cpu_up(unsigned int cpu) ++{ + /* In case one didn't come up */ + if (!cpu_isset(cpu, cpu_callin_map)) { ++ printk(KERN_DEBUG "skipping cpu%d, didn't come online\n", cpu); + local_irq_enable(); + return -EIO; + } + ++#ifdef CONFIG_HOTPLUG_CPU ++ /* Already up, and in cpu_quiescent now? */ ++ if (cpu_isset(cpu, smp_commenced_mask)) { ++ cpu_enable(cpu); ++ return 0; ++ } ++#endif ++ + local_irq_enable(); + /* Unleash the CPU! */ + cpu_set(cpu, smp_commenced_mask); +diff -puN arch/i386/kernel/smp.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/smp.c +--- 25/arch/i386/kernel/smp.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/kernel/smp.c 2005-02-23 02:20:06.000000000 -0800 +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -163,7 +164,7 @@ void send_IPI_mask_bitmask(cpumask_t cpu + unsigned long flags; + + local_irq_save(flags); +- ++ WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]); + /* + * Wait for idle. + */ +@@ -345,21 +346,21 @@ out: + static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, + unsigned long va) + { +- cpumask_t tmp; + /* + * A couple of (to be removed) sanity checks: + * +- * - we do not send IPIs to not-yet booted CPUs. + * - current CPU must not be in mask + * - mask must exist :) + */ + BUG_ON(cpus_empty(cpumask)); +- +- cpus_and(tmp, cpumask, cpu_online_map); +- BUG_ON(!cpus_equal(cpumask, tmp)); + BUG_ON(cpu_isset(smp_processor_id(), cpumask)); + BUG_ON(!mm); + ++ /* If a CPU which we ran on has gone down, OK. */ ++ cpus_and(cpumask, cpumask, cpu_online_map); ++ if (cpus_empty(cpumask)) ++ return; ++ + /* + * i'm not happy about this global shared spinlock in the + * MM hot path, but we'll see how contended it is. +@@ -484,6 +485,7 @@ void smp_send_nmi_allbutself(void) + */ + void smp_send_reschedule(int cpu) + { ++ WARN_ON(cpu_is_offline(cpu)); + send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR); + } + +@@ -524,10 +526,16 @@ int smp_call_function (void (*func) (voi + */ + { + struct call_data_struct data; +- int cpus = num_online_cpus()-1; ++ int cpus; + +- if (!cpus) ++ /* Holding any lock stops cpus from going down. */ ++ spin_lock(&call_lock); ++ cpus = num_online_cpus()-1; ++ ++ if (!cpus) { ++ spin_unlock(&call_lock); + return 0; ++ } + + /* Can deadlock when called with interrupts disabled */ + WARN_ON(irqs_disabled()); +@@ -539,7 +547,6 @@ int smp_call_function (void (*func) (voi + if (wait) + atomic_set(&data.finished, 0); + +- spin_lock(&call_lock); + call_data = &data; + mb(); + +diff -puN arch/i386/kernel/traps.c~i386-cpu-hotplug-updated-for-mm arch/i386/kernel/traps.c +--- 25/arch/i386/kernel/traps.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/i386/kernel/traps.c 2005-02-23 02:20:06.000000000 -0800 +@@ -669,6 +669,14 @@ fastcall void do_nmi(struct pt_regs * re + nmi_enter(); + + cpu = smp_processor_id(); ++ ++#ifdef CONFIG_HOTPLUG_CPU ++ if (!cpu_online(cpu)) { ++ nmi_exit(); ++ return; ++ } ++#endif ++ + ++nmi_count(cpu); + + if (!nmi_callback(regs, cpu)) +diff -puN arch/ia64/kernel/smpboot.c~i386-cpu-hotplug-updated-for-mm arch/ia64/kernel/smpboot.c +--- 25/arch/ia64/kernel/smpboot.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/ia64/kernel/smpboot.c 2005-02-23 02:20:06.000000000 -0800 +@@ -590,9 +590,10 @@ int __cpu_disable(void) + if (cpu == 0) + return -EBUSY; + ++ cpu_clear(cpu, cpu_online_map); + fixup_irqs(); + local_flush_tlb_all(); +- printk ("Disabled cpu %u\n", smp_processor_id()); ++ printk("Disabled cpu %u\n", cpu); + return 0; + } + +diff -puN arch/ppc64/kernel/smp.c~i386-cpu-hotplug-updated-for-mm arch/ppc64/kernel/smp.c +diff -puN arch/s390/kernel/smp.c~i386-cpu-hotplug-updated-for-mm arch/s390/kernel/smp.c +--- 25/arch/s390/kernel/smp.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/arch/s390/kernel/smp.c 2005-02-23 02:20:06.000000000 -0800 +@@ -679,12 +679,14 @@ __cpu_disable(void) + { + unsigned long flags; + ec_creg_mask_parms cr_parms; ++ int cpu = smp_processor_id(); + + spin_lock_irqsave(&smp_reserve_lock, flags); +- if (smp_cpu_reserved[smp_processor_id()] != 0) { ++ if (smp_cpu_reserved[cpu] != 0) { + spin_unlock_irqrestore(&smp_reserve_lock, flags); + return -EBUSY; + } ++ cpu_clear(cpu, cpu_online_map); + + #ifdef CONFIG_PFAULT + /* Disable pfault pseudo page faults on this cpu. */ +diff -puN include/asm-i386/cpu.h~i386-cpu-hotplug-updated-for-mm include/asm-i386/cpu.h +--- 25/include/asm-i386/cpu.h~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/include/asm-i386/cpu.h 2005-02-23 02:20:06.000000000 -0800 +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + + #include + +@@ -17,4 +18,5 @@ extern int arch_register_cpu(int num); + extern void arch_unregister_cpu(int); + #endif + ++DECLARE_PER_CPU(int, cpu_state); + #endif /* _ASM_I386_CPU_H_ */ +diff -puN include/asm-i386/irq.h~i386-cpu-hotplug-updated-for-mm include/asm-i386/irq.h +--- 25/include/asm-i386/irq.h~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/include/asm-i386/irq.h 2005-02-23 02:20:06.000000000 -0800 +@@ -38,4 +38,8 @@ extern void release_vm86_irqs(struct tas + extern int irqbalance_disable(char *str); + #endif + ++#ifdef CONFIG_HOTPLUG_CPU ++extern void fixup_irqs(cpumask_t map); ++#endif ++ + #endif /* _ASM_IRQ_H */ +diff -puN include/asm-i386/smp.h~i386-cpu-hotplug-updated-for-mm include/asm-i386/smp.h +--- 25/include/asm-i386/smp.h~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/include/asm-i386/smp.h 2005-02-23 02:20:06.000000000 -0800 +@@ -85,6 +85,9 @@ static __inline int logical_smp_processo + } + + #endif ++ ++extern int __cpu_disable(void); ++extern void __cpu_die(unsigned int cpu); + #endif /* !__ASSEMBLY__ */ + + #define NO_PROC_ID 0xFF /* No processor magic marker */ +diff -puN kernel/cpu.c~i386-cpu-hotplug-updated-for-mm kernel/cpu.c +--- 25/kernel/cpu.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:06.000000000 -0800 ++++ 25-akpm/kernel/cpu.c 2005-02-23 02:20:06.000000000 -0800 +@@ -63,19 +63,15 @@ static int take_cpu_down(void *unused) + { + int err; + +- /* Take offline: makes arch_cpu_down somewhat easier. */ +- cpu_clear(smp_processor_id(), cpu_online_map); +- + /* Ensure this CPU doesn't handle any more interrupts. */ + err = __cpu_disable(); + if (err < 0) +- cpu_set(smp_processor_id(), cpu_online_map); +- else +- /* Force idle task to run as soon as we yield: it should +- immediately notice cpu is offline and die quickly. */ +- sched_idle_next(); ++ return err; + +- return err; ++ /* Force idle task to run as soon as we yield: it should ++ immediately notice cpu is offline and die quickly. */ ++ sched_idle_next(); ++ return 0; + } + + int cpu_down(unsigned int cpu) +diff -puN arch/ppc64/kernel/pSeries_smp.c~i386-cpu-hotplug-updated-for-mm arch/ppc64/kernel/pSeries_smp.c +--- 25/arch/ppc64/kernel/pSeries_smp.c~i386-cpu-hotplug-updated-for-mm 2005-02-23 02:20:08.000000000 -0800 ++++ 25-akpm/arch/ppc64/kernel/pSeries_smp.c 2005-02-23 02:20:08.000000000 -0800 +@@ -86,10 +86,13 @@ static int query_cpu_stopped(unsigned in + + int pSeries_cpu_disable(void) + { ++ int cpu = smp_processor_id(); ++ ++ cpu_clear(cpu, cpu_online_map); + systemcfg->processorCount--; + + /*fix boot_cpuid here*/ +- if (smp_processor_id() == boot_cpuid) ++ if (cpu == boot_cpuid) + boot_cpuid = any_online_cpu(cpu_online_map); + + /* FIXME: abstract this to not be platform specific later on */ +_ From 9af364c3c4a0c798f74aba7a1d605d103c1632b9 Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Fri, 6 May 2005 17:02:01 +0000 Subject: [PATCH 13/54] bitkeeper revision 1.1389.9.1 (427ba309i_zOrtoMDOTBwa5_vBiEXQ) Add support for privified mov-from-pmd Add counters for privified-fc and privified-cpuid Add optional support for counting addresses of privops Remove unnecessary PCI stuff Add optional heartbeat console output Signed-off by: Dan Magenheimer --- xen/arch/ia64/privop.c | 82 ++++++++++++++++++++++++++++++++--- xen/arch/ia64/vcpu.c | 41 ++++++++++-------- xen/arch/ia64/xenmisc.c | 69 +---------------------------- xen/arch/ia64/xentime.c | 11 +++++ xen/include/asm-ia64/config.h | 6 --- xen/include/asm-ia64/vcpu.h | 15 +++++++ 6 files changed, 126 insertions(+), 98 deletions(-) diff --git a/xen/arch/ia64/privop.c b/xen/arch/ia64/privop.c index 0b59b60ad8..11ef17310f 100644 --- a/xen/arch/ia64/privop.c +++ b/xen/arch/ia64/privop.c @@ -417,10 +417,17 @@ IA64FAULT priv_mov_from_pmc(VCPU *vcpu, INST64 inst) UINT64 val; IA64FAULT fault; - fault = vcpu_get_pmc(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); - if (fault == IA64_NO_FAULT) - return vcpu_set_gr(vcpu, inst.M43.r1, val); - else return fault; + if (inst.M43.r1 > 63) { // privified mov from pmd + fault = vcpu_get_pmd(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); + if (fault == IA64_NO_FAULT) + return vcpu_set_gr(vcpu, inst.M43.r1-64, val); + } + else { + fault = vcpu_get_pmc(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); + if (fault == IA64_NO_FAULT) + return vcpu_set_gr(vcpu, inst.M43.r1, val); + } + return fault; } unsigned long from_cr_cnt[128] = { 0 }; @@ -531,6 +538,8 @@ struct { unsigned long bsw0; unsigned long bsw1; unsigned long cover; + unsigned long fc; + unsigned long cpuid; unsigned long Mpriv_cnt[64]; } privcnt = { 0 }; @@ -631,7 +640,11 @@ priv_handle_op(VCPU *vcpu, REGS *regs, int privlvl) else x6 = 0x1a; } } - privcnt.Mpriv_cnt[x6]++; + if (x6 == 52 && inst.M28.r3 > 63) + privcnt.fc++; + else if (x6 == 16 && inst.M43.r3 > 63) + privcnt.cpuid++; + else privcnt.Mpriv_cnt[x6]++; return (*pfunc)(vcpu,inst); break; case B: @@ -826,6 +839,12 @@ int dump_privop_counts(char *buf) if (privcnt.cover) s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.cover, "cover", (privcnt.cover*100L)/sum); + if (privcnt.fc) + s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.fc, + "privified-fc", (privcnt.fc*100L)/sum); + if (privcnt.cpuid) + s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.cpuid, + "privified-getcpuid", (privcnt.cpuid*100L)/sum); for (i=0; i < 64; i++) if (privcnt.Mpriv_cnt[i]) { if (!Mpriv_str[i]) s += sprintf(s,"PRIVSTRING NULL!!\r\n"); else s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.Mpriv_cnt[i], @@ -864,6 +883,7 @@ int zero_privop_counts(char *buf) privcnt.ssm = 0; privcnt.rsm = 0; privcnt.rfi = 0; privcnt.bsw0 = 0; privcnt.bsw1 = 0; privcnt.cover = 0; + privcnt.fc = 0; privcnt.cpuid = 0; for (i=0; i < 64; i++) privcnt.Mpriv_cnt[i] = 0; for (j=0; j < 128; j++) from_cr_cnt[j] = 0; for (j=0; j < 128; j++) to_cr_cnt[j] = 0; @@ -871,12 +891,61 @@ int zero_privop_counts(char *buf) return s - buf; } +#ifdef PRIVOP_ADDR_COUNT + +extern struct privop_addr_count privop_addr_counter[]; + +void privop_count_addr(unsigned long iip, int inst) +{ + struct privop_addr_count *v = &privop_addr_counter[inst]; + int i; + + for (i = 0; i < PRIVOP_COUNT_NADDRS; i++) { + if (!v->addr[i]) { v->addr[i] = iip; v->count[i]++; return; } + else if (v->addr[i] == iip) { v->count[i]++; return; } + } + v->overflow++;; +} + +int dump_privop_addrs(char *buf) +{ + int i,j; + char *s = buf; + s += sprintf(s,"Privop addresses:\r\n"); + for (i = 0; i < PRIVOP_COUNT_NINSTS; i++) { + struct privop_addr_count *v = &privop_addr_counter[i]; + s += sprintf(s,"%s:\n",v->instname); + for (j = 0; j < PRIVOP_COUNT_NADDRS; j++) { + if (!v->addr[j]) break; + s += sprintf(s," @%p #%ld\n",v->addr[j],v->count[j]); + } + if (v->overflow) + s += sprintf(s," other #%ld\n",v->overflow); + } + return s - buf; +} + +void zero_privop_addrs(void) +{ + int i,j; + for (i = 0; i < PRIVOP_COUNT_NINSTS; i++) { + struct privop_addr_count *v = &privop_addr_counter[i]; + for (j = 0; j < PRIVOP_COUNT_NADDRS; j++) + v->addr[j] = v->count[j] = 0; + v->overflow = 0; + } +} +#endif + #define TMPBUFLEN 8*1024 int dump_privop_counts_to_user(char __user *ubuf, int len) { char buf[TMPBUFLEN]; int n = dump_privop_counts(buf); +#ifdef PRIVOP_ADDR_COUNT + n += dump_privop_addrs(buf + n); +#endif if (len < TMPBUFLEN) return -1; if (__copy_to_user(ubuf,buf,n)) return -1; return n; @@ -887,6 +956,9 @@ int zero_privop_counts_to_user(char __user *ubuf, int len) char buf[TMPBUFLEN]; int n = zero_privop_counts(buf); +#ifdef PRIVOP_ADDR_COUNT + zero_privop_addrs(); +#endif if (len < TMPBUFLEN) return -1; if (__copy_to_user(ubuf,buf,n)) return -1; return n; diff --git a/xen/arch/ia64/vcpu.c b/xen/arch/ia64/vcpu.c index d1769a20c3..f5c3f458b3 100644 --- a/xen/arch/ia64/vcpu.c +++ b/xen/arch/ia64/vcpu.c @@ -37,6 +37,17 @@ typedef union { #define STATIC +#ifdef PRIVOP_ADDR_COUNT +struct privop_addr_count privop_addr_counter[PRIVOP_COUNT_NINSTS] = { + { "rsm", { 0 }, { 0 }, 0 }, + { "ssm", { 0 }, { 0 }, 0 } +}; +extern void privop_count_addr(unsigned long addr, int inst); +#define PRIVOP_COUNT_ADDR(regs,inst) privop_count_addr(regs->cr_iip,inst) +#else +#define PRIVOP_COUNT_ADDR(x,y) do {} while (0) +#endif + unsigned long vcpu_verbose = 0; #define verbose(a...) do {if (vcpu_verbose) printf(a);} while(0) @@ -77,30 +88,20 @@ vcpu_set_gr(VCPU *vcpu, unsigned reg, UINT64 value) IA64FAULT vcpu_set_ar(VCPU *vcpu, UINT64 reg, UINT64 val) { if (reg == 44) return (vcpu_set_itc(vcpu,val)); - if (reg == 27) return (IA64_ILLOP_FAULT); - if (reg > 7) return (IA64_ILLOP_FAULT); - PSCB(vcpu,krs[reg]) = val; -#if 0 -// for now, privify kr read's so all kr accesses are privileged - switch (reg) { - case 0: asm volatile ("mov ar.k0=%0" :: "r"(val)); break; - case 1: asm volatile ("mov ar.k1=%0" :: "r"(val)); break; - case 2: asm volatile ("mov ar.k2=%0" :: "r"(val)); break; - case 3: asm volatile ("mov ar.k3=%0" :: "r"(val)); break; - case 4: asm volatile ("mov ar.k4=%0" :: "r"(val)); break; - case 5: asm volatile ("mov ar.k5=%0" :: "r"(val)); break; - case 6: asm volatile ("mov ar.k6=%0" :: "r"(val)); break; - case 7: asm volatile ("mov ar.k7=%0" :: "r"(val)); break; - case 27: asm volatile ("mov ar.cflg=%0" :: "r"(val)); break; - } -#endif + else if (reg == 27) return (IA64_ILLOP_FAULT); + else if (reg == 24) + printf("warning: setting ar.eflg is a no-op; no IA-32 support\n"); + else if (reg > 7) return (IA64_ILLOP_FAULT); + else PSCB(vcpu,krs[reg]) = val; return IA64_NO_FAULT; } IA64FAULT vcpu_get_ar(VCPU *vcpu, UINT64 reg, UINT64 *val) { - if (reg > 7) return (IA64_ILLOP_FAULT); - *val = PSCB(vcpu,krs[reg]); + if (reg == 24) + printf("warning: getting ar.eflg is a no-op; no IA-32 support\n"); + else if (reg > 7) return (IA64_ILLOP_FAULT); + else *val = PSCB(vcpu,krs[reg]); return IA64_NO_FAULT; } @@ -124,6 +125,7 @@ IA64FAULT vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24) struct ia64_psr psr, imm, *ipsr; REGS *regs = vcpu_regs(vcpu); + PRIVOP_COUNT_ADDR(regs,_RSM); // TODO: All of these bits need to be virtualized // TODO: Only allowed for current vcpu __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory"); @@ -158,6 +160,7 @@ IA64FAULT vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24) REGS *regs = vcpu_regs(vcpu); UINT64 mask, enabling_interrupts = 0; + PRIVOP_COUNT_ADDR(regs,_SSM); // TODO: All of these bits need to be virtualized __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory"); imm = *(struct ia64_psr *)&imm24; diff --git a/xen/arch/ia64/xenmisc.c b/xen/arch/ia64/xenmisc.c index fe9f3442d2..09dfc2a7b9 100644 --- a/xen/arch/ia64/xenmisc.c +++ b/xen/arch/ia64/xenmisc.c @@ -132,73 +132,6 @@ void free_page_type(struct pfn_info *page, unsigned int type) dummy(); } -/////////////////////////////// -// from arch/x86/pci.c -/////////////////////////////// - -int -pcibios_prep_mwi (struct pci_dev *dev) -{ - dummy(); -} - -/////////////////////////////// -// from arch/x86/pci-irq.c -/////////////////////////////// - -void pcibios_enable_irq(struct pci_dev *dev) -{ - dummy(); -} - -/////////////////////////////// -// from arch/ia64/pci-pc.c -/////////////////////////////// - -#include - -int pcibios_enable_device(struct pci_dev *dev, int mask) -{ - dummy(); - return 0; -} - -int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value) = NULL; -int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value) = NULL; - -//struct pci_fixup pcibios_fixups[] = { { 0 } }; -struct pci_fixup pcibios_fixups[] = { { 0 } }; - -void -pcibios_align_resource(void *data, struct resource *res, - unsigned long size, unsigned long align) -{ - dummy(); -} - -void -pcibios_update_resource(struct pci_dev *dev, struct resource *root, - struct resource *res, int resource) -{ - dummy(); -} - -void __devinit pcibios_fixup_bus(struct pci_bus *b) -{ - dummy(); -} - -void __init pcibios_init(void) -{ - dummy(); -} - -char * __devinit pcibios_setup(char *str) -{ - dummy(); - return 0; -} - /////////////////////////////// // from arch/ia64/traps.c /////////////////////////////// @@ -206,7 +139,7 @@ char * __devinit pcibios_setup(char *str) void show_registers(struct pt_regs *regs) { printf("*** ADD REGISTER DUMP HERE FOR DEBUGGING\n"); -} +} /////////////////////////////// // from common/keyhandler.c diff --git a/xen/arch/ia64/xentime.c b/xen/arch/ia64/xentime.c index 20d13eb7ef..a3790b4577 100644 --- a/xen/arch/ia64/xentime.c +++ b/xen/arch/ia64/xentime.c @@ -84,6 +84,17 @@ xen_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) { unsigned long new_itm; +#define HEARTBEAT_FREQ 16 // period in seconds +#ifdef HEARTBEAT_FREQ + static long count = 0; + if (!(++count & ((HEARTBEAT_FREQ*1024)-1))) { + printf("Heartbeat... iip=%p,psr.i=%d,pend=%d\n", + regs->cr_iip, + current->vcpu_info->arch.interrupt_delivery_enabled, + current->vcpu_info->arch.pending_interruption); + count = 0; + } +#endif #ifndef XEN if (unlikely(cpu_is_offline(smp_processor_id()))) { return IRQ_HANDLED; diff --git a/xen/include/asm-ia64/config.h b/xen/include/asm-ia64/config.h index 74dbb3a4e5..0a3672b18e 100644 --- a/xen/include/asm-ia64/config.h +++ b/xen/include/asm-ia64/config.h @@ -174,12 +174,6 @@ struct device { #endif }; -// from linux/include/linux/pci.h -struct pci_bus_region { - unsigned long start; - unsigned long end; -}; - // warning: unless search_extable is declared, the return value gets // truncated to 32-bits, causing a very strange error in privop handling struct exception_table_entry; diff --git a/xen/include/asm-ia64/vcpu.h b/xen/include/asm-ia64/vcpu.h index 6ee2e73dde..e3bcfbde79 100644 --- a/xen/include/asm-ia64/vcpu.h +++ b/xen/include/asm-ia64/vcpu.h @@ -21,6 +21,21 @@ typedef struct pt_regs REGS; //#define vcpu_regs(vcpu) &((struct spk_thread_t *)vcpu)->thread_regs //#define vcpu_thread(vcpu) ((struct spk_thread_t *)vcpu) +#define PRIVOP_ADDR_COUNT +#ifdef PRIVOP_ADDR_COUNT +#define _RSM 0 +#define _SSM 1 +#define PRIVOP_COUNT_NINSTS 2 +#define PRIVOP_COUNT_NADDRS 30 + +struct privop_addr_count { + char *instname; + unsigned long addr[PRIVOP_COUNT_NADDRS]; + unsigned long count[PRIVOP_COUNT_NADDRS]; + unsigned long overflow; +}; +#endif + /* general registers */ extern UINT64 vcpu_get_gr(VCPU *vcpu, unsigned reg); extern IA64FAULT vcpu_set_gr(VCPU *vcpu, unsigned reg, UINT64 value); From aedd1ba753f07d1cecd57d7a517eab921a85acb1 Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Fri, 6 May 2005 21:20:51 +0000 Subject: [PATCH 14/54] bitkeeper revision 1.1389.9.2 (427bdfb3_b3KQR-vZHyKEmWLaNwEJQ) First implementation of hyperprivops (no fast assembly yet) Signed-off by: Dan Magenheimer --- xen/arch/ia64/asm-offsets.c | 4 ++++ xen/arch/ia64/ivt.S | 14 +++++++++++++- xen/arch/ia64/privop.c | 32 ++++++++++++++++++++++++++++++++ xen/arch/ia64/process.c | 4 ++++ xen/arch/ia64/vcpu.c | 12 ++++++++++++ 5 files changed, 65 insertions(+), 1 deletion(-) diff --git a/xen/arch/ia64/asm-offsets.c b/xen/arch/ia64/asm-offsets.c index 73f2500f81..f7b2fbd67e 100644 --- a/xen/arch/ia64/asm-offsets.c +++ b/xen/arch/ia64/asm-offsets.c @@ -8,6 +8,7 @@ #include #include #include +#include #define task_struct exec_domain @@ -37,6 +38,9 @@ void foo(void) BLANK(); + DEFINE(XSI_PSR_IC_OFS, offsetof(vcpu_info_t, arch.interrupt_collection_enabled)); + DEFINE(XSI_PSR_IC, (SHAREDINFO_ADDR+offsetof(vcpu_info_t, arch.interrupt_collection_enabled))); + DEFINE(XSI_PSR_I_OFS, offsetof(vcpu_info_t, arch.interrupt_delivery_enabled)); //DEFINE(IA64_TASK_BLOCKED_OFFSET,offsetof (struct task_struct, blocked)); //DEFINE(IA64_TASK_CLEAR_CHILD_TID_OFFSET,offsetof (struct task_struct, clear_child_tid)); //DEFINE(IA64_TASK_GROUP_LEADER_OFFSET, offsetof (struct task_struct, group_leader)); diff --git a/xen/arch/ia64/ivt.S b/xen/arch/ia64/ivt.S index f68e78a834..a44f5eb8a9 100644 --- a/xen/arch/ia64/ivt.S +++ b/xen/arch/ia64/ivt.S @@ -778,10 +778,22 @@ ENTRY(break_fault) mov r17=cr.iim mov r31=pr ;; + movl r18=XSI_PSR_IC + ;; + ld8 r19=[r18] + ;; cmp.eq p7,p0=r0,r17 // is this a psuedo-cover? - // FIXME: may also need to check slot==2? (p7) br.sptk.many dispatch_privop_fault + ;; + cmp.ne p7,p0=r0,r19 +(p7) br.sptk.many dispatch_break_fault + // If we get to here, we have a hyperprivop + // For now, hyperprivops are handled through the break mechanism + // Later, they will be fast hand-coded assembly with psr.ic off + // which means no calls, no use of r1-r15 and no memory accesses + // except to pinned addresses! br.sptk.many dispatch_break_fault + ;; #endif mov r16=IA64_KR(CURRENT) // r16 = current task; 12 cycle read lat. mov r17=cr.iim diff --git a/xen/arch/ia64/privop.c b/xen/arch/ia64/privop.c index 11ef17310f..c17adc5bde 100644 --- a/xen/arch/ia64/privop.c +++ b/xen/arch/ia64/privop.c @@ -758,6 +758,38 @@ priv_emulate(VCPU *vcpu, REGS *regs, UINT64 isr) } +// FIXME: Move these to include/public/arch-ia64? +#define HYPERPRIVOP_RFI 1 +#define HYPERPRIVOP_RSM_DT 2 +#define HYPERPRIVOP_SSM_DT 3 +#define HYPERPRIVOP_COVER 4 + +/* hyperprivops are generally executed in assembly (with physical psr.ic off) + * so this code is primarily used for debugging them */ +int +ia64_hyperprivop(unsigned long iim) +{ + struct exec_domain *ed = (struct domain *) current; + +// FIXME: Add instrumentation for these + switch(iim) { + case HYPERPRIVOP_RFI: + (void)vcpu_rfi(ed); + return 0; // don't update iip + case HYPERPRIVOP_RSM_DT: + (void)vcpu_reset_psr_dt(ed); + return 1; + case HYPERPRIVOP_SSM_DT: + (void)vcpu_set_psr_dt(ed); + return 1; + case HYPERPRIVOP_COVER: + (void)vcpu_cover(ed); + return 1; + } + return 0; +} + + /************************************************************************** Privileged operation instrumentation routines **************************************************************************/ diff --git a/xen/arch/ia64/process.c b/xen/arch/ia64/process.c index 221812123d..27115d1b39 100644 --- a/xen/arch/ia64/process.c +++ b/xen/arch/ia64/process.c @@ -722,6 +722,10 @@ ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, u if (ia64_hypercall(regs)) vcpu_increment_iip(current); } + else if (!PSCB(ed,interrupt_collection_enabled)) { + if (ia64_hyperprivop(iim)) + vcpu_increment_iip(current); + } else reflect_interruption(ifa,isr,iim,regs,IA64_BREAK_VECTOR); } diff --git a/xen/arch/ia64/vcpu.c b/xen/arch/ia64/vcpu.c index f5c3f458b3..f07d5ab788 100644 --- a/xen/arch/ia64/vcpu.c +++ b/xen/arch/ia64/vcpu.c @@ -120,6 +120,12 @@ void vcpu_set_metaphysical_mode(VCPU *vcpu, BOOLEAN newmode) } } +IA64FAULT vcpu_reset_psr_dt(VCPU *vcpu) +{ + vcpu_set_metaphysical_mode(vcpu,TRUE); + return IA64_NO_FAULT; +} + IA64FAULT vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24) { struct ia64_psr psr, imm, *ipsr; @@ -154,6 +160,12 @@ IA64FAULT vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24) extern UINT64 vcpu_check_pending_interrupts(VCPU *vcpu); #define SPURIOUS_VECTOR 0xf +IA64FAULT vcpu_set_psr_dt(VCPU *vcpu) +{ + vcpu_set_metaphysical_mode(vcpu,FALSE); + return IA64_NO_FAULT; +} + IA64FAULT vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24) { struct ia64_psr psr, imm, *ipsr; From f6f5d2be1a75012e909a592aa749bcb7d70b7dc6 Mon Sep 17 00:00:00 2001 From: "kmacy@netapp.com[kaf24]" Date: Sat, 7 May 2005 09:19:14 +0000 Subject: [PATCH 15/54] bitkeeper revision 1.1389.5.26 (427c8812BoSWeQz8YGOr4XZvnAzolA) [PATCH] [PATCH] remove gdbserver chattiness # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2005/05/06 17:39:50-07:00 kmacy@barleywine.eng.netapp.com # remove irritating chattiness from gdbserver # Signed-off-by: Kip Macy # # BitKeeper/etc/logging_ok # 2005/05/06 17:39:50-07:00 kmacy@barleywine.eng.netapp.com +1 -0 # Logging to logging@openlogging.org accepted # # tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c # 2005/05/06 17:39:19-07:00 kmacy@barleywine.eng.netapp.com +2 -1 # remove debug noise # --- tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c b/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c index 0e35f30294..e2c72f8798 100644 --- a/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c +++ b/tools/gdb/gdb-6.2.1-xen-sparse/gdb/gdbserver/linux-xen-low.c @@ -338,7 +338,9 @@ regsets_store_inferior_registers () } else { +#ifdef DEBUG perror ("Warning: ptrace(regsets_store_inferior_registers)"); +#endif } } regset ++; @@ -364,7 +366,6 @@ linux_fetch_registers (int regno) void linux_store_registers (int regno) { - printf("store %d\n", regno); if (use_regsets_p) { if (regsets_store_inferior_registers () == 0) From 8c750837ad114000d0751e8410357ba32f481661 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sat, 7 May 2005 09:43:57 +0000 Subject: [PATCH 16/54] bitkeeper revision 1.1159.258.113 (427c8dddgGYSerAwRWcC_vwqkNujiQ) Add legacy pty support to domu config. Signed-off-by: Keir Fraser --- .../arch/xen/Kconfig.drivers | 37 +++++++++++++++++++ .../arch/xen/configs/xenU_defconfig | 6 +++ 2 files changed, 43 insertions(+) diff --git a/linux-2.6.11-xen-sparse/arch/xen/Kconfig.drivers b/linux-2.6.11-xen-sparse/arch/xen/Kconfig.drivers index 8158f26fd0..cb30533783 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/Kconfig.drivers +++ b/linux-2.6.11-xen-sparse/arch/xen/Kconfig.drivers @@ -49,9 +49,46 @@ source "drivers/infiniband/Kconfig" endif if !XEN_PHYSDEV_ACCESS + +menu "Character devices" + config UNIX98_PTYS bool default y + +config LEGACY_PTYS + bool "Legacy (BSD) PTY support" + default y + ---help--- + A pseudo terminal (PTY) is a software device consisting of two + halves: a master and a slave. The slave device behaves identical to + a physical terminal; the master device is used by a process to + read data from and write data to the slave, thereby emulating a + terminal. Typical programs for the master side are telnet servers + and xterms. + + Linux has traditionally used the BSD-like names /dev/ptyxx + for masters and /dev/ttyxx for slaves of pseudo + terminals. This scheme has a number of problems, including + security. This option enables these legacy devices; on most + systems, it is safe to say N. + + +config LEGACY_PTY_COUNT + int "Maximum number of legacy PTY in use" + depends on LEGACY_PTYS + range 1 256 + default "256" + ---help--- + The maximum number of legacy PTYs that can be used at any one time. + The default is 256, and should be more than enough. Embedded + systems may want to reduce this to save memory. + + When not in use, each legacy PTY occupies 12 bytes on 32-bit + architectures and 24 bytes on 64-bit architectures. + +endmenu + endif endmenu diff --git a/linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig b/linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig index 3279d25fb9..37fce4937e 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig +++ b/linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig @@ -331,6 +331,12 @@ CONFIG_NETDEVICES=y # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# Character devices +# # # File systems From a182a0fc6e4304abec4af80f222eb01fd99fad72 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sat, 7 May 2005 09:47:18 +0000 Subject: [PATCH 17/54] bitkeeper revision 1.1389.5.28 (427c8ea6vitJqJlB7zCBJ0-DYF9xXQ) Add 'legacy pty' support to domU default kernel config. Signed-off-by: Keir Fraser --- .../arch/xen/configs/xenU_defconfig_x86_64 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig_x86_64 b/linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig_x86_64 index 9aa0f4f70e..e766ae7da1 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig_x86_64 +++ b/linux-2.6.11-xen-sparse/arch/xen/configs/xenU_defconfig_x86_64 @@ -316,6 +316,12 @@ CONFIG_NETDEVICES=y # CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 + +# +# Character devices +# # # File systems From 186141a492e85b49c4a21cd2afbf5a459417258b Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sat, 7 May 2005 10:01:24 +0000 Subject: [PATCH 18/54] bitkeeper revision 1.1389.5.29 (427c91f4-NwTlq2np5GYzwS7yWmzGA) Move serial definitions into serial.h where they can be picked up by arch-specific code. Signed-off-by: Keir Fraser --- xen/drivers/char/serial.c | 65 ------------------------------ xen/include/asm-ia64/serial.h | 63 ----------------------------- xen/include/xen/serial.h | 74 +++++++++++++++++++++++++++++++++-- 3 files changed, 70 insertions(+), 132 deletions(-) diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c index ebfd44cea8..7d9852ebab 100644 --- a/xen/drivers/char/serial.c +++ b/xen/drivers/char/serial.c @@ -26,71 +26,6 @@ static char opt_com1[30] = OPT_COM1_STR, opt_com2[30] = OPT_COM2_STR; string_param("com1", opt_com1); string_param("com2", opt_com2); -/* Register offsets */ -#define RBR 0x00 /* receive buffer */ -#define THR 0x00 /* transmit holding */ -#define IER 0x01 /* interrupt enable */ -#define IIR 0x02 /* interrupt identity */ -#define FCR 0x02 /* FIFO control */ -#define LCR 0x03 /* line control */ -#define MCR 0x04 /* Modem control */ -#define LSR 0x05 /* line status */ -#define MSR 0x06 /* Modem status */ -#define DLL 0x00 /* divisor latch (ls) (DLAB=1) */ -#define DLM 0x01 /* divisor latch (ms) (DLAB=1) */ - -/* Interrupt Enable Register */ -#define IER_ERDAI 0x01 /* rx data recv'd */ -#define IER_ETHREI 0x02 /* tx reg. empty */ -#define IER_ELSI 0x04 /* rx line status */ -#define IER_EMSI 0x08 /* MODEM status */ - -/* FIFO control register */ -#define FCR_ENABLE 0x01 /* enable FIFO */ -#define FCR_CLRX 0x02 /* clear Rx FIFO */ -#define FCR_CLTX 0x04 /* clear Tx FIFO */ -#define FCR_DMA 0x10 /* enter DMA mode */ -#define FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */ -#define FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */ -#define FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */ -#define FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */ - -/* Line control register */ -#define LCR_DLAB 0x80 /* Divisor Latch Access */ - -/* Modem Control Register */ -#define MCR_DTR 0x01 /* Data Terminal Ready */ -#define MCR_RTS 0x02 /* Request to Send */ -#define MCR_OUT2 0x08 /* OUT2: interrupt mask */ - -/* Line Status Register */ -#define LSR_DR 0x01 /* Data ready */ -#define LSR_OE 0x02 /* Overrun */ -#define LSR_PE 0x04 /* Parity error */ -#define LSR_FE 0x08 /* Framing error */ -#define LSR_BI 0x10 /* Break */ -#define LSR_THRE 0x20 /* Xmit hold reg empty */ -#define LSR_TEMT 0x40 /* Xmitter empty */ -#define LSR_ERR 0x80 /* Error */ - -/* These parity settings can be ORed directly into the LCR. */ -#define PARITY_NONE (0<<3) -#define PARITY_ODD (1<<3) -#define PARITY_EVEN (3<<3) -#define PARITY_MARK (5<<3) -#define PARITY_SPACE (7<<3) - -#define RXBUFSZ 32 -#define MASK_RXBUF_IDX(_i) ((_i)&(RXBUFSZ-1)) -struct uart { - int baud, data_bits, parity, stop_bits, io_base, irq; - serial_rx_fn rx_lo, rx_hi, rx; - spinlock_t lock; - unsigned char rxbuf[RXBUFSZ]; - unsigned int rxbufp, rxbufc; - struct irqaction irqaction; -}; - static struct uart com[2] = { { 0, 0, 0, 0, 0x3f8, 4, NULL, NULL, NULL, diff --git a/xen/include/asm-ia64/serial.h b/xen/include/asm-ia64/serial.h index 7011963fb1..1ef5776032 100644 --- a/xen/include/asm-ia64/serial.h +++ b/xen/include/asm-ia64/serial.h @@ -21,69 +21,6 @@ #define OPT_COM1_STR "115200" #define OPT_COM2_STR "" -/* Register offsets */ -#define RBR 0x00 /* receive buffer */ -#define THR 0x00 /* transmit holding */ -#define IER 0x01 /* interrupt enable */ -#define IIR 0x02 /* interrupt identity */ -#define FCR 0x02 /* FIFO control */ -#define LCR 0x03 /* line control */ -#define MCR 0x04 /* Modem control */ -#define LSR 0x05 /* line status */ -#define MSR 0x06 /* Modem status */ -#define DLL 0x00 /* divisor latch (ls) (DLAB=1) */ -#define DLM 0x01 /* divisor latch (ms) (DLAB=1) */ - -/* Interrupt Enable Register */ -#define IER_ERDAI 0x01 /* rx data recv'd */ -#define IER_ETHREI 0x02 /* tx reg. empty */ -#define IER_ELSI 0x04 /* rx line status */ -#define IER_EMSI 0x08 /* MODEM status */ - -/* FIFO control register */ -#define FCR_ENABLE 0x01 /* enable FIFO */ -#define FCR_CLRX 0x02 /* clear Rx FIFO */ -#define FCR_CLTX 0x04 /* clear Tx FIFO */ -#define FCR_DMA 0x10 /* enter DMA mode */ -#define FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */ -#define FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */ -#define FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */ -#define FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */ - -/* Line control register */ -#define LCR_DLAB 0x80 /* Divisor Latch Access */ - -/* Modem Control Register */ -#define MCR_DTR 0x01 /* Data Terminal Ready */ -#define MCR_RTS 0x02 /* Request to Send */ -#define MCR_OUT2 0x08 /* OUT2: interrupt mask */ - -/* Line Status Register */ -#define LSR_DR 0x01 /* Data ready */ -#define LSR_OE 0x02 /* Overrun */ -#define LSR_PE 0x04 /* Parity error */ -#define LSR_FE 0x08 /* Framing error */ -#define LSR_BI 0x10 /* Break */ -#define LSR_THRE 0x20 /* Xmit hold reg empty */ -#define LSR_TEMT 0x40 /* Xmitter empty */ -#define LSR_ERR 0x80 /* Error */ - -/* These parity settings can be ORed directly into the LCR. */ -#define PARITY_NONE (0<<3) -#define PARITY_ODD (1<<3) -#define PARITY_EVEN (3<<3) -#define PARITY_MARK (5<<3) -#define PARITY_SPACE (7<<3) - -#define RXBUFSZ 32 -#define MASK_RXBUF_IDX(_i) ((_i)&(RXBUFSZ-1)) - -#define UART_ENABLED(_u) ((_u)->baud != 0) -#define DISABLE_UART(_u) ((_u)->baud = 0) - -/* 'Serial handles' are comprise the following fields. */ -#define SERHND_IDX (1<<0) /* COM1 or COM2? */ - unsigned char irq_serial_getc(int handle); void serial_force_unlock(int handle); diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h index 01e5236dd5..51a0d1a1f2 100644 --- a/xen/include/xen/serial.h +++ b/xen/include/xen/serial.h @@ -11,9 +11,79 @@ #ifndef __XEN_SERIAL_H__ #define __XEN_SERIAL_H__ +#include #include #include +/* Register offsets */ +#define RBR 0x00 /* receive buffer */ +#define THR 0x00 /* transmit holding */ +#define IER 0x01 /* interrupt enable */ +#define IIR 0x02 /* interrupt identity */ +#define FCR 0x02 /* FIFO control */ +#define LCR 0x03 /* line control */ +#define MCR 0x04 /* Modem control */ +#define LSR 0x05 /* line status */ +#define MSR 0x06 /* Modem status */ +#define DLL 0x00 /* divisor latch (ls) (DLAB=1) */ +#define DLM 0x01 /* divisor latch (ms) (DLAB=1) */ + +/* Interrupt Enable Register */ +#define IER_ERDAI 0x01 /* rx data recv'd */ +#define IER_ETHREI 0x02 /* tx reg. empty */ +#define IER_ELSI 0x04 /* rx line status */ +#define IER_EMSI 0x08 /* MODEM status */ + +/* FIFO control register */ +#define FCR_ENABLE 0x01 /* enable FIFO */ +#define FCR_CLRX 0x02 /* clear Rx FIFO */ +#define FCR_CLTX 0x04 /* clear Tx FIFO */ +#define FCR_DMA 0x10 /* enter DMA mode */ +#define FCR_TRG1 0x00 /* Rx FIFO trig lev 1 */ +#define FCR_TRG4 0x40 /* Rx FIFO trig lev 4 */ +#define FCR_TRG8 0x80 /* Rx FIFO trig lev 8 */ +#define FCR_TRG14 0xc0 /* Rx FIFO trig lev 14 */ + +/* Line control register */ +#define LCR_DLAB 0x80 /* Divisor Latch Access */ + +/* Modem Control Register */ +#define MCR_DTR 0x01 /* Data Terminal Ready */ +#define MCR_RTS 0x02 /* Request to Send */ +#define MCR_OUT2 0x08 /* OUT2: interrupt mask */ + +/* Line Status Register */ +#define LSR_DR 0x01 /* Data ready */ +#define LSR_OE 0x02 /* Overrun */ +#define LSR_PE 0x04 /* Parity error */ +#define LSR_FE 0x08 /* Framing error */ +#define LSR_BI 0x10 /* Break */ +#define LSR_THRE 0x20 /* Xmit hold reg empty */ +#define LSR_TEMT 0x40 /* Xmitter empty */ +#define LSR_ERR 0x80 /* Error */ + +/* These parity settings can be ORed directly into the LCR. */ +#define PARITY_NONE (0<<3) +#define PARITY_ODD (1<<3) +#define PARITY_EVEN (3<<3) +#define PARITY_MARK (5<<3) +#define PARITY_SPACE (7<<3) + +/* Register a character-receive hook on the specified COM port. */ +typedef void (*serial_rx_fn)(unsigned char, struct cpu_user_regs *); +void serial_set_rx_handler(int handle, serial_rx_fn fn); + +#define RXBUFSZ 32 +#define MASK_RXBUF_IDX(_i) ((_i)&(RXBUFSZ-1)) +struct uart { + int baud, data_bits, parity, stop_bits, io_base, irq; + serial_rx_fn rx_lo, rx_hi, rx; + spinlock_t lock; + unsigned char rxbuf[RXBUFSZ]; + unsigned int rxbufp, rxbufc; + struct irqaction irqaction; +}; + /* 'Serial handles' are comprise the following fields. */ #define SERHND_IDX (1<<0) /* COM1 or COM2? */ #define SERHND_HI (1<<1) /* Mux/demux each transferred char by MSB. */ @@ -27,10 +97,6 @@ void serial_init_stage2(void); /* Takes a config string and creates a numeric handle on the COM port. */ int parse_serial_handle(char *conf); -/* Register a character-receive hook on the specified COM port. */ -typedef void (*serial_rx_fn)(unsigned char, struct cpu_user_regs *); -void serial_set_rx_handler(int handle, serial_rx_fn fn); - /* Transmit a single character via the specified COM port. */ void serial_putc(int handle, unsigned char c); From 904141e5e30e923f7f7ccaa65894a1fbb51dfc65 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sat, 7 May 2005 10:14:55 +0000 Subject: [PATCH 19/54] bitkeeper revision 1.1389.5.30 (427c951f6ULpkuxG36TskUioGnRY9w) x86_64 gcc sometimes doesn't have builtin memmove. Always use the version we provide. Signed-off-by: Keir Fraser --- xen/arch/x86/string.c | 38 ++++++++++++++--------------- xen/include/asm-x86/x86_64/string.h | 8 +++--- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/xen/arch/x86/string.c b/xen/arch/x86/string.c index b45a9197d5..745670b926 100644 --- a/xen/arch/x86/string.c +++ b/xen/arch/x86/string.c @@ -8,25 +8,6 @@ #include #include -#undef memmove -void *memmove(void *dest, const void *src, size_t n) -{ - int d0, d1, d2; - - if ( dest < src ) - return memcpy(dest, src, n); - - __asm__ __volatile__ ( - " std ; " - " rep ; movsb ; " - " cld " - : "=&c" (d0), "=&S" (d1), "=&D" (d2) - : "0" (n), "1" (n-1+(const char *)src), "2" (n-1+(char *)dest) - : "memory"); - - return dest; -} - #undef memcpy void *memcpy(void *dest, const void *src, size_t n) { @@ -61,3 +42,22 @@ void *memset(void *s, int c, size_t n) return s; } + +#undef memmove +void *memmove(void *dest, const void *src, size_t n) +{ + int d0, d1, d2; + + if ( dest < src ) + return memcpy(dest, src, n); + + __asm__ __volatile__ ( + " std ; " + " rep ; movsb ; " + " cld " + : "=&c" (d0), "=&S" (d1), "=&D" (d2) + : "0" (n), "1" (n-1+(const char *)src), "2" (n-1+(char *)dest) + : "memory"); + + return dest; +} diff --git a/xen/include/asm-x86/x86_64/string.h b/xen/include/asm-x86/x86_64/string.h index 6c1cc902f9..613c982718 100644 --- a/xen/include/asm-x86/x86_64/string.h +++ b/xen/include/asm-x86/x86_64/string.h @@ -1,10 +1,6 @@ #ifndef _X86_64_STRING_H_ #define _X86_64_STRING_H_ -#define __HAVE_ARCH_MEMMOVE -#define memmove(dest,src,n) (__memmove((dest),(src),(n))) -#define __memmove(dest,src,n) (__builtin_memmove((dest),(src),(n))) - #define __HAVE_ARCH_MEMCPY #define memcpy(t,f,n) (__memcpy((t),(f),(n))) #define __memcpy(t,f,n) (__builtin_memcpy((t),(f),(n))) @@ -13,4 +9,8 @@ #define memset(s, c, count) (__memset((s),(c),(count))) #define __memset(s, c, count) (__builtin_memset((s),(c),(count))) +/* Some versions of 64-bit gcc don't have this built in. */ +#define __HAVE_ARCH_MEMMOVE +extern void *memmove(void *dest, const void *src, size_t n); + #endif From c613638f31100e8901549dfbb704cfdd20993d6c Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sat, 7 May 2005 10:22:07 +0000 Subject: [PATCH 20/54] bitkeeper revision 1.1389.5.31 (427c96cfOpa2KErBqa0pO1osWWIb6Q) pci/direct.c is no longer patched in arch/xen/i386, so arch/xen/x86_64 must symlink straight to arch/i386. Signed-off-by: Keir Fraser --- linux-2.6.11-xen-sparse/arch/xen/x86_64/pci/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-2.6.11-xen-sparse/arch/xen/x86_64/pci/Makefile b/linux-2.6.11-xen-sparse/arch/xen/x86_64/pci/Makefile index d6a253a090..47dbc45daa 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/x86_64/pci/Makefile +++ b/linux-2.6.11-xen-sparse/arch/xen/x86_64/pci/Makefile @@ -12,7 +12,7 @@ c-obj-y := i386.o c-obj-y += fixup.o c-obj-$(CONFIG_ACPI_PCI) += acpi.o c-obj-y += legacy.o common.o -c-xen-obj-$(CONFIG_PCI_DIRECT)+= direct.o +c-obj-$(CONFIG_PCI_DIRECT)+= direct.o c-xen-obj-y += irq.o # mmconfig has a 64bit special c-obj-$(CONFIG_PCI_MMCONFIG) += mmconfig.o From c4d7a1af8e6b8d8c651d6f3efc0180b9ec9c17c8 Mon Sep 17 00:00:00 2001 From: "lists-xen@pimb.org[kaf24]" Date: Sun, 8 May 2005 08:37:12 +0000 Subject: [PATCH 21/54] bitkeeper revision 1.1159.258.114 (427dcfb8HaNsKoCdNjOQCEM_vCEWTA) [PATCH] [PATCH] Increase size of sxpr parser input buffer Increase the size of the sxpr parser input buffer from 1024 characters, which isn't long enough to hold larger domain configurations (xfrd transmits the entire domain config sxpr as a single atom inside of another sxpr). Signed-off-by: Jody Belka --- BitKeeper/etc/logging_ok | 1 + tools/libxutil/sxpr_parser.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok index 90b505243e..e119b60bfa 100644 --- a/BitKeeper/etc/logging_ok +++ b/BitKeeper/etc/logging_ok @@ -41,6 +41,7 @@ kaf24@striker.cl.cam.ac.uk kaf24@viper.(none) katzj@redhat.com laudney@eclipse.(none) +lists-xen@pimb.org lynx@idefix.cl.cam.ac.uk mafetter@fleming.research mark@maw48.kings.cam.ac.uk diff --git a/tools/libxutil/sxpr_parser.h b/tools/libxutil/sxpr_parser.h index 0736fd3d40..0a3fde55fd 100644 --- a/tools/libxutil/sxpr_parser.h +++ b/tools/libxutil/sxpr_parser.h @@ -28,7 +28,7 @@ /** Size of a parser input buffer. * Tokens read must fit into this size (including trailing null). */ -#define PARSER_BUF_SIZE 1024 +#define PARSER_BUF_SIZE 4096 struct Parser; typedef int ParserStateFn(struct Parser *, char c); From e76b32de9d71ca8a038e32f783cd11de1ada3a8c Mon Sep 17 00:00:00 2001 From: "kmacy@netapp.com[kaf24]" Date: Sun, 8 May 2005 08:39:54 +0000 Subject: [PATCH 22/54] bitkeeper revision 1.1389.5.33 (427dd05a9r9PEjJTAexFhIB1u7f7Sw) [PATCH] [PATCH] AP boot support # This is a BitKeeper generated diff -Nru style patch. # # ChangeSet # 2005/05/07 21:32:49-07:00 kmacy@curly.lab.netapp.com # get AP booting working # currently crashing in init_secondary - will fix after adding SMP debug support # Signed-off-by: Kip Macy # # freebsd-5.3-xen-sparse/i386-xen/include/xenfunc.h # 2005/05/07 21:32:47-07:00 kmacy@curly.lab.netapp.com +4 -0 # add declaration for per-cpu clock init # # freebsd-5.3-xen-sparse/i386-xen/include/pmap.h # 2005/05/07 21:32:47-07:00 kmacy@curly.lab.netapp.com +1 -0 # make pmap_lazyfix_action global # # freebsd-5.3-xen-sparse/i386-xen/include/pcpu.h # 2005/05/07 21:32:47-07:00 kmacy@curly.lab.netapp.com +6 -1 # add IPI fields # # freebsd-5.3-xen-sparse/i386-xen/include/hypervisor.h # 2005/05/07 21:32:47-07:00 kmacy@curly.lab.netapp.com +16 -0 # add boot_vcpu call # # freebsd-5.3-xen-sparse/i386-xen/i386-xen/xen_machdep.c # 2005/05/07 21:32:47-07:00 kmacy@curly.lab.netapp.com +0 -2 # make PANIC_IF declaration global # # freebsd-5.3-xen-sparse/i386-xen/i386-xen/pmap.c # 2005/05/07 21:32:47-07:00 kmacy@curly.lab.netapp.com +0 -1 # make pmap_lazyfix_action global # # freebsd-5.3-xen-sparse/i386-xen/i386-xen/mp_machdep.c # 2005/05/07 21:32:47-07:00 kmacy@curly.lab.netapp.com +229 -55 # add support for booting APs # # freebsd-5.3-xen-sparse/i386-xen/i386-xen/machdep.c # 2005/05/07 21:32:47-07:00 kmacy@curly.lab.netapp.com +78 -46 # do per-cpu GDT initialization up-front # # freebsd-5.3-xen-sparse/i386-xen/i386-xen/evtchn.c # 2005/05/07 21:32:47-07:00 kmacy@curly.lab.netapp.com +15 -8 # special case AST IPI # # freebsd-5.3-xen-sparse/i386-xen/i386-xen/clock.c # 2005/05/07 21:32:46-07:00 kmacy@curly.lab.netapp.com +60 -14 # add per-cpu clock support # --- .../i386-xen/i386-xen/clock.c | 74 ++++- .../i386-xen/i386-xen/evtchn.c | 23 +- .../i386-xen/i386-xen/machdep.c | 124 +++++--- .../i386-xen/i386-xen/mp_machdep.c | 284 ++++++++++++++---- .../i386-xen/i386-xen/pmap.c | 1 - .../i386-xen/i386-xen/xen_machdep.c | 2 - .../i386-xen/include/hypervisor.h | 16 + .../i386-xen/include/pcpu.h | 7 +- .../i386-xen/include/pmap.h | 1 + .../i386-xen/include/xenfunc.h | 4 + 10 files changed, 409 insertions(+), 127 deletions(-) diff --git a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/clock.c b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/clock.c index 1a25569d4b..902ae965e8 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/clock.c +++ b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/clock.c @@ -87,6 +87,12 @@ __FBSDID("$FreeBSD: src/sys/i386/isa/clock.c,v 1.207 2003/11/13 10:02:12 phk Exp /* XEN specific defines */ #include +#include /* needed by machine/pmap.h */ +#include /* needed by machine/pmap.h */ +#include /* needed by xen-os.h */ +#include +#include /* needed by xenfunc.h */ +#include /* * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we @@ -129,7 +135,15 @@ static uint64_t shadow_system_time; static uint32_t shadow_time_version; static struct timeval shadow_tv; +#define DEFINE_PER_CPU(type, name) \ + __typeof__(type) per_cpu__##name + +#define per_cpu(var, cpu) (*((void)cpu, &per_cpu__##var)) + + static uint64_t processed_system_time;/* System time (ns) at last processing. */ +static DEFINE_PER_CPU(uint64_t, processed_system_time); + #define NS_PER_TICK (1000000000ULL/hz) @@ -202,18 +216,19 @@ static struct timecounter xen_timecounter = { static void clkintr(struct clockframe *frame) { - int64_t delta; + int64_t cpu_delta, delta; + int cpu = smp_processor_id(); long ticks = 0; - do { __get_time_values_from_xen(); - delta = (int64_t)(shadow_system_time + - xen_get_offset() * 1000 - - processed_system_time); + delta = cpu_delta = (int64_t)shadow_system_time + + (int64_t)xen_get_offset() * 1000; + delta -= processed_system_time; + cpu_delta -= per_cpu(processed_system_time, cpu); } while (!TIME_VALUES_UP_TO_DATE); - if (unlikely(delta < 0)) { + if (unlikely(delta < 0) || unlikely(cpu_delta < 0)) { printk("Timer ISR: Time went backwards: %lld\n", delta); return; } @@ -225,15 +240,28 @@ clkintr(struct clockframe *frame) delta -= NS_PER_TICK; processed_system_time += NS_PER_TICK; } - - if (ticks > 0) { - if (frame) - timer_func(frame); -#ifdef SMP - if (timer_func == hardclock && frame) - forward_hardclock(); + /* Local CPU jiffy work. */ + while (cpu_delta >= NS_PER_TICK) { + cpu_delta -= NS_PER_TICK; + per_cpu(processed_system_time, cpu) += NS_PER_TICK; +#if 0 + update_process_times(user_mode(regs)); + profile_tick(CPU_PROFILING, regs); #endif } + if (ticks > 0) { + if (frame) timer_func(frame); + } + + if (cpu != 0) + return; + /* + * Take synchronised time from Xen once a minute if we're not + * synchronised ourselves, and we haven't chosen to keep an independent + * time base. + */ + + /* XXX TODO */ } #include "opt_ddb.h" @@ -429,7 +457,7 @@ resettodr() * Start clocks running. */ void -cpu_initclocks() +cpu_initclocks(void) { int diag; int time_irq = bind_virq_to_irq(VIRQ_TIMER); @@ -445,8 +473,26 @@ cpu_initclocks() /* initialize xen values */ __get_time_values_from_xen(); processed_system_time = shadow_system_time; + per_cpu(processed_system_time, 0) = processed_system_time; + } +#ifdef SMP +void +ap_cpu_initclocks(void) +{ + int irq; + int cpu = smp_processor_id(); + + per_cpu(processed_system_time, cpu) = shadow_system_time; + + irq = bind_virq_to_irq(VIRQ_TIMER); + PCPU_SET(time_irq, irq); + PANIC_IF(intr_add_handler("clk", irq, (driver_intr_t *)clkintr, + NULL, INTR_TYPE_CLK | INTR_FAST, NULL)); +} +#endif + void cpu_startprofclock(void) { diff --git a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/evtchn.c b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/evtchn.c index d6bda9ecc5..fde7fda330 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/evtchn.c +++ b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/evtchn.c @@ -79,9 +79,14 @@ evtchn_do_upcall(struct intrframe *frame) l2 &= ~(1 << l2i); port = (l1i << 5) + l2i; + irq = evtchn_to_irq[port]; +#ifdef SMP + if (irq == PCPU_GET(cpuast)) + continue; +#endif if ( (owned = mtx_owned(&sched_lock)) != 0 ) mtx_unlock_spin_flags(&sched_lock, MTX_QUIET); - if ( (irq = evtchn_to_irq[port]) != -1 ) { + if ( irq != -1 ) { struct intsrc *isrc = intr_lookup_source(irq); intr_execute_handlers(isrc, frame); } else { @@ -584,6 +589,7 @@ ap_evtchn_init(int cpu) PCPU_GET(virq_to_irq)[i] = -1; } + static void evtchn_init(void *dummy __unused) { @@ -591,13 +597,6 @@ evtchn_init(void *dummy __unused) struct xenpic *xp; struct xenpic_intsrc *pin; - /* - * xenpic_lock: in order to allow an interrupt to occur in a critical - * section, to set pcpu->ipending (etc...) properly, we - * must be able to get the icu lock, so it can't be - * under witness. - */ - mtx_init(&irq_mapping_update_lock, "xp", NULL, MTX_DEF); /* XXX -- expedience hack */ PCPU_SET(virq_to_irq, (int *)&virq_to_irq[0]); @@ -657,3 +656,11 @@ evtchn_init(void *dummy __unused) } SYSINIT(evtchn_init, SI_SUB_INTR, SI_ORDER_ANY, evtchn_init, NULL); + /* + * xenpic_lock: in order to allow an interrupt to occur in a critical + * section, to set pcpu->ipending (etc...) properly, we + * must be able to get the icu lock, so it can't be + * under witness. + */ + +MTX_SYSINIT(irq_mapping_update_lock, &irq_mapping_update_lock, "xp", MTX_DEF|MTX_NOWITNESS); diff --git a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/machdep.c b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/machdep.c index ba1adb1de9..2343e63409 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/machdep.c +++ b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/machdep.c @@ -78,6 +78,7 @@ __FBSDID("$FreeBSD: src/sys/i386/i386/machdep.c,v 1.584 2003/12/03 21:12:09 jhb #include #include #include +#include #include #include #include @@ -883,14 +884,6 @@ SYSCTL_INT(_machdep, OID_AUTO, cpu_idle_hlt, CTLFLAG_RW, static void cpu_idle_default(void) { -#if 0 - /* - * we must absolutely guarentee that hlt is the - * absolute next instruction after sti or we - * introduce a timing window. - */ - __asm __volatile("sti; hlt"); -#endif idle_block(); enable_intr(); } @@ -1376,6 +1369,7 @@ pteinfo_t *pteinfo_list; unsigned long *xen_machine_phys = ((unsigned long *)VADDR(1008, 0)); int preemptable; int gdt_set; +static int ncpus; /* Linux infection */ #define PAGE_OFFSET KERNBASE @@ -1387,6 +1381,10 @@ initvalues(start_info_t *startinfo) int i; vm_paddr_t pdir_shadow_ma, KPTphys; vm_offset_t *pdir_shadow; +#ifdef SMP + int j; +#endif + #ifdef WRITABLE_PAGETABLES printk("using writable pagetables\n"); HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_writable_pagetables); @@ -1447,18 +1445,19 @@ initvalues(start_info_t *startinfo) #ifdef SMP +#if 0 /* allocate cpu0 private page */ cpu0prvpage = (KERNBASE + (tmpindex << PAGE_SHIFT)); tmpindex++; - +#endif /* allocate SMP page table */ SMPpt = (unsigned long *)(KERNBASE + (tmpindex << PAGE_SHIFT)); - +#if 0 /* Map the private page into the SMP page table */ SMPpt[0] = vtomach(cpu0prvpage) | PG_RW | PG_M | PG_V | PG_A; - +#endif /* map SMP page table RO */ - PT_SET_MA(SMPpt, vtomach(SMPpt) & ~PG_RW); + PT_SET_MA(SMPpt, *vtopte((vm_offset_t)SMPpt) & ~PG_RW); /* put the page table into the page directory */ xen_queue_pt_update((vm_paddr_t)(IdlePTD + MPPTDI), @@ -1496,44 +1495,61 @@ initvalues(start_info_t *startinfo) tmpindex++; HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list = (unsigned long)xen_phys_machine; + ncpus = HYPERVISOR_shared_info->n_vcpu; +#ifdef SMP + for (i = 0; i < ncpus; i++) { + int npages = (sizeof(struct privatespace) + 1)/PAGE_SIZE; + for (j = 0; j < npages; j++) { + vm_paddr_t ma = xpmap_ptom(tmpindex << PAGE_SHIFT); + tmpindex++; + PT_SET_VA_MA(SMPpt + i*npages + j, ma | PG_A | PG_V | PG_RW | PG_M, FALSE); + } + } + xen_flush_queue(); +#endif init_first = tmpindex; } + +trap_info_t trap_table[] = { + { 0, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(div)}, + { 1, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(dbg)}, + { 3, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(bpt)}, + { 4, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(ofl)}, + /* This is UPL on Linux and KPL on BSD */ + { 5, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(bnd)}, + { 6, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(ill)}, + { 7, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(dna)}, + /* + * { 8, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(XXX)}, + * no handler for double fault + */ + { 9, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(fpusegm)}, + {10, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(tss)}, + {11, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(missing)}, + {12, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(stk)}, + {13, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(prot)}, + {14, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(page)}, + {15, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(rsvd)}, + {16, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(fpu)}, + {17, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(align)}, + {18, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(mchk)}, + {19, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(xmm)}, + {0x80, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(int0x80_syscall)}, + { 0, 0, 0, 0 } +}; + void init386(void) { int gsel_tss, metadata_missing, off, x, error; struct pcpu *pc; unsigned long gdtmachpfn; - trap_info_t trap_table[] = { - { 0, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(div)}, - { 1, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(dbg)}, - { 3, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(bpt)}, - { 4, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(ofl)}, - /* This is UPL on Linux and KPL on BSD */ - { 5, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(bnd)}, - { 6, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(ill)}, - { 7, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(dna)}, - /* - * { 8, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(XXX)}, - * no handler for double fault - */ - { 9, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(fpusegm)}, - {10, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(tss)}, - {11, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(missing)}, - {12, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(stk)}, - {13, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(prot)}, - {14, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(page)}, - {15, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(rsvd)}, - {16, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(fpu)}, - {17, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(align)}, - {18, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(mchk)}, - {19, 0, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(xmm)}, - {0x80, 3, GSEL(GCODE_SEL, SEL_KPL), (unsigned long) &IDTVEC(int0x80_syscall)}, - { 0, 0, 0, 0 } - }; +#ifdef SMP + int i; +#endif proc0.p_uarea = proc0uarea; thread0.td_kstack = proc0kstack; thread0.td_pcb = (struct pcb *) @@ -1583,26 +1599,42 @@ init386(void) gdt_segs[GDATA_SEL].ssd_limit = atop(0 - ((1 << 26) - (1 << 22) + (1 << 16))); #endif #ifdef SMP - /* this correspond to the cpu private page as mapped into the SMP page - * table in initvalues + /* XXX this will blow up if there are more than 512/NGDT vcpus - will never + * be an issue in the real world but should add an assert on general principles + * we'll likely blow up when we hit LAST_RESERVED_GDT_ENTRY, at which point we + * would need to start allocating more pages for the GDT */ pc = &SMP_prvspace[0].pcpu; - gdt_segs[GPRIV_SEL].ssd_limit = - atop(sizeof(struct privatespace) - 1); + for (i = 0; i < ncpus; i++) { + cpu_add(i, (i == 0)); + + gdt_segs[GPRIV_SEL].ssd_base = (int) &SMP_prvspace[i]; + gdt_segs[GPRIV_SEL].ssd_limit = + atop(sizeof(struct privatespace) - 1); + gdt_segs[GPROC0_SEL].ssd_base = + (int) &SMP_prvspace[i].pcpu.pc_common_tss; + SMP_prvspace[i].pcpu.pc_prvspace = + &SMP_prvspace[i].pcpu; + + for (x = 0; x < NGDT; x++) { + ssdtosd(&gdt_segs[x], &gdt[i * NGDT + x].sd); + } + } #else pc = &__pcpu; gdt_segs[GPRIV_SEL].ssd_limit = atop(sizeof(struct pcpu) - 1); -#endif gdt_segs[GPRIV_SEL].ssd_base = (int) pc; gdt_segs[GPROC0_SEL].ssd_base = (int) &pc->pc_common_tss; for (x = 0; x < NGDT; x++) ssdtosd(&gdt_segs[x], &gdt[x].sd); +#endif + PT_SET_MA(gdt, *vtopte((unsigned long)gdt) & ~PG_RW); gdtmachpfn = vtomach(gdt) >> PAGE_SHIFT; - if ((error = HYPERVISOR_set_gdt(&gdtmachpfn, LAST_RESERVED_GDT_ENTRY + 1))) - panic("set_gdt failed"); + PANIC_IF(HYPERVISOR_set_gdt(&gdtmachpfn, LAST_RESERVED_GDT_ENTRY + 1) != 0); + lgdt_finish(); gdt_set = 1; diff --git a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/mp_machdep.c b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/mp_machdep.c index b975c9e491..64f42259e8 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/mp_machdep.c +++ b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/mp_machdep.c @@ -83,7 +83,16 @@ __FBSDID("$FreeBSD: src/sys/i386/i386/mp_machdep.c,v 1.235.2.3 2004/09/24 15:02: #include #include + +/* XEN includes */ #include +#include + +void Xhypervisor_callback(void); +void failsafe_callback(void); + +/***************/ + #define WARMBOOT_TARGET 0 #define WARMBOOT_OFF (KERNBASE + 0x0467) @@ -94,6 +103,10 @@ __FBSDID("$FreeBSD: src/sys/i386/i386/mp_machdep.c,v 1.235.2.3 2004/09/24 15:02: #define BIOS_RESET (0x0f) #define BIOS_WARM (0x0a) + +#undef POSTCODE +#define POSTCODE(x) + /* * this code MUST be enabled here and in mpboot.s. * it follows the very early stages of AP boot by placing values in CMOS ram. @@ -175,6 +188,8 @@ extern pt_entry_t *KPTphys; /* SMP page table page */ extern pt_entry_t *SMPpt; +extern trap_info_t trap_table[]; + struct pcb stoppcbs[MAXCPU]; /* Variables needed for SMP tlb shootdown. */ @@ -208,7 +223,9 @@ static u_int boot_address; static void set_logical_apic_ids(void); static int start_all_aps(void); +#if 0 static void install_ap_tramp(void); +#endif static int start_ap(int apic_id); static void release_aps(void *dummy); @@ -314,6 +331,7 @@ int cpu_mp_probe(void) { + mp_ncpus = HYPERVISOR_shared_info->n_vcpu; /* * Always record BSP in CPU map so that the mbuf init code works * correctly. @@ -342,20 +360,24 @@ cpu_mp_probe(void) return (1); } -/* - * Initialize the IPI handlers and start up the AP's. - */ -void -cpu_mp_start(void) +static void +cpu_mp_ipi_init(void) { - int i; - - POSTCODE(MP_START_POST); - - /* Initialize the logical ID to APIC ID table. */ - for (i = 0; i < MAXCPU; i++) - cpu_apic_ids[i] = -1; - + int irq; + int cpu = smp_processor_id(); + /* + * these are not needed by XenFreeBSD - from Keir: + * For TLB-flush related IPIs, Xen has hypercalls + * you should use instead. You can pass a pointer + * to a vcpu bitmap to update_va_mapping(), and to + * MMUEXT_flush_tlb_multi and MMEXT_invlpg_multi. + * Xen will then make sure that those vcpus get + * flushed appropriately before returning to the + * caller. + * There is also no indication that we need to forward + * clock interrupts. + */ +#if 0 /* Install an inter-CPU IPI for TLB invalidation */ setidt(IPI_INVLTLB, IDTVEC(invltlb), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); @@ -371,22 +393,69 @@ cpu_mp_start(void) /* Install an inter-CPU IPI for forwarding statclock() */ setidt(IPI_STATCLOCK, IDTVEC(statclock), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - +#endif + + /* + * These can all be consolidated. For now leaving + * as individual IPIs. + * + */ +#if 0 /* Install an inter-CPU IPI for lazy pmap release */ setidt(IPI_LAZYPMAP, IDTVEC(lazypmap), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); +#else + irq = bind_ipi_on_cpu_to_irq(cpu, IPI_LAZYPMAP); + PCPU_SET(lazypmap, irq); + PANIC_IF(intr_add_handler("pmap_lazyfix", irq, + (driver_intr_t *)pmap_lazyfix_action, + NULL, INTR_TYPE_CLK | INTR_FAST, NULL)); +#endif +#if 0 /* Install an inter-CPU IPI for all-CPU rendezvous */ setidt(IPI_RENDEZVOUS, IDTVEC(rendezvous), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); +#else + irq = bind_ipi_on_cpu_to_irq(cpu, IPI_RENDEZVOUS); + PCPU_SET(rendezvous, irq); + PANIC_IF(intr_add_handler("smp_rendezvous", irq, + (driver_intr_t *)smp_rendezvous_action, + NULL, INTR_TYPE_CLK | INTR_FAST, NULL)); +#endif +#if 0 /* Install an inter-CPU IPI for forcing an additional software trap */ setidt(IPI_AST, IDTVEC(cpuast), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); - +#else + irq = bind_ipi_on_cpu_to_irq(cpu, IPI_AST); + PCPU_SET(cpuast, irq); +#endif + /* XXX ignore for now */ +#if 0 /* Install an inter-CPU IPI for CPU stop/restart */ setidt(IPI_STOP, IDTVEC(cpustop), SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); +#endif + +} + +SYSINIT(ipi_setup, SI_SUB_INTR, SI_ORDER_ANY, cpu_mp_ipi_init, NULL); + +/* + * Initialize the IPI handlers and start up the AP's. + */ +void +cpu_mp_start(void) /* --- Start here --- */ +{ + int i; + + POSTCODE(MP_START_POST); + + /* Initialize the logical ID to APIC ID table. */ + for (i = 0; i < MAXCPU; i++) + cpu_apic_ids[i] = -1; /* Set boot_cpu_id if needed. */ @@ -437,35 +506,44 @@ cpu_mp_announce(void) void init_secondary(void) { - int gsel_tss; - int x, myid; + int myid; + unsigned long gdtmachpfn; + printk("MADE IT!!"); + #if 0 u_int cr0; #endif + /* Steps to booting SMP on xen as gleaned from XenLinux: + * - cpu_init() - processor specific initialization + * - smp_callin() + * - wait 2s for BP to finish its startup sequence + * - map_cpu_to_logical_apicid() + * - save cpuid info + * - set bit in callin map to let master (BP?) continue + * - local setup timer() - per cpu timer initialization + * - ldebug_setup() - bind debug IRQ to local CPU. + * - smp_intr_init() - IPI setup that we do in cpu_mp_start + * - local_irq_enable() - enable interrupts locally + * - cpu_set(id, map) - announce that we're up + * - cpu_idle() - make us schedulable + */ + + /* bootAP is set in start_ap() to our ID. */ myid = bootAP; - gdt_segs[GPRIV_SEL].ssd_base = (int) &SMP_prvspace[myid]; - gdt_segs[GPROC0_SEL].ssd_base = - (int) &SMP_prvspace[myid].pcpu.pc_common_tss; - SMP_prvspace[myid].pcpu.pc_prvspace = - &SMP_prvspace[myid].pcpu; - for (x = 0; x < NGDT; x++) { - ssdtosd(&gdt_segs[x], &gdt[myid * NGDT + x].sd); - } + gdtmachpfn = vtomach(gdt) >> PAGE_SHIFT; + PANIC_IF(HYPERVISOR_set_gdt(&gdtmachpfn, LAST_RESERVED_GDT_ENTRY + 1) != 0); -#if 0 - r_gdt.rd_limit = NGDT * sizeof(gdt[0]) - 1; - r_gdt.rd_base = (int) &gdt[myid * NGDT]; - lgdt(&r_gdt); /* does magic intra-segment return */ + + lgdt_finish(); - lidt(&r_idt); - lldt(_default_ldt); -#endif + PCPU_SET(cpuid, myid); + + + set_user_ldt((struct mdproc *)_default_ldt); PCPU_SET(currentldt, _default_ldt); - gsel_tss = GSEL(GPROC0_SEL, SEL_KPL); - gdt[myid * NGDT + GPROC0_SEL].sd.sd_type = SDT_SYS386TSS; PCPU_SET(common_tss.tss_esp0, 0); /* not used until after switch */ PCPU_SET(common_tss.tss_ss0, GSEL(GDATA_SEL, SEL_KPL)); PCPU_SET(common_tss.tss_ioopt, (sizeof (struct i386tss)) << 16); @@ -557,6 +635,13 @@ init_secondary(void) while (smp_started == 0) ia32_pause(); + /* need to wait until now to setup the IPIs as SI_SUB_CPU is + * much earlier than SI_SUB_INTR + */ + ap_evtchn_init(myid); + ap_cpu_initclocks(); + cpu_mp_ipi_init(); + /* ok, now grab sched_lock and enter the scheduler */ mtx_lock_spin(&sched_lock); @@ -610,28 +695,35 @@ set_logical_apic_ids(void) static int start_all_aps(void) { -#ifndef PC98 - u_char mpbiosreason; -#endif - u_long mpbioswarmvec; struct pcpu *pc; char *stack; - uintptr_t kptbase; - int i, pg, apic_id, cpu; + int i, apic_id, cpu; + + /* + * This function corresponds most closely to + * smp_boot_cpus in XenLinux - the sequence there + * is: + * - check if SMP config is found - if not: + * - clear the I/O APIC IRQs + * - map cpu to logical apicid + * - exit + * - smp_intr_init - IPI initialization + * - map cpu to logical apicid + * - boot each of the vcpus + * - clear and then construct the cpu sibling [logical CPUs] map. + * + */ POSTCODE(START_ALL_APS_POST); mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN); - +#if 0 /* install the AP 1st level boot code */ install_ap_tramp(); /* save the current value of the warm-start vector */ mpbioswarmvec = *((u_long *) WARMBOOT_OFF); -#ifndef PC98 - outb(CMOS_REG, BIOS_RESET); - mpbiosreason = inb(CMOS_DATA); -#endif + /* set up temporary P==V mapping for AP boot */ /* XXX this is a hack, we should boot the AP on its own stack/PTD */ @@ -640,7 +732,7 @@ start_all_aps(void) PTD[i] = (pd_entry_t)(PG_V | PG_RW | ((kptbase + i * PAGE_SIZE) & PG_FRAME)); invltlb(); - +#endif /* start each AP */ for (cpu = 0, apic_id = 0; apic_id < MAXCPU; apic_id++) { if (!cpu_info[apic_id].cpu_present || @@ -650,7 +742,7 @@ start_all_aps(void) /* save APIC ID for this logical ID */ cpu_apic_ids[cpu] = apic_id; - +#if 0 /* first page of AP's private space */ pg = cpu * i386_btop(sizeof(struct privatespace)); @@ -665,11 +757,14 @@ start_all_aps(void) for (i = 0; i < KSTACK_PAGES; i++) SMPpt[pg + 1 + i] = (pt_entry_t) (PG_V | PG_RW | vtophys(PAGE_SIZE * i + stack)); +#endif + pc = &SMP_prvspace[cpu].pcpu; /* prime data page for it to use */ pcpu_init(pc, cpu, sizeof(struct pcpu)); pc->pc_apic_id = apic_id; +#if 0 /* setup a vector to our boot code */ *((volatile u_short *) WARMBOOT_OFF) = WARMBOOT_TARGET; *((volatile u_short *) WARMBOOT_SEG) = (boot_address >> 4); @@ -677,7 +772,7 @@ start_all_aps(void) outb(CMOS_REG, BIOS_RESET); outb(CMOS_DATA, BIOS_WARM); /* 'warm-start' */ #endif - +#endif bootSTK = &SMP_prvspace[cpu].idlekstack[KSTACK_PAGES * PAGE_SIZE]; bootAP = cpu; @@ -700,13 +795,10 @@ start_all_aps(void) /* build our map of 'other' CPUs */ PCPU_SET(other_cpus, all_cpus & ~PCPU_GET(cpumask)); +#if 0 /* restore the warmstart vector */ *(u_long *) WARMBOOT_OFF = mpbioswarmvec; -#ifndef PC98 - outb(CMOS_REG, BIOS_RESET); - outb(CMOS_DATA, mpbiosreason); #endif - /* * Set up the idle context for the BSP. Similar to above except * that some was done by locore, some by pmap.c and some is implicit @@ -739,7 +831,7 @@ extern void bootDataSeg(void); extern void MPentry(void); extern u_int MP_GDT; extern u_int mp_gdtbase; - +#if 0 static void install_ap_tramp(void) { @@ -791,6 +883,21 @@ install_ap_tramp(void) *dst16 = (u_int) boot_address & 0xffff; *dst8 = ((u_int) boot_address >> 16) & 0xff; } +#endif + +static int +cpu_mp_trap_init(trap_info_t *trap_ctxt) +{ + + trap_info_t *t = trap_table; + + for (t = trap_table; t->address; t++) { + trap_ctxt[t->vector].flags = t->flags; + trap_ctxt[t->vector].cs = t->cs; + trap_ctxt[t->vector].address = t->address; + } + return 0x80 /*SYSCALL_VECTOR*/; +} /* * This function starts the AP (application processor) identified @@ -802,8 +909,25 @@ install_ap_tramp(void) static int start_ap(int apic_id) { - int vector, ms; - int cpus; + int vector, ms, i; + int cpus, boot_error; + vcpu_guest_context_t ctxt; + + /* + * This is the FreeBSD equivalent to do_boot_cpu(apicid) in + * smpboot.c. + * its initialization sequence consists of: + * - fork_idle(cpu) to create separate idle context + * - initialization of idle's context to start_secondary + * - initialization of cpu ctxt to start in startup_32_smp + * - then we call HYPERVISOR_boot_vcpu with the cpu index and + * a pointer to the context. + * - on boot success we: + * - set ourselves in the callout_map + * - wait up to 5 seconds for us to be set in the callin map + * - set x86_cpu_to_apicid[cpu] = apicid; + * + */ POSTCODE(START_AP_POST); @@ -813,6 +937,55 @@ start_ap(int apic_id) /* used as a watchpoint to signal AP startup */ cpus = mp_naps; + memset(&ctxt, 0, sizeof(ctxt)); + + ctxt.user_regs.ds = GSEL(GDATA_SEL, SEL_KPL); + ctxt.user_regs.es = GSEL(GDATA_SEL, SEL_KPL); + ctxt.user_regs.fs = 0; + ctxt.user_regs.gs = 0; + ctxt.user_regs.ss = __KERNEL_DS; + ctxt.user_regs.cs = __KERNEL_CS; + ctxt.user_regs.eip = (unsigned long)init_secondary; + ctxt.user_regs.esp = (unsigned long)bootSTK; +#ifdef notyet + ctxt.user_regs.eflags = (1<<9) | (1<<2) | (idle->thread.io_pl<<12); +#else + ctxt.user_regs.eflags = (1<<9) | (1<<2); +#endif + /* FPU is set up to default initial state. */ + memset(&ctxt.fpu_ctxt, 0, sizeof(ctxt.fpu_ctxt)); + + /* Virtual IDT is empty at start-of-day. */ + for ( i = 0; i < 256; i++ ) + { + ctxt.trap_ctxt[i].vector = i; + ctxt.trap_ctxt[i].cs = FLAT_KERNEL_CS; + } + ctxt.fast_trap_idx = cpu_mp_trap_init(ctxt.trap_ctxt); + + /* No LDT. */ + ctxt.ldt_ents = 0; + + /* Ring 1 stack is the initial stack. */ + ctxt.kernel_ss = __KERNEL_DS; + ctxt.kernel_sp = (unsigned long)bootSTK; + + /* Callback handlers. */ + ctxt.event_callback_cs = __KERNEL_CS; + ctxt.event_callback_eip = (unsigned long)Xhypervisor_callback; + ctxt.failsafe_callback_cs = __KERNEL_CS; + ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback; + + ctxt.pt_base = (vm_paddr_t)IdlePTD; + + boot_error = HYPERVISOR_boot_vcpu(bootAP, &ctxt); + + + if (boot_error) + printk("Houston we have a problem\n"); + else + printk("boot_vcpu succeeded\n"); +#if 0 /* * first we do an INIT/RESET IPI this INIT IPI might be run, reseting * and running the target CPU. OR this INIT IPI might be latched (P5 @@ -862,6 +1035,7 @@ start_ap(int apic_id) APIC_LEVEL_DEASSERT | APIC_DESTMODE_PHY | APIC_DELMODE_STARTUP | vector, apic_id); lapic_ipi_wait(-1); +#endif DELAY(200); /* wait ~200uS */ /* Wait up to 5 seconds for it to start. */ diff --git a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/pmap.c b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/pmap.c index 79b052a34c..6529602eb7 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/pmap.c +++ b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/pmap.c @@ -1374,7 +1374,6 @@ static u_int *lazymask; static u_int lazyptd; static volatile u_int lazywait; -void pmap_lazyfix_action(void); void pmap_lazyfix_action(void) diff --git a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/xen_machdep.c b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/xen_machdep.c index 85794f2c2e..2d7f184ac7 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/i386-xen/xen_machdep.c +++ b/freebsd-5.3-xen-sparse/i386-xen/i386-xen/xen_machdep.c @@ -380,8 +380,6 @@ printk(const char *fmt, ...) (void)HYPERVISOR_console_write(buf, ret); } -#define PANIC_IF(exp) if (unlikely(exp)) {printk("%s failed\n",#exp); panic("%s: %s:%d", #exp, __FILE__, __LINE__);} - #define XPQUEUE_SIZE 128 #ifdef SMP diff --git a/freebsd-5.3-xen-sparse/i386-xen/include/hypervisor.h b/freebsd-5.3-xen-sparse/i386-xen/include/hypervisor.h index 94c449ded9..824ca96cee 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/include/hypervisor.h +++ b/freebsd-5.3-xen-sparse/i386-xen/include/hypervisor.h @@ -441,4 +441,20 @@ HYPERVISOR_vm_assist(unsigned int cmd, unsigned int type) return ret; } +static inline int +HYPERVISOR_boot_vcpu( + unsigned long vcpu, vcpu_guest_context_t *ctxt) +{ + int ret; + unsigned long ign1, ign2; + + __asm__ __volatile__ ( + TRAP_INSTR + : "=a" (ret), "=b" (ign1), "=c" (ign2) + : "0" (__HYPERVISOR_boot_vcpu), "1" (vcpu), "2" (ctxt) + : "memory"); + + return ret; +} + #endif /* __HYPERVISOR_H__ */ diff --git a/freebsd-5.3-xen-sparse/i386-xen/include/pcpu.h b/freebsd-5.3-xen-sparse/i386-xen/include/pcpu.h index e373697cca..42941d5a91 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/include/pcpu.h +++ b/freebsd-5.3-xen-sparse/i386-xen/include/pcpu.h @@ -53,7 +53,12 @@ int *pc_ipi_to_evtchn; \ int *pc_virq_to_irq; \ u_int pc_cr2; \ - u_int pc_pdir + u_int pc_pdir; \ + u_int pc_lazypmap; \ + u_int pc_rendezvous; \ + u_int pc_cpuast; \ + u_int pc_time_irq; \ + uint64_t pc_processed_system_time; #if defined(lint) diff --git a/freebsd-5.3-xen-sparse/i386-xen/include/pmap.h b/freebsd-5.3-xen-sparse/i386-xen/include/pmap.h index c067a19969..d7f1923234 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/include/pmap.h +++ b/freebsd-5.3-xen-sparse/i386-xen/include/pmap.h @@ -343,6 +343,7 @@ void pmap_set_pg(void); void pmap_invalidate_page(pmap_t, vm_offset_t); void pmap_invalidate_range(pmap_t, vm_offset_t, vm_offset_t); void pmap_invalidate_all(pmap_t); +void pmap_lazyfix_action(void); void pmap_map_readonly(pmap_t pmap, vm_offset_t va, int len); void pmap_map_readwrite(pmap_t pmap, vm_offset_t va, int len); diff --git a/freebsd-5.3-xen-sparse/i386-xen/include/xenfunc.h b/freebsd-5.3-xen-sparse/i386-xen/include/xenfunc.h index bd35cf2ff1..e2b682265f 100644 --- a/freebsd-5.3-xen-sparse/i386-xen/include/xenfunc.h +++ b/freebsd-5.3-xen-sparse/i386-xen/include/xenfunc.h @@ -61,6 +61,9 @@ void load_cr3(uint32_t val); void xen_machphys_update(unsigned long, unsigned long); void xen_update_descriptor(union descriptor *, union descriptor *); void lldt(u_short sel); +void ap_cpu_initclocks(void); + + /* * Invalidate a patricular VA on all cpus * @@ -79,5 +82,6 @@ invltlb(void) } +#define PANIC_IF(exp) if (unlikely(exp)) {printk("%s failed\n",#exp); panic("%s: %s:%d", #exp, __FILE__, __LINE__);} #endif /* _XEN_XENFUNC_H_ */ From a0cc4ba202a39f23085b367904a4c9a9684b4954 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sun, 8 May 2005 11:12:14 +0000 Subject: [PATCH 23/54] bitkeeper revision 1.1389.5.34 (427df40e93QBBJSf6UjtUfrHOApBXA) Fix process destruction: we should clear the LDT before calling destroy_context(). Signed-off-by: Keir Fraser --- linux-2.6.11-xen-sparse/arch/xen/i386/mm/init.c | 1 + linux-2.6.11-xen-sparse/arch/xen/i386/mm/pgtable.c | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/mm/init.c b/linux-2.6.11-xen-sparse/arch/xen/i386/mm/init.c index e3a588e029..b571bd6aaf 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/mm/init.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/mm/init.c @@ -361,6 +361,7 @@ static void __init pagetable_init (void) make_page_writable(old_pgd); __flush_tlb_all(); free_bootmem(__pa(old_pgd), PAGE_SIZE); + init_mm.context.pinned = 1; kernel_physical_mapping_init(pgd_base); remap_numa_kva(); diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/mm/pgtable.c b/linux-2.6.11-xen-sparse/arch/xen/i386/mm/pgtable.c index 59399cceff..0215422a5a 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/mm/pgtable.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/mm/pgtable.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -480,7 +481,6 @@ void mm_unpin(struct mm_struct *mm) void _arch_exit_mmap(struct mm_struct *mm) { - unsigned int cpu = smp_processor_id(); struct task_struct *tsk = current; task_lock(tsk); @@ -494,9 +494,7 @@ void _arch_exit_mmap(struct mm_struct *mm) tsk->active_mm = &init_mm; atomic_inc(&init_mm.mm_count); - cpu_set(cpu, init_mm.cpu_vm_mask); - load_cr3(swapper_pg_dir); - cpu_clear(cpu, mm->cpu_vm_mask); + switch_mm(mm, &init_mm, tsk); atomic_dec(&mm->mm_count); BUG_ON(atomic_read(&mm->mm_count) == 0); From 96f8844d3d165eadc9cba55aa91fe2166a496e62 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sun, 8 May 2005 12:06:10 +0000 Subject: [PATCH 24/54] bitkeeper revision 1.1389.5.35 (427e00b2juTv-JMiPdIYinvwaH2N8Q) Field-name cleanups. Signed-off-by: Keir Fraser --- xen/arch/ia64/domain.c | 8 ++-- xen/arch/ia64/idle0_task.c | 2 +- xen/arch/ia64/xenmisc.c | 4 +- xen/arch/ia64/xensetup.c | 2 +- xen/arch/x86/dom0_ops.c | 2 +- xen/arch/x86/domain.c | 16 +++---- xen/arch/x86/domain_build.c | 4 +- xen/arch/x86/i387.c | 6 +-- xen/arch/x86/idle0_task.c | 2 +- xen/arch/x86/mm.c | 12 ++--- xen/arch/x86/physdev.c | 2 +- xen/arch/x86/setup.c | 2 +- xen/arch/x86/shadow.c | 2 +- xen/arch/x86/smpboot.c | 2 +- xen/arch/x86/traps.c | 14 +++--- xen/common/dom0_ops.c | 20 ++++---- xen/common/domain.c | 34 +++++++------- xen/common/event_channel.c | 2 +- xen/common/keyhandler.c | 8 ++-- xen/common/page_alloc.c | 6 +-- xen/common/sched_bvt.c | 68 +++++++++++++-------------- xen/common/schedule.c | 51 ++++++++++---------- xen/include/asm-x86/config.h | 4 +- xen/include/asm-x86/debugger.h | 2 +- xen/include/asm-x86/i387.h | 2 +- xen/include/xen/event.h | 2 +- xen/include/xen/sched.h | 85 ++++++++++++++++++---------------- 27 files changed, 185 insertions(+), 179 deletions(-) diff --git a/xen/arch/ia64/domain.c b/xen/arch/ia64/domain.c index 9f0d9d20ba..19a608e1ac 100644 --- a/xen/arch/ia64/domain.c +++ b/xen/arch/ia64/domain.c @@ -626,7 +626,7 @@ int construct_dom0(struct domain *d, #ifndef CLONE_DOMAIN0 if ( d != dom0 ) BUG(); - if ( test_bit(DF_CONSTRUCTED, &d->d_flags) ) + if ( test_bit(DF_CONSTRUCTED, &d->flags) ) BUG(); #endif @@ -753,7 +753,7 @@ int construct_dom0(struct domain *d, #endif console_endboot(strstr(cmdline, "tty0") != NULL); - set_bit(DF_CONSTRUCTED, &d->d_flags); + set_bit(DF_CONSTRUCTED, &d->flags); new_thread(ed, pkern_entry, 0, 0); // FIXME: Hack for keyboard input @@ -783,7 +783,7 @@ int construct_domU(struct domain *d, unsigned long pkern_entry; #ifndef DOMU_AUTO_RESTART - if ( test_bit(DF_CONSTRUCTED, &d->d_flags) ) BUG(); + if ( test_bit(DF_CONSTRUCTED, &d->flags) ) BUG(); #endif printk("*** LOADING DOMAIN %d ***\n",d->id); @@ -816,7 +816,7 @@ int construct_domU(struct domain *d, loaddomainelfimage(d,image_start); printk("loaddomainelfimage returns\n"); - set_bit(DF_CONSTRUCTED, &d->d_flags); + set_bit(DF_CONSTRUCTED, &d->flags); printk("calling new_thread, entry=%p\n",pkern_entry); #ifdef DOMU_AUTO_RESTART diff --git a/xen/arch/ia64/idle0_task.c b/xen/arch/ia64/idle0_task.c index b7523ea502..4bc636ae6e 100644 --- a/xen/arch/ia64/idle0_task.c +++ b/xen/arch/ia64/idle0_task.c @@ -22,7 +22,7 @@ #define IDLE0_DOMAIN(_t) \ { \ id: IDLE_DOMAIN_ID, \ - d_flags: 1<domain->id & 0xf; if (!cnt[id]--) { printk("%x",id); cnt[id] = 50; } if (!i--) { printk("+",id); cnt[id] = 100; } } - clear_bit(EDF_RUNNING, &prev->ed_flags); + clear_bit(EDF_RUNNING, &prev->flags); //if (!is_idle_task(next->domain) ) //send_guest_virq(next, VIRQ_TIMER); load_region_regs(current); @@ -270,7 +270,7 @@ loop: printf(buf); if (regs) show_registers(regs); domain_pause_by_systemcontroller(current->domain); - set_bit(DF_CRASHED, ed->domain->d_flags); + set_bit(DF_CRASHED, ed->domain->flags); if (ed->domain->id == 0) { int i = 1000000000L; // if domain0 crashes, just periodically print out panic diff --git a/xen/arch/ia64/xensetup.c b/xen/arch/ia64/xensetup.c index 7d497ea40c..ec864e1ef2 100644 --- a/xen/arch/ia64/xensetup.c +++ b/xen/arch/ia64/xensetup.c @@ -267,7 +267,7 @@ printk("About to call init_idle_task()\n"); if ( dom0 == NULL ) panic("Error creating domain 0\n"); - set_bit(DF_PRIVILEGED, &dom0->d_flags); + set_bit(DF_PRIVILEGED, &dom0->flags); /* * We're going to setup domain0 using the module(s) that we stashed safely diff --git a/xen/arch/x86/dom0_ops.c b/xen/arch/x86/dom0_ops.c index 722317b698..a3251368ce 100644 --- a/xen/arch/x86/dom0_ops.c +++ b/xen/arch/x86/dom0_ops.c @@ -397,7 +397,7 @@ void arch_getdomaininfo_ctxt( #endif c->flags = 0; - if ( test_bit(EDF_DONEFPUINIT, &ed->ed_flags) ) + if ( test_bit(EDF_DONEFPUINIT, &ed->flags) ) c->flags |= VGCF_I387_VALID; if ( KERNEL_MODE(ed, &ed->arch.guest_context.user_regs) ) c->flags |= VGCF_IN_KERNEL; diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 3d275206b4..a3fdcaf1bf 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -252,7 +252,7 @@ void arch_do_createdomain(struct exec_domain *ed) d->shared_info = (void *)alloc_xenheap_page(); memset(d->shared_info, 0, PAGE_SIZE); - ed->vcpu_info = &d->shared_info->vcpu_data[ed->eid]; + ed->vcpu_info = &d->shared_info->vcpu_data[ed->id]; SHARE_PFN_WITH_DOMAIN(virt_to_page(d->shared_info), d); machine_to_phys_mapping[virt_to_phys(d->shared_info) >> PAGE_SHIFT] = INVALID_M2P_ENTRY; @@ -294,7 +294,7 @@ void arch_do_boot_vcpu(struct exec_domain *ed) struct domain *d = ed->domain; ed->arch.schedule_tail = d->exec_domain[0]->arch.schedule_tail; ed->arch.perdomain_ptes = - d->arch.mm_perdomain_pt + (ed->eid << PDPT_VCPU_SHIFT); + d->arch.mm_perdomain_pt + (ed->id << PDPT_VCPU_SHIFT); ed->arch.flags = TF_kernel_mode; } @@ -397,9 +397,9 @@ int arch_set_info_guest( return -EINVAL; } - clear_bit(EDF_DONEFPUINIT, &ed->ed_flags); + clear_bit(EDF_DONEFPUINIT, &ed->flags); if ( c->flags & VGCF_I387_VALID ) - set_bit(EDF_DONEFPUINIT, &ed->ed_flags); + set_bit(EDF_DONEFPUINIT, &ed->flags); ed->arch.flags &= ~TF_kernel_mode; if ( c->flags & VGCF_IN_KERNEL ) @@ -415,7 +415,7 @@ int arch_set_info_guest( if ( !IS_PRIV(d) ) ed->arch.guest_context.user_regs.eflags &= 0xffffcfff; - if ( test_bit(EDF_DONEINIT, &ed->ed_flags) ) + if ( test_bit(EDF_DONEINIT, &ed->flags) ) return 0; if ( (rc = (int)set_fast_trap(ed, c->fast_trap_idx)) != 0 ) @@ -426,7 +426,7 @@ int arch_set_info_guest( for ( i = 0; i < 8; i++ ) (void)set_debugreg(ed, i, c->debugreg[i]); - if ( ed->eid == 0 ) + if ( ed->id == 0 ) d->vm_assist = c->vm_assist; phys_basetab = c->pt_base; @@ -478,7 +478,7 @@ int arch_set_info_guest( update_pagetables(ed); /* Don't redo final setup */ - set_bit(EDF_DONEINIT, &ed->ed_flags); + set_bit(EDF_DONEINIT, &ed->flags); return 0; } @@ -796,7 +796,7 @@ void context_switch(struct exec_domain *prev, struct exec_domain *next) * 'prev' (after this point, a dying domain's info structure may be freed * without warning). */ - clear_bit(EDF_RUNNING, &prev->ed_flags); + clear_bit(EDF_RUNNING, &prev->flags); schedule_tail(next); BUG(); diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c index 5a82ac60eb..5c650f4688 100644 --- a/xen/arch/x86/domain_build.c +++ b/xen/arch/x86/domain_build.c @@ -114,7 +114,7 @@ int construct_dom0(struct domain *d, /* Sanity! */ if ( d->id != 0 ) BUG(); - if ( test_bit(DF_CONSTRUCTED, &d->d_flags) ) + if ( test_bit(DF_CONSTRUCTED, &d->flags) ) BUG(); memset(&dsi, 0, sizeof(struct domain_setup_info)); @@ -540,7 +540,7 @@ int construct_dom0(struct domain *d, /* DOM0 gets access to everything. */ physdev_init_dom0(d); - set_bit(DF_CONSTRUCTED, &d->d_flags); + set_bit(DF_CONSTRUCTED, &d->flags); new_thread(ed, dsi.v_kernentry, vstack_end, vstartinfo_start); diff --git a/xen/arch/x86/i387.c b/xen/arch/x86/i387.c index 08dc9fdcb7..af54d0af8a 100644 --- a/xen/arch/x86/i387.c +++ b/xen/arch/x86/i387.c @@ -18,7 +18,7 @@ void init_fpu(void) __asm__ __volatile__ ( "fninit" ); if ( cpu_has_xmm ) load_mxcsr(0x1f80); - set_bit(EDF_DONEFPUINIT, ¤t->ed_flags); + set_bit(EDF_DONEFPUINIT, ¤t->flags); } void save_init_fpu(struct exec_domain *tsk) @@ -28,7 +28,7 @@ void save_init_fpu(struct exec_domain *tsk) * This causes us to set the real flag, so we'll need * to temporarily clear it while saving f-p state. */ - if ( test_bit(EDF_GUEST_STTS, &tsk->ed_flags) ) + if ( test_bit(EDF_GUEST_STTS, &tsk->flags) ) clts(); if ( cpu_has_fxsr ) @@ -40,7 +40,7 @@ void save_init_fpu(struct exec_domain *tsk) "fnsave %0 ; fwait" : "=m" (tsk->arch.guest_context.fpu_ctxt) ); - clear_bit(EDF_USEDFPU, &tsk->ed_flags); + clear_bit(EDF_USEDFPU, &tsk->flags); stts(); } diff --git a/xen/arch/x86/idle0_task.c b/xen/arch/x86/idle0_task.c index 71fbc34dd6..43c0c31c25 100644 --- a/xen/arch/x86/idle0_task.c +++ b/xen/arch/x86/idle0_task.c @@ -5,7 +5,7 @@ struct domain idle0_domain = { id: IDLE_DOMAIN_ID, - d_flags: 1<d_flags)); + test_bit(DF_DYING, &page_get_owner(page)->flags)); if ( unlikely((nx & PGT_count_mask) == 0) ) { @@ -1691,13 +1691,13 @@ int do_mmuext_op( * it is dying. */ ASSERT(e->tot_pages <= e->max_pages); - if ( unlikely(test_bit(DF_DYING, &e->d_flags)) || + if ( unlikely(test_bit(DF_DYING, &e->flags)) || unlikely(e->tot_pages == e->max_pages) || unlikely(IS_XEN_HEAP_FRAME(page)) ) { MEM_LOG("Transferee has no reservation headroom (%d,%d), or " "page is in Xen heap (%lx), or dom is dying (%ld).\n", - e->tot_pages, e->max_pages, op.mfn, e->d_flags); + e->tot_pages, e->max_pages, op.mfn, e->flags); okay = 0; goto reassign_fail; } @@ -2776,7 +2776,7 @@ int ptwr_do_page_fault(struct domain *d, unsigned long addr) * If this is a multi-processor guest then ensure that the page is hooked * into at most one L2 table, which must be the one running on this VCPU. */ - if ( (d->exec_domain[0]->ed_next_list != NULL) && + if ( (d->exec_domain[0]->next_in_list != NULL) && ((page->u.inuse.type_info & PGT_count_mask) != (!!(page->u.inuse.type_info & PGT_pinned) + (which == PTWR_PT_ACTIVE))) ) @@ -2945,13 +2945,13 @@ void ptwr_destroy(struct domain *d) * Also, a domain mustn't have PGC_allocated pages when it is dying. */ ASSERT(e->tot_pages <= e->max_pages); - if ( unlikely(test_bit(DF_DYING, &e->d_flags)) || + if ( unlikely(test_bit(DF_DYING, &e->flags)) || unlikely(e->tot_pages == e->max_pages) || unlikely(!gnttab_prepare_for_transfer(e, d, gntref)) ) { MEM_LOG("Transferee has no reservation headroom (%d,%d), or " "provided a bad grant ref, or is dying (%p).\n", - e->tot_pages, e->max_pages, e->d_flags); + e->tot_pages, e->max_pages, e->flags); spin_unlock(&e->page_alloc_lock); put_domain(e); okay = 0; diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c index 9e47826998..66e0ed1251 100644 --- a/xen/arch/x86/physdev.c +++ b/xen/arch/x86/physdev.c @@ -130,7 +130,7 @@ void physdev_init_dom0(struct domain *d) BUG_ON(d->arch.iobmp_mask == NULL); memset(d->arch.iobmp_mask, 0, IOBMP_BYTES); - set_bit(DF_PHYSDEV, &d->d_flags); + set_bit(DF_PHYSDEV, &d->flags); } diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 8b8f8182e0..37cc2c4684 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -581,7 +581,7 @@ void __init __start_xen(multiboot_info_t *mbi) if ( dom0 == NULL ) panic("Error creating domain 0\n"); - set_bit(DF_PRIVILEGED, &dom0->d_flags); + set_bit(DF_PRIVILEGED, &dom0->flags); /* Grab the DOM0 command line. Skip past the image name. */ cmdline = (char *)(mod[0].string ? __va(mod[0].string) : NULL); diff --git a/xen/arch/x86/shadow.c b/xen/arch/x86/shadow.c index 3651d9c9aa..6d8a849005 100644 --- a/xen/arch/x86/shadow.c +++ b/xen/arch/x86/shadow.c @@ -1120,7 +1120,7 @@ void __shadow_mode_disable(struct domain *d) * Currently this does not fix up page ref counts, so it is valid to call * only when a domain is being destroyed. */ - BUG_ON(!test_bit(DF_DYING, &d->d_flags)); + BUG_ON(!test_bit(DF_DYING, &d->flags)); d->arch.shadow_tainted_refcnts = 1; free_shadow_pages(d); diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index a992045be2..981a36d97d 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -658,7 +658,7 @@ static void __init do_boot_cpu (int apicid) ed = idle->exec_domain[0]; - set_bit(DF_IDLETASK, &idle->d_flags); + set_bit(DF_IDLETASK, &idle->flags); ed->arch.monitor_table = mk_pagetable(__pa(idle_pg_table)); diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 3c5cc07c0c..f242333c8d 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -361,13 +361,13 @@ long do_fpu_taskswitch(int set) if ( set ) { - set_bit(EDF_GUEST_STTS, &ed->ed_flags); + set_bit(EDF_GUEST_STTS, &ed->flags); stts(); } else { - clear_bit(EDF_GUEST_STTS, &ed->ed_flags); - if ( test_bit(EDF_USEDFPU, &ed->ed_flags) ) + clear_bit(EDF_GUEST_STTS, &ed->flags); + if ( test_bit(EDF_USEDFPU, &ed->flags) ) clts(); } @@ -665,7 +665,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs) case 0: /* Read CR0 */ *reg = (read_cr0() & ~X86_CR0_TS) | - (test_bit(EDF_GUEST_STTS, &ed->ed_flags) ? X86_CR0_TS : 0); + (test_bit(EDF_GUEST_STTS, &ed->flags) ? X86_CR0_TS : 0); break; case 2: /* Read CR2 */ @@ -919,15 +919,15 @@ asmlinkage int math_state_restore(struct cpu_user_regs *regs) /* Prevent recursion. */ clts(); - if ( !test_and_set_bit(EDF_USEDFPU, ¤t->ed_flags) ) + if ( !test_and_set_bit(EDF_USEDFPU, ¤t->flags) ) { - if ( test_bit(EDF_DONEFPUINIT, ¤t->ed_flags) ) + if ( test_bit(EDF_DONEFPUINIT, ¤t->flags) ) restore_fpu(current); else init_fpu(); } - if ( test_and_clear_bit(EDF_GUEST_STTS, ¤t->ed_flags) ) + if ( test_and_clear_bit(EDF_GUEST_STTS, ¤t->flags) ) { struct trap_bounce *tb = ¤t->arch.trap_bounce; tb->flags = TBF_EXCEPTION; diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c index 750eb14813..23fc589d4d 100644 --- a/xen/common/dom0_ops.c +++ b/xen/common/dom0_ops.c @@ -139,7 +139,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op) { ret = -EINVAL; if ( (d != current->domain) && - test_bit(DF_CONSTRUCTED, &d->d_flags) ) + test_bit(DF_CONSTRUCTED, &d->flags) ) { domain_unpause_by_systemcontroller(d); ret = 0; @@ -246,14 +246,14 @@ long do_dom0_op(dom0_op_t *u_dom0_op) if ( cpu == -1 ) { - clear_bit(EDF_CPUPINNED, &ed->ed_flags); + clear_bit(EDF_CPUPINNED, &ed->flags); } else { exec_domain_pause(ed); if ( ed->processor != (cpu % smp_num_cpus) ) - set_bit(EDF_MIGRATED, &ed->ed_flags); - set_bit(EDF_CPUPINNED, &ed->ed_flags); + set_bit(EDF_MIGRATED, &ed->flags); + set_bit(EDF_CPUPINNED, &ed->flags); ed->processor = cpu % smp_num_cpus; exec_domain_unpause(ed); } @@ -311,12 +311,12 @@ long do_dom0_op(dom0_op_t *u_dom0_op) ed = d->exec_domain[op->u.getdomaininfo.exec_domain]; op->u.getdomaininfo.flags = - (test_bit( DF_DYING, &d->d_flags) ? DOMFLAGS_DYING : 0) | - (test_bit( DF_CRASHED, &d->d_flags) ? DOMFLAGS_CRASHED : 0) | - (test_bit( DF_SHUTDOWN, &d->d_flags) ? DOMFLAGS_SHUTDOWN : 0) | - (test_bit(EDF_CTRLPAUSE, &ed->ed_flags) ? DOMFLAGS_PAUSED : 0) | - (test_bit(EDF_BLOCKED, &ed->ed_flags) ? DOMFLAGS_BLOCKED : 0) | - (test_bit(EDF_RUNNING, &ed->ed_flags) ? DOMFLAGS_RUNNING : 0); + (test_bit( DF_DYING, &d->flags) ? DOMFLAGS_DYING : 0) | + (test_bit( DF_CRASHED, &d->flags) ? DOMFLAGS_CRASHED : 0) | + (test_bit( DF_SHUTDOWN, &d->flags) ? DOMFLAGS_SHUTDOWN : 0) | + (test_bit(EDF_CTRLPAUSE, &ed->flags) ? DOMFLAGS_PAUSED : 0) | + (test_bit(EDF_BLOCKED, &ed->flags) ? DOMFLAGS_BLOCKED : 0) | + (test_bit(EDF_RUNNING, &ed->flags) ? DOMFLAGS_RUNNING : 0); op->u.getdomaininfo.flags |= ed->processor << DOMFLAGS_CPUSHIFT; op->u.getdomaininfo.flags |= diff --git a/xen/common/domain.c b/xen/common/domain.c index 253a6b102b..7ab17768c6 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -66,12 +66,12 @@ struct domain *do_createdomain(domid_t dom_id, unsigned int cpu) { write_lock(&domlist_lock); pd = &domain_list; /* NB. domain_list maintained in order of dom_id. */ - for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_list ) + for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) if ( (*pd)->id > d->id ) break; - d->next_list = *pd; + d->next_in_list = *pd; *pd = d; - d->next_hash = domain_hash[DOMAIN_HASH(dom_id)]; + d->next_in_hashbucket = domain_hash[DOMAIN_HASH(dom_id)]; domain_hash[DOMAIN_HASH(dom_id)] = d; write_unlock(&domlist_lock); } @@ -94,7 +94,7 @@ struct domain *find_domain_by_id(domid_t dom) d = NULL; break; } - d = d->next_hash; + d = d->next_in_hashbucket; } read_unlock(&domlist_lock); @@ -107,7 +107,7 @@ void domain_kill(struct domain *d) struct exec_domain *ed; domain_pause(d); - if ( !test_and_set_bit(DF_DYING, &d->d_flags) ) + if ( !test_and_set_bit(DF_DYING, &d->flags) ) { for_each_exec_domain(d, ed) sched_rem_domain(ed); @@ -124,7 +124,7 @@ void domain_crash(void) if ( d->id == 0 ) BUG(); - set_bit(DF_CRASHED, &d->d_flags); + set_bit(DF_CRASHED, &d->flags); send_guest_virq(dom0->exec_domain[0], VIRQ_DOM_EXC); @@ -164,9 +164,9 @@ void domain_shutdown(u8 reason) } if ( (d->shutdown_code = reason) == SHUTDOWN_crash ) - set_bit(DF_CRASHED, &d->d_flags); + set_bit(DF_CRASHED, &d->flags); else - set_bit(DF_SHUTDOWN, &d->d_flags); + set_bit(DF_SHUTDOWN, &d->flags); send_guest_virq(dom0->exec_domain[0], VIRQ_DOM_EXC); @@ -180,7 +180,7 @@ void domain_destruct(struct domain *d) struct domain **pd; atomic_t old, new; - if ( !test_bit(DF_DYING, &d->d_flags) ) + if ( !test_bit(DF_DYING, &d->flags) ) BUG(); /* May be already destructed, or get_domain() can race us. */ @@ -194,12 +194,12 @@ void domain_destruct(struct domain *d) write_lock(&domlist_lock); pd = &domain_list; while ( *pd != d ) - pd = &(*pd)->next_list; - *pd = d->next_list; + pd = &(*pd)->next_in_list; + *pd = d->next_in_list; pd = &domain_hash[DOMAIN_HASH(d->id)]; while ( *pd != d ) - pd = &(*pd)->next_hash; - *pd = d->next_hash; + pd = &(*pd)->next_in_hashbucket; + *pd = d->next_in_hashbucket; write_unlock(&domlist_lock); destroy_event_channels(d); @@ -227,8 +227,8 @@ int set_info_guest(struct domain *p, dom0_setdomaininfo_t *setdomaininfo) if ( (vcpu >= MAX_VIRT_CPUS) || ((ed = p->exec_domain[vcpu]) == NULL) ) return -EINVAL; - if (test_bit(DF_CONSTRUCTED, &p->d_flags) && - !test_bit(EDF_CTRLPAUSE, &ed->ed_flags)) + if (test_bit(DF_CONSTRUCTED, &p->flags) && + !test_bit(EDF_CTRLPAUSE, &ed->flags)) return -EINVAL; if ( (c = xmalloc(struct vcpu_guest_context)) == NULL ) @@ -243,7 +243,7 @@ int set_info_guest(struct domain *p, dom0_setdomaininfo_t *setdomaininfo) if ( (rc = arch_set_info_guest(ed, c)) != 0 ) goto out; - set_bit(DF_CONSTRUCTED, &p->d_flags); + set_bit(DF_CONSTRUCTED, &p->flags); out: xfree(c); @@ -294,7 +294,7 @@ long do_boot_vcpu(unsigned long vcpu, struct vcpu_guest_context *ctxt) sched_add_domain(ed); /* domain_unpause_by_systemcontroller */ - if ( test_and_clear_bit(EDF_CTRLPAUSE, &ed->ed_flags) ) + if ( test_and_clear_bit(EDF_CTRLPAUSE, &ed->flags) ) domain_wake(ed); xfree(c); diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index b1ed16ac37..22b01ad541 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -40,7 +40,7 @@ static int get_free_port(struct exec_domain *ed) max = d->max_event_channel; chn = d->event_channel; - for ( port = ed->eid * EVENT_CHANNELS_SPREAD; port < max; port++ ) + for ( port = ed->id * EVENT_CHANNELS_SPREAD; port < max; port++ ) if ( chn[port].state == ECS_FREE ) break; diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c index ca43f2f3c3..3449143458 100644 --- a/xen/common/keyhandler.c +++ b/xen/common/keyhandler.c @@ -109,7 +109,7 @@ static void do_task_queues(unsigned char key) for_each_domain ( d ) { printk("Xen: DOM %u, flags=%lx refcnt=%d nr_pages=%d " - "xenheap_pages=%d\n", d->id, d->d_flags, + "xenheap_pages=%d\n", d->id, d->flags, atomic_read(&d->refcnt), d->tot_pages, d->xenheap_pages); dump_pageframe_info(d); @@ -118,11 +118,11 @@ static void do_task_queues(unsigned char key) printk("Guest: %p CPU %d [has=%c] flags=%lx " "upcall_pend = %02x, upcall_mask = %02x\n", ed, ed->processor, - test_bit(EDF_RUNNING, &ed->ed_flags) ? 'T':'F', - ed->ed_flags, + test_bit(EDF_RUNNING, &ed->flags) ? 'T':'F', + ed->flags, ed->vcpu_info->evtchn_upcall_pending, ed->vcpu_info->evtchn_upcall_mask); - printk("Notifying guest... %d/%d\n", d->id, ed->eid); + printk("Notifying guest... %d/%d\n", d->id, ed->id); printk("port %d/%d stat %d %d %d\n", VIRQ_DEBUG, ed->virq_to_evtchn[VIRQ_DEBUG], test_bit(ed->virq_to_evtchn[VIRQ_DEBUG], diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c index 5573ced957..fb26edc69c 100644 --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -503,13 +503,13 @@ struct pfn_info *alloc_domheap_pages(struct domain *d, unsigned int order) spin_lock(&d->page_alloc_lock); - if ( unlikely(test_bit(DF_DYING, &d->d_flags)) || + if ( unlikely(test_bit(DF_DYING, &d->flags)) || unlikely((d->tot_pages + (1 << order)) > d->max_pages) ) { DPRINTK("Over-allocation for domain %u: %u > %u\n", d->id, d->tot_pages + (1 << order), d->max_pages); DPRINTK("...or the domain is dying (%d)\n", - !!test_bit(DF_DYING, &d->d_flags)); + !!test_bit(DF_DYING, &d->flags)); spin_unlock(&d->page_alloc_lock); free_heap_pages(MEMZONE_DOM, pg, order); return NULL; @@ -574,7 +574,7 @@ void free_domheap_pages(struct pfn_info *pg, unsigned int order) spin_unlock_recursive(&d->page_alloc_lock); - if ( likely(!test_bit(DF_DYING, &d->d_flags)) ) + if ( likely(!test_bit(DF_DYING, &d->flags)) ) { free_heap_pages(MEMZONE_DOM, pg, order); } diff --git a/xen/common/sched_bvt.c b/xen/common/sched_bvt.c index 65fa6125bf..276479e490 100644 --- a/xen/common/sched_bvt.c +++ b/xen/common/sched_bvt.c @@ -59,7 +59,7 @@ struct bvt_cpu_info }; #define BVT_INFO(p) ((struct bvt_dom_info *)(p)->sched_priv) -#define EBVT_INFO(p) ((struct bvt_edom_info *)(p)->ed_sched_priv) +#define EBVT_INFO(p) ((struct bvt_edom_info *)(p)->sched_priv) #define CPU_INFO(cpu) ((struct bvt_cpu_info *)(schedule_data[cpu]).sched_priv) #define RUNLIST(p) ((struct list_head *)&(EBVT_INFO(p)->run_list)) #define RUNQUEUE(cpu) ((struct list_head *)&(CPU_INFO(cpu)->runqueue)) @@ -174,9 +174,9 @@ static int bvt_alloc_task(struct exec_domain *ed) return -1; memset(d->sched_priv, 0, sizeof(struct bvt_dom_info)); } - ed->ed_sched_priv = &BVT_INFO(d)->ed_inf[ed->eid]; - BVT_INFO(d)->ed_inf[ed->eid].inf = BVT_INFO(d); - BVT_INFO(d)->ed_inf[ed->eid].exec_domain = ed; + ed->sched_priv = &BVT_INFO(d)->ed_inf[ed->id]; + BVT_INFO(d)->ed_inf[ed->id].inf = BVT_INFO(d); + BVT_INFO(d)->ed_inf[ed->id].exec_domain = ed; return 0; } @@ -190,7 +190,7 @@ static void bvt_add_task(struct exec_domain *d) ASSERT(inf != NULL); ASSERT(d != NULL); - if (d->eid == 0) { + if (d->id == 0) { inf->mcu_advance = MCU_ADVANCE; inf->domain = d->domain; inf->warpback = 0; @@ -224,43 +224,43 @@ static void bvt_add_task(struct exec_domain *d) } } -static int bvt_init_idle_task(struct exec_domain *p) +static int bvt_init_idle_task(struct exec_domain *ed) { - if ( bvt_alloc_task(p) < 0 ) + if ( bvt_alloc_task(ed) < 0 ) return -1; - bvt_add_task(p); + bvt_add_task(ed); + + set_bit(EDF_RUNNING, &ed->flags); + if ( !__task_on_runqueue(ed) ) + __add_to_runqueue_head(ed); - set_bit(EDF_RUNNING, &p->ed_flags); - if ( !__task_on_runqueue(p) ) - __add_to_runqueue_head(p); - return 0; } -static void bvt_wake(struct exec_domain *d) +static void bvt_wake(struct exec_domain *ed) { - struct bvt_edom_info *einf = EBVT_INFO(d); + struct bvt_edom_info *einf = EBVT_INFO(ed); struct exec_domain *curr; s_time_t now, r_time; - int cpu = d->processor; + int cpu = ed->processor; u32 curr_evt; - if ( unlikely(__task_on_runqueue(d)) ) + if ( unlikely(__task_on_runqueue(ed)) ) return; - __add_to_runqueue_head(d); + __add_to_runqueue_head(ed); now = NOW(); /* Set the BVT parameters. AVT should always be updated if CPU migration ocurred.*/ if ( einf->avt < CPU_SVT(cpu) || - unlikely(test_bit(EDF_MIGRATED, &d->ed_flags)) ) + unlikely(test_bit(EDF_MIGRATED, &ed->flags)) ) einf->avt = CPU_SVT(cpu); /* Deal with warping here. */ - einf->evt = calc_evt(d, einf->avt); + einf->evt = calc_evt(ed, einf->avt); curr = schedule_data[cpu].curr; curr_evt = calc_evt(curr, calc_avt(curr, now)); @@ -277,12 +277,12 @@ static void bvt_wake(struct exec_domain *d) } -static void bvt_sleep(struct exec_domain *d) +static void bvt_sleep(struct exec_domain *ed) { - if ( test_bit(EDF_RUNNING, &d->ed_flags) ) - cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ); - else if ( __task_on_runqueue(d) ) - __del_from_runqueue(d); + if ( test_bit(EDF_RUNNING, &ed->flags) ) + cpu_raise_softirq(ed->processor, SCHEDULE_SOFTIRQ); + else if ( __task_on_runqueue(ed) ) + __del_from_runqueue(ed); } /** @@ -377,7 +377,7 @@ static struct task_slice bvt_do_schedule(s_time_t now) struct bvt_edom_info *next_prime_einf = NULL; struct task_slice ret; - ASSERT(prev->ed_sched_priv != NULL); + ASSERT(prev->sched_priv != NULL); ASSERT(prev_einf != NULL); ASSERT(__task_on_runqueue(prev)); @@ -526,8 +526,8 @@ static void bvt_dump_cpu_state(int i) { struct list_head *queue; int loop = 0; - struct bvt_edom_info *d_inf; - struct exec_domain *d; + struct bvt_edom_info *ed_inf; + struct exec_domain *ed; printk("svt=0x%08lX ", CPU_SVT(i)); @@ -535,15 +535,15 @@ static void bvt_dump_cpu_state(int i) printk("QUEUE 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 ) + list_for_each_entry ( ed_inf, queue, run_list ) { - d = d_inf->exec_domain; - printk("%3d: %u has=%c ", loop++, d->domain->id, - test_bit(EDF_RUNNING, &d->ed_flags) ? 'T':'F'); - bvt_dump_runq_el(d); - printk("c=0x%X%08X\n", (u32)(d->cpu_time>>32), (u32)d->cpu_time); + ed = ed_inf->exec_domain; + printk("%3d: %u has=%c ", loop++, ed->domain->id, + test_bit(EDF_RUNNING, &ed->flags) ? 'T':'F'); + bvt_dump_runq_el(ed); + printk("c=0x%X%08X\n", (u32)(ed->cpu_time>>32), (u32)ed->cpu_time); printk(" l: %p n: %p p: %p\n", - &d_inf->run_list, d_inf->run_list.next, d_inf->run_list.prev); + &ed_inf->run_list, ed_inf->run_list.next, ed_inf->run_list.prev); } } diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 4123231dd1..b08e09094c 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -93,24 +93,27 @@ struct exec_domain *alloc_exec_domain_struct(struct domain *d, d->exec_domain[vcpu] = ed; ed->domain = d; - ed->eid = vcpu; + ed->id = vcpu; if ( SCHED_OP(alloc_task, ed) < 0 ) goto out; - if (vcpu != 0) { - ed->vcpu_info = &d->shared_info->vcpu_data[ed->eid]; + if ( vcpu != 0 ) + { + ed->vcpu_info = &d->shared_info->vcpu_data[ed->id]; - for_each_exec_domain(d, edc) { - if (edc->ed_next_list == NULL || edc->ed_next_list->eid > vcpu) + for_each_exec_domain( d, edc ) + { + if ( (edc->next_in_list == NULL) || + (edc->next_in_list->id > vcpu) ) break; } - ed->ed_next_list = edc->ed_next_list; - edc->ed_next_list = ed; + ed->next_in_list = edc->next_in_list; + edc->next_in_list = ed; - if (test_bit(EDF_CPUPINNED, &edc->ed_flags)) { + if (test_bit(EDF_CPUPINNED, &edc->flags)) { ed->processor = (edc->processor + 1) % smp_num_cpus; - set_bit(EDF_CPUPINNED, &ed->ed_flags); + set_bit(EDF_CPUPINNED, &ed->flags); } else { ed->processor = (edc->processor + 1) % smp_num_cpus; /* XXX */ } @@ -152,7 +155,7 @@ void sched_add_domain(struct exec_domain *ed) struct domain *d = ed->domain; /* Must be unpaused by control software to start execution. */ - set_bit(EDF_CTRLPAUSE, &ed->ed_flags); + set_bit(EDF_CTRLPAUSE, &ed->flags); if ( d->id != IDLE_DOMAIN_ID ) { @@ -168,14 +171,14 @@ void sched_add_domain(struct exec_domain *ed) } SCHED_OP(add_task, ed); - TRACE_2D(TRC_SCHED_DOM_ADD, d->id, ed->eid); + TRACE_2D(TRC_SCHED_DOM_ADD, d->id, ed->id); } void sched_rem_domain(struct exec_domain *ed) { rem_ac_timer(&ed->timer); SCHED_OP(rem_task, ed); - TRACE_2D(TRC_SCHED_DOM_REM, ed->domain->id, ed->eid); + TRACE_2D(TRC_SCHED_DOM_REM, ed->domain->id, ed->id); } void init_idle_task(void) @@ -193,10 +196,10 @@ void domain_sleep(struct exec_domain *ed) SCHED_OP(sleep, ed); spin_unlock_irqrestore(&schedule_data[ed->processor].schedule_lock, flags); - TRACE_2D(TRC_SCHED_SLEEP, ed->domain->id, ed->eid); + TRACE_2D(TRC_SCHED_SLEEP, ed->domain->id, ed->id); /* Synchronous. */ - while ( test_bit(EDF_RUNNING, &ed->ed_flags) && !domain_runnable(ed) ) + while ( test_bit(EDF_RUNNING, &ed->flags) && !domain_runnable(ed) ) cpu_relax(); } @@ -212,10 +215,10 @@ void domain_wake(struct exec_domain *ed) ed->wokenup = NOW(); #endif } - clear_bit(EDF_MIGRATED, &ed->ed_flags); + clear_bit(EDF_MIGRATED, &ed->flags); spin_unlock_irqrestore(&schedule_data[ed->processor].schedule_lock, flags); - TRACE_2D(TRC_SCHED_WAKE, ed->domain->id, ed->eid); + TRACE_2D(TRC_SCHED_WAKE, ed->domain->id, ed->id); } /* Block the currently-executing domain until a pertinent event occurs. */ @@ -224,16 +227,16 @@ long do_block(void) struct exec_domain *ed = current; ed->vcpu_info->evtchn_upcall_mask = 0; - set_bit(EDF_BLOCKED, &ed->ed_flags); + set_bit(EDF_BLOCKED, &ed->flags); /* Check for events /after/ blocking: avoids wakeup waiting race. */ if ( event_pending(ed) ) { - clear_bit(EDF_BLOCKED, &ed->ed_flags); + clear_bit(EDF_BLOCKED, &ed->flags); } else { - TRACE_2D(TRC_SCHED_BLOCK, ed->domain->id, ed->eid); + TRACE_2D(TRC_SCHED_BLOCK, ed->domain->id, ed->id); __enter_scheduler(); } @@ -243,7 +246,7 @@ long do_block(void) /* Voluntarily yield the processor for this allocation. */ static long do_yield(void) { - TRACE_2D(TRC_SCHED_YIELD, current->domain->id, current->eid); + TRACE_2D(TRC_SCHED_YIELD, current->domain->id, current->id); __enter_scheduler(); return 0; } @@ -272,7 +275,7 @@ long do_sched_op(unsigned long op) case SCHEDOP_shutdown: { - TRACE_3D(TRC_SCHED_SHUTDOWN, current->domain->id, current->eid, + TRACE_3D(TRC_SCHED_SHUTDOWN, current->domain->id, current->id, (op >> SCHEDOP_reasonshift)); domain_shutdown((u8)(op >> SCHEDOP_reasonshift)); break; @@ -379,7 +382,7 @@ static void __enter_scheduler(void) add_ac_timer(&schedule_data[cpu].s_timer); /* Must be protected by the schedule_lock! */ - set_bit(EDF_RUNNING, &next->ed_flags); + set_bit(EDF_RUNNING, &next->flags); spin_unlock_irq(&schedule_data[cpu].schedule_lock); @@ -417,8 +420,8 @@ static void __enter_scheduler(void) } TRACE_4D(TRC_SCHED_SWITCH, - prev->domain->id, prev->eid, - next->domain->id, next->eid); + prev->domain->id, prev->id, + next->domain->id, next->id); context_switch(prev, next); } diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h index fabe304155..7f44c5ae87 100644 --- a/xen/include/asm-x86/config.h +++ b/xen/include/asm-x86/config.h @@ -271,9 +271,9 @@ extern unsigned long _end; /* standard ELF symbol */ extern unsigned long xenheap_phys_end; /* user-configurable */ #endif -#define GDT_VIRT_START(ed) (PERDOMAIN_VIRT_START + ((ed)->eid << PDPT_VCPU_VA_SHIFT)) +#define GDT_VIRT_START(ed) (PERDOMAIN_VIRT_START + ((ed)->id << PDPT_VCPU_VA_SHIFT)) #define GDT_VIRT_END(ed) (GDT_VIRT_START(ed) + (64*1024)) -#define LDT_VIRT_START(ed) (PERDOMAIN_VIRT_START + (64*1024) + ((ed)->eid << PDPT_VCPU_VA_SHIFT)) +#define LDT_VIRT_START(ed) (PERDOMAIN_VIRT_START + (64*1024) + ((ed)->id << PDPT_VCPU_VA_SHIFT)) #define LDT_VIRT_END(ed) (LDT_VIRT_START(ed) + (64*1024)) #define PDPT_VCPU_SHIFT 5 diff --git a/xen/include/asm-x86/debugger.h b/xen/include/asm-x86/debugger.h index 0d6221a25e..6e9cf223d5 100644 --- a/xen/include/asm-x86/debugger.h +++ b/xen/include/asm-x86/debugger.h @@ -69,7 +69,7 @@ static inline int debugger_trap_entry( { case TRAP_int3: case TRAP_debug: - set_bit(EDF_CTRLPAUSE, &ed->ed_flags); + set_bit(EDF_CTRLPAUSE, &ed->flags); raise_softirq(SCHEDULE_SOFTIRQ); return 1; } diff --git a/xen/include/asm-x86/i387.h b/xen/include/asm-x86/i387.h index 9f6bb78b90..ca81778089 100644 --- a/xen/include/asm-x86/i387.h +++ b/xen/include/asm-x86/i387.h @@ -19,7 +19,7 @@ extern void save_init_fpu(struct exec_domain *tsk); extern void restore_fpu(struct exec_domain *tsk); #define unlazy_fpu(_tsk) do { \ - if ( test_bit(EDF_USEDFPU, &(_tsk)->ed_flags) ) \ + if ( test_bit(EDF_USEDFPU, &(_tsk)->flags) ) \ save_init_fpu(_tsk); \ } while ( 0 ) diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h index f0f3d61fd6..ac7ce6b1a0 100644 --- a/xen/include/xen/event.h +++ b/xen/include/xen/event.h @@ -43,7 +43,7 @@ static inline void evtchn_set_pending(struct exec_domain *ed, int port) * NB2. We save DF_RUNNING across the unblock to avoid a needless * IPI for domains that we IPI'd to unblock. */ - running = test_bit(EDF_RUNNING, &ed->ed_flags); + running = test_bit(EDF_RUNNING, &ed->flags); exec_domain_unblock(ed); if ( running ) smp_send_event_check_cpu(ed->processor); diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 266e34e8ec..6f64e0c057 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -60,13 +60,14 @@ int init_exec_domain_event_channels(struct exec_domain *ed); struct exec_domain { - u32 processor; + int id; - vcpu_info_t *vcpu_info; + int processor; - struct domain *domain; - struct exec_domain *ed_next_list; - int eid; + vcpu_info_t *vcpu_info; + + struct domain *domain; + struct exec_domain *next_in_list; struct ac_timer timer; /* one-shot timer for timeout values */ unsigned long sleep_tick; /* tick at which this vcpu started sleep */ @@ -75,13 +76,13 @@ struct exec_domain s_time_t lastdeschd; /* time this domain was last descheduled */ s_time_t cpu_time; /* total CPU time received till now */ s_time_t wokenup; /* time domain got woken up */ - void *ed_sched_priv; /* scheduler-specific data */ + void *sched_priv; /* scheduler-specific data */ - unsigned long ed_flags; + unsigned long flags; - u16 virq_to_evtchn[NR_VIRQS]; + u16 virq_to_evtchn[NR_VIRQS]; - atomic_t pausecnt; + atomic_t pausecnt; struct arch_exec_domain arch; }; @@ -111,14 +112,15 @@ struct domain int shutdown_code; /* code value from OS (if DF_SHUTDOWN). */ void *sched_priv; /* scheduler-specific data */ - struct domain *next_list, *next_hash; + struct domain *next_in_list; + struct domain *next_in_hashbucket; /* Event channel information. */ event_channel_t *event_channel; unsigned int max_event_channel; spinlock_t event_channel_lock; - grant_table_t *grant_table; + grant_table_t *grant_table; /* * Interrupt to event-channel mappings. Updates should be protected by the @@ -126,13 +128,13 @@ struct domain * the lock, but races don't usually matter. */ #define NR_PIRQS 128 /* Put this somewhere sane! */ - u16 pirq_to_evtchn[NR_PIRQS]; - u32 pirq_mask[NR_PIRQS/32]; + u16 pirq_to_evtchn[NR_PIRQS]; + u32 pirq_mask[NR_PIRQS/32]; - unsigned long d_flags; - unsigned long vm_assist; + unsigned long flags; + unsigned long vm_assist; - atomic_t refcnt; + atomic_t refcnt; struct exec_domain *exec_domain[MAX_VIRT_CPUS]; @@ -166,7 +168,7 @@ extern struct exec_domain idle0_exec_domain; extern struct exec_domain *idle_task[NR_CPUS]; #define IDLE_DOMAIN_ID (0x7FFFU) -#define is_idle_task(_p) (test_bit(DF_IDLETASK, &(_p)->d_flags)) +#define is_idle_task(_p) (test_bit(DF_IDLETASK, &(_p)->flags)) struct exec_domain *alloc_exec_domain_struct(struct domain *d, unsigned long vcpu); @@ -315,35 +317,36 @@ extern struct domain *domain_hash[DOMAIN_HASH_SIZE]; extern struct domain *domain_list; #define for_each_domain(_d) \ - for ( (_d) = domain_list; (_d) != NULL; (_d) = (_d)->next_list ) + for ( (_d) = domain_list; (_d) != NULL; (_d) = (_d)->next_in_list ) #define for_each_exec_domain(_d,_ed) \ for ( (_ed) = (_d)->exec_domain[0]; \ (_ed) != NULL; \ - (_ed) = (_ed)->ed_next_list ) + (_ed) = (_ed)->next_in_list ) #define EDF_DONEFPUINIT 0 /* Has the FPU been initialised for this task? */ #define EDF_USEDFPU 1 /* Has this task used the FPU since last save? */ #define EDF_GUEST_STTS 2 /* Has the guest OS requested 'stts'? */ -#define DF_CONSTRUCTED 3 /* Has the guest OS been fully built yet? */ -#define DF_IDLETASK 4 /* Is this one of the per-CPU idle domains? */ -#define DF_PRIVILEGED 5 /* Is this domain privileged? */ -#define DF_PHYSDEV 6 /* May this domain do IO to physical devices? */ -#define EDF_BLOCKED 7 /* Domain is blocked waiting for an event. */ -#define EDF_CTRLPAUSE 8 /* Domain is paused by controller software. */ -#define DF_SHUTDOWN 9 /* Guest shut itself down for some reason. */ -#define DF_CRASHED 10 /* Domain crashed inside Xen, cannot continue. */ -#define DF_DYING 11 /* Death rattle. */ -#define EDF_RUNNING 12 /* Currently running on a CPU. */ -#define EDF_CPUPINNED 13 /* Disables auto-migration. */ -#define EDF_MIGRATED 14 /* Domain migrated between CPUs. */ -#define EDF_DONEINIT 15 /* Initialization completed . */ +#define EDF_BLOCKED 3 /* Domain is blocked waiting for an event. */ +#define EDF_CTRLPAUSE 4 /* Domain is paused by controller software. */ +#define EDF_RUNNING 5 /* Currently running on a CPU. */ +#define EDF_CPUPINNED 6 /* Disables auto-migration. */ +#define EDF_MIGRATED 7 /* Domain migrated between CPUs. */ +#define EDF_DONEINIT 8 /* Initialization completed . */ -static inline int domain_runnable(struct exec_domain *d) +#define DF_CONSTRUCTED 0 /* Has the guest OS been fully built yet? */ +#define DF_IDLETASK 1 /* Is this one of the per-CPU idle domains? */ +#define DF_PRIVILEGED 2 /* Is this domain privileged? */ +#define DF_PHYSDEV 3 /* May this domain do IO to physical devices? */ +#define DF_SHUTDOWN 4 /* Guest shut itself down for some reason. */ +#define DF_CRASHED 5 /* Domain crashed inside Xen, cannot continue. */ +#define DF_DYING 6 /* Death rattle. */ + +static inline int domain_runnable(struct exec_domain *ed) { - return ( (atomic_read(&d->pausecnt) == 0) && - !(d->ed_flags & ((1<domain->d_flags & ((1<pausecnt) == 0) && + !(ed->flags & ((1<domain->flags & ((1<ed_flags) ) + if ( test_and_clear_bit(EDF_BLOCKED, &ed->flags) ) domain_wake(ed); } @@ -396,7 +399,7 @@ static inline void domain_pause_by_systemcontroller(struct domain *d) for_each_exec_domain ( d, ed ) { ASSERT(ed != current); - if ( !test_and_set_bit(EDF_CTRLPAUSE, &ed->ed_flags) ) + if ( !test_and_set_bit(EDF_CTRLPAUSE, &ed->flags) ) domain_sleep(ed); } @@ -409,14 +412,14 @@ static inline void domain_unpause_by_systemcontroller(struct domain *d) for_each_exec_domain ( d, ed ) { - if ( test_and_clear_bit(EDF_CTRLPAUSE, &ed->ed_flags) ) + if ( test_and_clear_bit(EDF_CTRLPAUSE, &ed->flags) ) domain_wake(ed); } } -#define IS_PRIV(_d) (test_bit(DF_PRIVILEGED, &(_d)->d_flags)) -#define IS_CAPABLE_PHYSDEV(_d) (test_bit(DF_PHYSDEV, &(_d)->d_flags)) +#define IS_PRIV(_d) (test_bit(DF_PRIVILEGED, &(_d)->flags)) +#define IS_CAPABLE_PHYSDEV(_d) (test_bit(DF_PHYSDEV, &(_d)->flags)) #define VM_ASSIST(_d,_t) (test_bit((_t), &(_d)->vm_assist)) From 33ea028eb0fde1c4c3d3846773617e2c948354ff Mon Sep 17 00:00:00 2001 From: "mafetter@fleming.research" Date: Mon, 9 May 2005 13:22:13 +0000 Subject: [PATCH 25/54] bitkeeper revision 1.1385.1.7 (427f6405sUeICnIzUJ_HaXbYnLds4A) Enabling light-weight shadows (especially shadow_mode_dirty). Light-weight shadows leave all the page ref counts based on the guest p.t. pages, while heavy-weight shadows do all their ref counts based on the shadow's p.t. pages. shadow_mode_refcounts(dom) == 1 implies heavy-weight shadows. --- xen/arch/x86/audit.c | 171 ++++--- xen/arch/x86/domain.c | 21 +- xen/arch/x86/domain_build.c | 4 +- xen/arch/x86/mm.c | 338 ++++++------- xen/arch/x86/shadow.c | 615 +++++++++++++++++------ xen/arch/x86/traps.c | 5 +- xen/arch/x86/vmx.c | 4 +- xen/include/asm-x86/mm.h | 27 +- xen/include/asm-x86/page.h | 2 + xen/include/asm-x86/shadow.h | 398 ++++++++++----- xen/include/asm-x86/x86_32/domain_page.h | 47 ++ xen/include/xen/lib.h | 2 +- xen/include/xen/perfc_defn.h | 6 +- 13 files changed, 1091 insertions(+), 549 deletions(-) diff --git a/xen/arch/x86/audit.c b/xen/arch/x86/audit.c index 2df4d69be8..b7e874c62d 100644 --- a/xen/arch/x86/audit.c +++ b/xen/arch/x86/audit.c @@ -49,7 +49,8 @@ static int l1, l2, oos_count, page_count; int audit_adjust_pgtables(struct domain *d, int dir, int noisy) { int errors = 0; - int shadow_enabled = shadow_mode_enabled(d) ? 1 : 0; + int shadow_refcounts = !!shadow_mode_refcounts(d); + int shadow_enabled = !!shadow_mode_enabled(d); int l2limit; void _adjust(struct pfn_info *page, int adjtype ADJUST_EXTRA_ARGS) @@ -119,7 +120,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) page->count_info += dir; } - void adjust_l2_page(unsigned long mfn) + void adjust_l2_page(unsigned long mfn, int shadow) { unsigned long *pt = map_domain_mem(mfn << PAGE_SHIFT); int i; @@ -133,7 +134,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) if ( noisy ) { - if ( shadow_enabled ) + if ( shadow ) { if ( page_get_owner(l1page) != NULL ) { @@ -145,6 +146,17 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) errors++; continue; } + + u32 page_type = l1page->u.inuse.type_info & PGT_type_mask; + + if ( page_type != PGT_l1_shadow ) + { + printk("Audit %d: [Shadow L2 mfn=%lx i=%x] " + "Expected Shadow L1 t=%x mfn=%lx\n", + d->id, mfn, i, + l1page->u.inuse.type_info, l1mfn); + errors++; + } } else { @@ -154,7 +166,9 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) "belonging to other dom %p (id=%d)\n", l1mfn, page_get_owner(l1page), - page_get_owner(l1page)->id); + (page_get_owner(l1page) + ? page_get_owner(l1page)->id + : -1)); errors++; continue; } @@ -179,7 +193,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) } } - adjust(l1page, !shadow_enabled); + adjust(l1page, !shadow); } } @@ -280,7 +294,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) errors++; } - if ( shadow_enabled && + if ( shadow_refcounts && page_is_page_table(gpage) && ! page_out_of_sync(gpage) ) { @@ -336,19 +350,21 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) break; case PGT_l1_shadow: adjust(pfn_to_page(gmfn), 0); - adjust_l1_page(smfn); + if ( shadow_refcounts ) + adjust_l1_page(smfn); if ( page->u.inuse.type_info & PGT_pinned ) adjust(page, 0); break; case PGT_hl2_shadow: adjust(pfn_to_page(gmfn), 0); - adjust_hl2_page(smfn); + if ( shadow_refcounts ) + adjust_hl2_page(smfn); if ( page->u.inuse.type_info & PGT_pinned ) adjust(page, 0); break; case PGT_l2_shadow: adjust(pfn_to_page(gmfn), 0); - adjust_l2_page(smfn); + adjust_l2_page(smfn, 1); if ( page->u.inuse.type_info & PGT_pinned ) adjust(page, 0); break; @@ -391,45 +407,43 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) struct exec_domain *ed; for_each_exec_domain(d, ed) - { - if ( !shadow_enabled ) - { - if ( pagetable_val(ed->arch.guest_table) ) - adjust(&frame_table[pagetable_val(ed->arch.guest_table) - >> PAGE_SHIFT], 1); - } - else - { - if ( pagetable_val(ed->arch.guest_table) ) - adjust(&frame_table[pagetable_val(ed->arch.guest_table) - >> PAGE_SHIFT], 0); - if ( pagetable_val(ed->arch.shadow_table) ) - adjust(&frame_table[pagetable_val(ed->arch.shadow_table) - >> PAGE_SHIFT], 0); - if ( ed->arch.monitor_shadow_ref ) - adjust(&frame_table[ed->arch.monitor_shadow_ref], 0); - } - } + { + if ( pagetable_val(ed->arch.guest_table) ) + adjust(&frame_table[pagetable_get_pfn(ed->arch.guest_table)], 1); + if ( pagetable_val(ed->arch.shadow_table) ) + adjust(&frame_table[pagetable_get_pfn(ed->arch.shadow_table)], 0); + if ( ed->arch.monitor_shadow_ref ) + adjust(&frame_table[ed->arch.monitor_shadow_ref], 0); + } } void adjust_guest_pages() { struct list_head *list_ent = d->page_list.next; struct pfn_info *page; - unsigned long mfn; + unsigned long mfn, snapshot_mfn; while ( list_ent != &d->page_list ) { u32 page_type; page = list_entry(list_ent, struct pfn_info, list); - mfn = page_to_pfn(page); + snapshot_mfn = mfn = page_to_pfn(page); page_type = page->u.inuse.type_info & PGT_type_mask; BUG_ON(page_get_owner(page) != d); page_count++; + if ( shadow_enabled && !shadow_refcounts && + page_out_of_sync(page) ) + { + unsigned long gpfn = __mfn_to_gpfn(d, mfn); + ASSERT( VALID_M2P(gpfn) ); + snapshot_mfn = __shadow_status(d, gpfn, PGT_snapshot); + ASSERT( snapshot_mfn ); + } + switch ( page_type ) { case PGT_l2_page_table: @@ -437,7 +451,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) if ( noisy ) { - if ( shadow_enabled ) + if ( shadow_refcounts ) { printk("Audit %d: found an L2 guest page " "mfn=%lx t=%08x c=%08x while in shadow mode\n", @@ -446,19 +460,22 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) errors++; } - if ( (page->u.inuse.type_info & PGT_validated) != - PGT_validated ) + if ( (page->u.inuse.type_info & PGT_count_mask) != 0 ) { - printk("Audit %d: L2 mfn=%lx not validated %08x\n", - d->id, mfn, page->u.inuse.type_info); - errors++; - } + if ( (page->u.inuse.type_info & PGT_validated) != + PGT_validated ) + { + printk("Audit %d: L2 mfn=%lx not validated %08x\n", + d->id, mfn, page->u.inuse.type_info); + errors++; + } - if ( (page->u.inuse.type_info & PGT_pinned) != PGT_pinned ) - { - printk("Audit %d: L2 mfn=%lx not pinned t=%08x\n", - d->id, mfn, page->u.inuse.type_info); - errors++; + if ( (page->u.inuse.type_info & PGT_pinned) != PGT_pinned ) + { + printk("Audit %d: L2 mfn=%lx not pinned t=%08x\n", + d->id, mfn, page->u.inuse.type_info); + errors++; + } } } @@ -466,7 +483,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) adjust(page, 1); if ( page->u.inuse.type_info & PGT_validated ) - adjust_l2_page(mfn); + adjust_l2_page(snapshot_mfn, 0); break; @@ -475,7 +492,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) if ( noisy ) { - if ( shadow_enabled ) + if ( shadow_refcounts ) { printk("found an L1 guest page mfn=%lx t=%08x c=%08x " "while in shadow mode\n", @@ -483,21 +500,24 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) errors++; } - if ( (page->u.inuse.type_info & PGT_validated) != PGT_validated ) + if ( (page->u.inuse.type_info & PGT_count_mask) != 0 ) { - printk("Audit %d: L1 not validated mfn=%lx t=%08x\n", - d->id, mfn, page->u.inuse.type_info); - errors++; - } - - if ( (page->u.inuse.type_info & PGT_pinned) != PGT_pinned ) - { - if ( !VM_ASSIST(d, VMASST_TYPE_writable_pagetables) ) + if ( (page->u.inuse.type_info & PGT_validated) != + PGT_validated ) { - printk("Audit %d: L1 mfn=%lx not pinned t=%08x\n", + printk("Audit %d: L1 not validated mfn=%lx t=%08x\n", d->id, mfn, page->u.inuse.type_info); errors++; } + + if ( (page->u.inuse.type_info & PGT_pinned) != PGT_pinned ) + { + if ( !VM_ASSIST(d, VMASST_TYPE_writable_pagetables) ) + { + printk("Audit %d: L1 mfn=%lx not pinned t=%08x\n", + d->id, mfn, page->u.inuse.type_info); + } + } } } @@ -505,7 +525,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) adjust(page, 1); if ( page->u.inuse.type_info & PGT_validated ) - adjust_l1_page(mfn); + adjust_l1_page(snapshot_mfn); break; @@ -520,7 +540,7 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy) break; case PGT_writable_page: - if ( shadow_enabled ) + if ( shadow_refcounts ) { // In shadow mode, writable pages can get pinned by // paravirtualized guests that think they are pinning @@ -589,6 +609,8 @@ void audit_pagelist(struct domain *d) void _audit_domain(struct domain *d, int flags) { + int shadow_refcounts = !!shadow_mode_refcounts(d); + void scan_for_pfn_in_mfn(struct domain *d, unsigned long xmfn, unsigned long mfn) { @@ -608,8 +630,29 @@ void _audit_domain(struct domain *d, int flags) unmap_domain_mem(pt); } + void scan_for_pfn_in_grant_table(struct domain *d, unsigned xmfn) + { + int i; + active_grant_entry_t *act = d->grant_table->active; + + spin_lock(&d->grant_table->lock); + + for ( i = 0; i < NR_GRANT_ENTRIES; i++ ) + { + if ( act[i].pin && (act[i].frame == xmfn) ) + { + printk(" found active grant table entry i=%d dom=%d pin=%d\n", + i, act[i].domid, act[i].pin); + } + } + + spin_unlock(&d->grant_table->lock); + } + void scan_for_pfn(struct domain *d, unsigned long xmfn) { + scan_for_pfn_in_grant_table(d, xmfn); + if ( !shadow_mode_enabled(d) ) { struct list_head *list_ent = d->page_list.next; @@ -688,7 +731,7 @@ void _audit_domain(struct domain *d, int flags) // Maybe we should just be using BIGLOCK? // - if ( !(flags & AUDIT_ALREADY_LOCKED) ) + if ( !(flags & AUDIT_SHADOW_ALREADY_LOCKED) ) shadow_lock(d); spin_lock(&d->page_alloc_lock); @@ -716,7 +759,7 @@ void _audit_domain(struct domain *d, int flags) errors++; } - if ( shadow_mode_enabled(d) && + if ( shadow_mode_refcounts(d) && (page_type == PGT_writable_page) && !(page->u.inuse.type_info & PGT_validated) ) { @@ -764,7 +807,9 @@ void _audit_domain(struct domain *d, int flags) mfn); errors++; } - if ( page_type != PGT_writable_page ) + if ( shadow_refcounts + ? (page_type != PGT_writable_page) + : !(page_type && (page_type <= PGT_l4_page_table)) ) { printk("out of sync page mfn=%lx has strange type " "t=%08x c=%08x\n", @@ -821,7 +866,7 @@ void _audit_domain(struct domain *d, int flags) d->id, page->u.inuse.type_info, page->tlbflush_timestamp, page->count_info, mfn); - errors++; + //errors++; } break; default: @@ -835,7 +880,7 @@ void _audit_domain(struct domain *d, int flags) page->count_info, page->u.inuse.type_info, page->tlbflush_timestamp, mfn ); - errors++; + //errors++; scan_for_pfn_remote(mfn); } @@ -870,6 +915,8 @@ void _audit_domain(struct domain *d, int flags) d->id, page_to_pfn(page), page->u.inuse.type_info, page->count_info); + printk("a->gpfn_and_flags=%p\n", + (void *)a->gpfn_and_flags); errors++; } break; @@ -905,7 +952,7 @@ void _audit_domain(struct domain *d, int flags) "pages=%d oos=%d l1=%d l2=%d ctot=%d ttot=%d\n", d->id, page_count, oos_count, l1, l2, ctot, ttot); - if ( !(flags & AUDIT_ALREADY_LOCKED) ) + if ( !(flags & AUDIT_SHADOW_ALREADY_LOCKED) ) shadow_unlock(d); if ( d != current->domain ) diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index a5029a45d5..2003ecc6ed 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -359,7 +359,8 @@ static int vmx_final_setup_guest(struct exec_domain *ed, /* Put the domain in shadow mode even though we're going to be using * the shared 1:1 page table initially. It shouldn't hurt */ - shadow_mode_enable(ed->domain, SHM_enable|SHM_translate|SHM_external); + shadow_mode_enable(ed->domain, + SHM_enable|SHM_refcounts|SHM_translate|SHM_external); } return 0; @@ -450,7 +451,7 @@ int arch_set_info_guest( phys_basetab = c->pt_base; ed->arch.guest_table = mk_pagetable(phys_basetab); - if ( shadow_mode_enabled(d) ) + if ( shadow_mode_refcounts(d) ) { if ( !get_page(&frame_table[phys_basetab>>PAGE_SHIFT], d) ) return -EINVAL; @@ -991,17 +992,21 @@ void domain_relinquish_resources(struct domain *d) { if ( pagetable_val(ed->arch.guest_table) != 0 ) { - (shadow_mode_enabled(d) ? put_page : put_page_and_type) - (&frame_table[pagetable_val( - ed->arch.guest_table) >> PAGE_SHIFT]); + if ( shadow_mode_refcounts(d) ) + put_page(&frame_table[pagetable_get_pfn(ed->arch.guest_table)]); + else + put_page_and_type(&frame_table[pagetable_get_pfn(ed->arch.guest_table)]); + ed->arch.guest_table = mk_pagetable(0); } if ( pagetable_val(ed->arch.guest_table_user) != 0 ) { - (shadow_mode_enabled(d) ? put_page : put_page_and_type) - (&frame_table[pagetable_val( - ed->arch.guest_table_user) >> PAGE_SHIFT]); + if ( shadow_mode_refcounts(d) ) + put_page(&frame_table[pagetable_get_pfn(ed->arch.guest_table_user)]); + else + put_page_and_type(&frame_table[pagetable_get_pfn(ed->arch.guest_table_user)]); + ed->arch.guest_table_user = mk_pagetable(0); } diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c index f1488d6f08..570fd1d33c 100644 --- a/xen/arch/x86/domain_build.c +++ b/xen/arch/x86/domain_build.c @@ -546,7 +546,7 @@ int construct_dom0(struct domain *d, if ( opt_dom0_shadow || opt_dom0_translate ) { shadow_mode_enable(d, (opt_dom0_translate - ? SHM_enable | SHM_translate + ? SHM_enable | SHM_refcounts | SHM_translate : SHM_enable)); if ( opt_dom0_translate ) { @@ -569,7 +569,7 @@ int construct_dom0(struct domain *d, idle_pg_table[1] = root_create_phys(pagetable_val(d->arch.phys_table), __PAGE_HYPERVISOR); translate_l2pgtable(d, (l1_pgentry_t *)(1u << L2_PAGETABLE_SHIFT), - pagetable_val(ed->arch.guest_table) >> PAGE_SHIFT); + pagetable_get_pfn(ed->arch.guest_table)); idle_pg_table[1] = root_empty(); local_flush_tlb(); } diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 050a4c0d33..107d2af585 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -316,7 +316,7 @@ int map_ldt_shadow_page(unsigned int off) res = get_page_and_type(&frame_table[gmfn], d, PGT_ldt_page); - if ( !res && unlikely(shadow_mode_enabled(d)) ) + if ( !res && unlikely(shadow_mode_refcounts(d)) ) { shadow_lock(d); shadow_remove_all_write_access(d, gpfn, gmfn); @@ -392,7 +392,7 @@ get_linear_pagetable( struct pfn_info *page; unsigned long pfn; - ASSERT( !shadow_mode_enabled(d) ); + ASSERT( !shadow_mode_refcounts(d) ); if ( (root_get_flags(re) & _PAGE_RW) ) { @@ -482,7 +482,7 @@ get_page_from_l2e( { int rc; - ASSERT(!shadow_mode_enabled(d)); + ASSERT(!shadow_mode_refcounts(d)); if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) ) return 1; @@ -512,6 +512,8 @@ static int get_page_from_l3e( l3_pgentry_t l3e, unsigned long pfn, struct domain *d) { + ASSERT( !shadow_mode_refcounts(d) ); + if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) ) return 1; @@ -533,6 +535,8 @@ get_page_from_l4e( { int rc; + ASSERT( !shadow_mode_refcounts(d) ); + if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) ) return 1; @@ -641,7 +645,7 @@ static int alloc_l1_table(struct pfn_info *page) l1_pgentry_t *pl1e; int i; - ASSERT(!shadow_mode_enabled(d)); + ASSERT(!shadow_mode_refcounts(d)); pl1e = map_domain_mem(pfn << PAGE_SHIFT); @@ -670,10 +674,12 @@ static int alloc_l2_table(struct pfn_info *page) l2_pgentry_t *pl2e; int i; + // See the code in shadow_promote() to understand why this is here... if ( (PGT_base_page_table == PGT_l2_page_table) && - shadow_mode_enabled(d) ) + unlikely(shadow_mode_refcounts(d)) ) return 1; - ASSERT( !shadow_mode_enabled(d) ); + + ASSERT( !shadow_mode_refcounts(d) ); pl2e = map_domain_mem(pfn << PAGE_SHIFT); @@ -716,7 +722,7 @@ static int alloc_l3_table(struct pfn_info *page) l3_pgentry_t *pl3e = page_to_virt(page); int i; - ASSERT( !shadow_mode_enabled(d) ); + ASSERT( !shadow_mode_refcounts(d) ); for ( i = 0; i < L3_PAGETABLE_ENTRIES; i++ ) if ( is_guest_l3_slot(i) && @@ -741,10 +747,12 @@ static int alloc_l4_table(struct pfn_info *page) l4_pgentry_t *pl4e = page_to_virt(page); int i; + // See the code in shadow_promote() to understand why this is here... if ( (PGT_base_page_table == PGT_l4_page_table) && - shadow_mode_enabled(d) ) + shadow_mode_refcounts(d) ) return 1; - ASSERT( !shadow_mode_enabled(d) ); + + ASSERT( !shadow_mode_refcounts(d) ); for ( i = 0; i < L4_PAGETABLE_ENTRIES; i++ ) if ( is_guest_l4_slot(i) && @@ -861,11 +869,12 @@ static int mod_l1_entry(l1_pgentry_t *pl1e, l1_pgentry_t nl1e) l1_pgentry_t ol1e; struct domain *d = current->domain; - ASSERT( !shadow_mode_enabled(d) ); - if ( unlikely(__copy_from_user(&ol1e, pl1e, sizeof(ol1e)) != 0) ) return 0; + if ( unlikely(shadow_mode_refcounts(d)) ) + return update_l1e(pl1e, ol1e, nl1e); + if ( l1e_get_flags(nl1e) & _PAGE_PRESENT ) { if ( unlikely(l1e_get_flags(nl1e) & L1_DISALLOW_MASK) ) @@ -893,7 +902,7 @@ static int mod_l1_entry(l1_pgentry_t *pl1e, l1_pgentry_t nl1e) if ( unlikely(!update_l1e(pl1e, ol1e, nl1e)) ) return 0; } - + put_page_from_l1e(ol1e, d); return 1; } @@ -1095,8 +1104,19 @@ int alloc_page_type(struct pfn_info *page, unsigned int type) void free_page_type(struct pfn_info *page, unsigned int type) { struct domain *owner = page_get_owner(page); - if ( likely(owner != NULL) && unlikely(shadow_mode_enabled(owner)) ) - return; + unsigned long gpfn; + + if ( owner != NULL ) + { + if ( unlikely(shadow_mode_refcounts(owner)) ) + return; + if ( unlikely(shadow_mode_enabled(owner)) ) + { + gpfn = __mfn_to_gpfn(owner, page_to_pfn(page)); + ASSERT(VALID_M2P(gpfn)); + remove_shadow(owner, gpfn, type); + } + } switch ( type ) { @@ -1287,7 +1307,7 @@ int new_guest_cr3(unsigned long mfn) int okay; unsigned long old_base_mfn; - if ( shadow_mode_enabled(d) ) + if ( shadow_mode_refcounts(d) ) okay = get_page_from_pagenr(mfn, d); else okay = get_page_and_type_from_pagenr(mfn, PGT_root_page_table, d); @@ -1296,24 +1316,24 @@ int new_guest_cr3(unsigned long mfn) { invalidate_shadow_ldt(ed); - old_base_mfn = pagetable_val(ed->arch.guest_table) >> PAGE_SHIFT; + old_base_mfn = pagetable_get_pfn(ed->arch.guest_table); ed->arch.guest_table = mk_pagetable(mfn << PAGE_SHIFT); update_pagetables(ed); /* update shadow_table and monitor_table */ write_ptbase(ed); - if ( shadow_mode_enabled(d) ) + if ( shadow_mode_refcounts(d) ) put_page(&frame_table[old_base_mfn]); else put_page_and_type(&frame_table[old_base_mfn]); - /* CR3 holds its own ref to its shadow. */ + /* CR3 also holds a ref to its shadow... */ if ( shadow_mode_enabled(d) ) { if ( ed->arch.monitor_shadow_ref ) put_shadow_ref(ed->arch.monitor_shadow_ref); ed->arch.monitor_shadow_ref = - pagetable_val(ed->arch.monitor_table) >> PAGE_SHIFT; + pagetable_get_pfn(ed->arch.monitor_table); ASSERT(!page_get_owner(&frame_table[ed->arch.monitor_shadow_ref])); get_shadow_ref(ed->arch.monitor_shadow_ref); } @@ -1486,7 +1506,7 @@ int do_mmuext_op( type = PGT_l1_page_table | PGT_va_mutable; pin_page: - if ( shadow_mode_enabled(FOREIGNDOM) ) + if ( shadow_mode_refcounts(FOREIGNDOM) ) type = PGT_writable_page; okay = get_page_and_type_from_pagenr(op.mfn, type, FOREIGNDOM); @@ -1557,7 +1577,7 @@ int do_mmuext_op( else { unsigned long old_mfn = - pagetable_val(ed->arch.guest_table_user) >> PAGE_SHIFT; + pagetable_get_pfn(ed->arch.guest_table_user); ed->arch.guest_table_user = mk_pagetable(op.mfn << PAGE_SHIFT); if ( old_mfn != 0 ) put_page_and_type(&frame_table[old_mfn]); @@ -1785,13 +1805,16 @@ int do_mmu_update( unsigned int foreigndom) { mmu_update_t req; - unsigned long va = 0, mfn, prev_mfn = 0, gpfn; + void *va; + unsigned long gpfn, mfn; struct pfn_info *page; int rc = 0, okay = 1, i = 0, cpu = smp_processor_id(); unsigned int cmd, done = 0; struct exec_domain *ed = current; struct domain *d = ed->domain; u32 type_info; + struct map_dom_mem_cache mapcache = MAP_DOM_MEM_CACHE_INIT; + struct map_dom_mem_cache sh_mapcache = MAP_DOM_MEM_CACHE_INIT; LOCK_BIGLOCK(d); @@ -1841,8 +1864,6 @@ int do_mmu_update( } cmd = req.ptr & (sizeof(l1_pgentry_t)-1); - mfn = req.ptr >> PAGE_SHIFT; - okay = 0; switch ( cmd ) @@ -1851,73 +1872,75 @@ int do_mmu_update( * MMU_NORMAL_PT_UPDATE: Normal update to any level of page table. */ case MMU_NORMAL_PT_UPDATE: + + gpfn = req.ptr >> PAGE_SHIFT; + mfn = __gpfn_to_mfn(d, gpfn); + if ( unlikely(!get_page_from_pagenr(mfn, current->domain)) ) { MEM_LOG("Could not get page for normal update"); break; } - if ( likely(prev_mfn == mfn) ) - { - va = (va & PAGE_MASK) | (req.ptr & ~PAGE_MASK); - } - else - { - if ( prev_mfn != 0 ) - unmap_domain_mem((void *)va); - va = (unsigned long)map_domain_mem(req.ptr); - prev_mfn = mfn; - } - + va = map_domain_mem_with_cache(req.ptr, &mapcache); page = &frame_table[mfn]; + switch ( (type_info = page->u.inuse.type_info) & PGT_type_mask ) { case PGT_l1_page_table: - ASSERT(!shadow_mode_enabled(d)); + ASSERT( !shadow_mode_refcounts(d) ); if ( likely(get_page_type( page, type_info & (PGT_type_mask|PGT_va_mask))) ) { - l1_pgentry_t pte; + l1_pgentry_t l1e; /* FIXME: doesn't work with PAE */ - pte = l1e_create_phys(req.val, req.val); - okay = mod_l1_entry((l1_pgentry_t *)va, pte); + l1e = l1e_create_phys(req.val, req.val); + okay = mod_l1_entry(va, l1e); + if ( okay && unlikely(shadow_mode_enabled(d)) ) + shadow_l1_normal_pt_update(d, req.ptr, l1e, &sh_mapcache); put_page_type(page); } break; case PGT_l2_page_table: - ASSERT(!shadow_mode_enabled(d)); + ASSERT( !shadow_mode_refcounts(d) ); if ( likely(get_page_type(page, PGT_l2_page_table)) ) { l2_pgentry_t l2e; /* FIXME: doesn't work with PAE */ l2e = l2e_create_phys(req.val, req.val); - okay = mod_l2_entry((l2_pgentry_t *)va, l2e, mfn); + okay = mod_l2_entry(va, l2e, mfn); + if ( okay && unlikely(shadow_mode_enabled(d)) ) + shadow_l2_normal_pt_update(d, req.ptr, l2e, &sh_mapcache); put_page_type(page); } break; #ifdef __x86_64__ case PGT_l3_page_table: - ASSERT(!shadow_mode_enabled(d)); + ASSERT( !shadow_mode_refcounts(d) ); if ( likely(get_page_type(page, PGT_l3_page_table)) ) { l3_pgentry_t l3e; /* FIXME: doesn't work with PAE */ l3e = l3e_create_phys(req.val,req.val); - okay = mod_l3_entry((l3_pgentry_t *)va, l3e, mfn); + okay = mod_l3_entry(va, l3e, mfn); + if ( okay && unlikely(shadow_mode_enabled(d)) ) + shadow_l3_normal_pt_update(d, req.ptr, l3e, &sh_mapcache); put_page_type(page); } break; case PGT_l4_page_table: - ASSERT(!shadow_mode_enabled(d)); + ASSERT( !shadow_mode_refcounts(d) ); if ( likely(get_page_type(page, PGT_l4_page_table)) ) { l4_pgentry_t l4e; l4e = l4e_create_phys(req.val,req.val); - okay = mod_l4_entry((l4_pgentry_t *)va, l4e, mfn); + okay = mod_l4_entry(va, l4e, mfn); + if ( okay && unlikely(shadow_mode_enabled(d)) ) + shadow_l4_normal_pt_update(d, req.ptr, l4e, &sh_mapcache); put_page_type(page); } break; @@ -1932,9 +1955,6 @@ int do_mmu_update( if ( shadow_mode_log_dirty(d) ) __mark_dirty(d, mfn); - gpfn = __mfn_to_gpfn(d, mfn); - ASSERT(VALID_M2P(gpfn)); - if ( page_is_page_table(page) && !page_out_of_sync(page) ) { @@ -1953,24 +1973,29 @@ int do_mmu_update( break; } + unmap_domain_mem_with_cache(va, &mapcache); + put_page(page); break; case MMU_MACHPHYS_UPDATE: + mfn = req.ptr >> PAGE_SHIFT; + gpfn = req.val; + /* HACK ALERT... Need to think about this some more... */ if ( unlikely(shadow_mode_translate(FOREIGNDOM) && IS_PRIV(d)) ) { - rc = FOREIGNDOM->next_io_page++; - printk("privileged guest dom%d requests mfn=%lx for dom%d, " - "gets pfn=%x\n", - d->id, mfn, FOREIGNDOM->id, rc); - set_machinetophys(mfn, rc); - set_p2m_entry(FOREIGNDOM, rc, mfn); + shadow_lock(FOREIGNDOM); + printk("privileged guest dom%d requests pfn=%lx to map mfn=%lx for dom%d\n", + d->id, gpfn, mfn, FOREIGNDOM->id); + set_machinetophys(mfn, gpfn); + set_p2m_entry(FOREIGNDOM, gpfn, mfn, NULL, NULL); okay = 1; + shadow_unlock(FOREIGNDOM); break; } - + if ( unlikely(!get_page_from_pagenr(mfn, FOREIGNDOM)) ) { MEM_LOG("Could not get page for mach->phys update"); @@ -1983,7 +2008,7 @@ int do_mmu_update( break; } - set_machinetophys(mfn, req.val); + set_machinetophys(mfn, gpfn); okay = 1; /* @@ -2012,8 +2037,8 @@ int do_mmu_update( } out: - if ( prev_mfn != 0 ) - unmap_domain_mem((void *)va); + unmap_domain_mem_cache(&mapcache); + unmap_domain_mem_cache(&sh_mapcache); process_deferred_ops(cpu); @@ -2031,73 +2056,6 @@ int do_mmu_update( /* This function assumes the caller is holding the domain's BIGLOCK * and is running in a shadow mode */ -int update_shadow_va_mapping(unsigned long va, - l1_pgentry_t val, - struct exec_domain *ed, - struct domain *d) -{ - unsigned long l1mfn; - l1_pgentry_t spte; - int rc = 0; - - check_pagetable(ed, "pre-va"); /* debug */ - shadow_lock(d); - - // This is actually overkill - we don't need to sync the L1 itself, - // just everything involved in getting to this L1 (i.e. we need - // linear_pg_table[l1_linear_offset(va)] to be in sync)... - // - __shadow_sync_va(ed, va); - -#if 1 /* keep check_pagetables() happy */ - /* - * However, the above doesn't guarantee that there's no snapshot of - * the L1 table in question; it just says that the relevant L2 and L1 - * entries for VA are in-sync. There might still be a snapshot. - * - * The checking code in _check_pagetables() assumes that no one will - * mutate the shadow of a page that has a snapshot. It's actually - * OK to not sync this page, but it seems simpler to: - * 1) keep all code paths the same, and - * 2) maintain the invariant for _check_pagetables(), rather than try - * to teach it about this boundary case. - * So we flush this L1 page, if it's out of sync. - */ - l1mfn = l2e_get_pfn(linear_l2_table(ed)[l2_table_offset(va)]); - if ( mfn_out_of_sync(l1mfn) ) - { - perfc_incrc(extra_va_update_sync); - __shadow_sync_mfn(d, l1mfn); - } -#endif /* keep check_pagetables() happy */ - - if ( unlikely(__copy_to_user(&linear_pg_table[l1_linear_offset(va)], - &val, sizeof(val)))) - { - rc = -EINVAL; - goto out; - } - - // also need to update the shadow - - l1pte_propagate_from_guest(d, val, &spte); - shadow_set_l1e(va, spte, 0); - - /* - * If we're in log-dirty mode then we need to note that we've updated - * the PTE in the PT-holding page. We need the machine frame number - * for this. - */ - if ( shadow_mode_log_dirty(d) ) - mark_dirty(d, va_to_l1mfn(ed, va)); - - out: - shadow_unlock(d); - check_pagetable(ed, "post-va"); /* debug */ - - return rc; -} - int update_grant_va_mapping(unsigned long va, l1_pgentry_t _nl1e, struct domain *d, @@ -2116,11 +2074,17 @@ int update_grant_va_mapping(unsigned long va, cleanup_writable_pagetable(d); + // This is actually overkill - we don't need to sync the L1 itself, + // just everything involved in getting to this L1 (i.e. we need + // linear_pg_table[l1_linear_offset(va)] to be in sync)... + // + __shadow_sync_va(ed, va); + pl1e = &linear_pg_table[l1_linear_offset(va)]; if ( unlikely(__copy_from_user(&ol1e, pl1e, sizeof(ol1e)) != 0) ) rc = -EINVAL; - else + else if ( !shadow_mode_refcounts(d) ) { if ( update_l1e(pl1e, ol1e, _nl1e) ) { @@ -2133,9 +2097,14 @@ int update_grant_va_mapping(unsigned long va, else rc = -EINVAL; } + else + { + printk("grant tables and shadow mode currently don't work together\n"); + BUG(); + } if ( unlikely(shadow_mode_enabled(d)) ) - update_shadow_va_mapping(va, _nl1e, ed, d); + shadow_do_update_va_mapping(va, _nl1e, ed); return rc; } @@ -2161,6 +2130,13 @@ int do_update_va_mapping(unsigned long va, cleanup_writable_pagetable(d); if ( unlikely(shadow_mode_enabled(d)) ) + check_pagetable(ed, "pre-va"); /* debug */ + + if ( unlikely(!mod_l1_entry(&linear_pg_table[l1_linear_offset(va)], + val)) ) + rc = -EINVAL; + + if ( likely(rc == 0) && unlikely(shadow_mode_enabled(d)) ) { if ( unlikely(percpu_info[cpu].foreign && (shadow_mode_translate(d) || @@ -2173,11 +2149,10 @@ int do_update_va_mapping(unsigned long va, domain_crash(); } - rc = update_shadow_va_mapping(va, val, ed, d); + rc = shadow_do_update_va_mapping(va, val, ed); + + check_pagetable(ed, "post-va"); /* debug */ } - else if ( unlikely(!mod_l1_entry(&linear_pg_table[l1_linear_offset(va)], - val)) ) - rc = -EINVAL; switch ( flags & UVMF_FLUSHTYPE_MASK ) { @@ -2468,14 +2443,68 @@ int ptwr_debug = 0x0; #define PTWR_PRINTK(_f, _a...) ((void)0) #endif +/* Re-validate a given p.t. page, given its prior snapshot */ +int revalidate_l1(struct domain *d, l1_pgentry_t *l1page, l1_pgentry_t *snapshot) +{ + l1_pgentry_t ol1e, nl1e; + int modified = 0, i; + +#if 0 + if ( d->id ) + printk("%s: l1page mfn=%lx snapshot mfn=%lx\n", __func__, + l1e_get_pfn(linear_pg_table[l1_linear_offset((unsigned long)l1page)]), + l1e_get_pfn(linear_pg_table[l1_linear_offset((unsigned long)snapshot)])); +#endif + + for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) + { + ol1e = snapshot[i]; + nl1e = l1page[i]; + + if ( likely(l1e_get_value(ol1e) == l1e_get_value(nl1e)) ) + continue; + + /* Update number of entries modified. */ + modified++; + + /* + * Fast path for PTEs that have merely been write-protected + * (e.g., during a Unix fork()). A strict reduction in privilege. + */ + if ( likely(l1e_get_value(ol1e) == (l1e_get_value(nl1e)|_PAGE_RW)) ) + { + if ( likely(l1e_get_flags(nl1e) & _PAGE_PRESENT) ) + put_page_type(&frame_table[l1e_get_pfn(nl1e)]); + continue; + } + + if ( unlikely(!get_page_from_l1e(nl1e, d)) ) + { + MEM_LOG("ptwr: Could not re-validate l1 page\n"); + /* + * Make the remaining p.t's consistent before crashing, so the + * reference counts are correct. + */ + memcpy(&l1page[i], &snapshot[i], + (L1_PAGETABLE_ENTRIES - i) * sizeof(l1_pgentry_t)); + domain_crash(); + break; + } + + put_page_from_l1e(ol1e, d); + } + + return modified; +} + + /* Flush the given writable p.t. page and write-protect it again. */ void ptwr_flush(struct domain *d, const int which) { unsigned long pte, *ptep, l1va; - l1_pgentry_t *pl1e, ol1e, nl1e; + l1_pgentry_t *pl1e; l2_pgentry_t *pl2e; - int i; - unsigned int modified = 0; + unsigned int modified; ASSERT(!shadow_mode_enabled(d)); @@ -2524,45 +2553,8 @@ void ptwr_flush(struct domain *d, const int which) */ pl1e = d->arch.ptwr[which].pl1e; - for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) - { - ol1e = d->arch.ptwr[which].page[i]; - nl1e = pl1e[i]; - - if ( likely(l1e_get_value(ol1e) == l1e_get_value(nl1e)) ) - continue; - - /* Update number of entries modified. */ - modified++; - - /* - * Fast path for PTEs that have merely been write-protected - * (e.g., during a Unix fork()). A strict reduction in privilege. - */ - if ( likely(l1e_get_value(ol1e) == (l1e_get_value(nl1e)|_PAGE_RW)) ) - { - if ( likely(l1e_get_flags(nl1e) & _PAGE_PRESENT) ) - put_page_type(&frame_table[l1e_get_pfn(nl1e)]); - continue; - } - - if ( unlikely(!get_page_from_l1e(nl1e, d)) ) - { - MEM_LOG("ptwr: Could not re-validate l1 page\n"); - /* - * Make the remaining p.t's consistent before crashing, so the - * reference counts are correct. - */ - memcpy(&pl1e[i], &d->arch.ptwr[which].page[i], - (L1_PAGETABLE_ENTRIES - i) * sizeof(l1_pgentry_t)); - domain_crash(); - break; - } - - put_page_from_l1e(ol1e, d); - } + modified = revalidate_l1(d, pl1e, d->arch.ptwr[which].page); unmap_domain_mem(pl1e); - perfc_incr_histo(wpt_updates, modified, PT_UPDATES); d->arch.ptwr[which].prev_nr_updates = modified; diff --git a/xen/arch/x86/shadow.c b/xen/arch/x86/shadow.c index 1db8ed71e9..817757c36a 100644 --- a/xen/arch/x86/shadow.c +++ b/xen/arch/x86/shadow.c @@ -30,11 +30,17 @@ #include #include +#define MFN_PINNED(_x) (frame_table[_x].u.inuse.type_info & PGT_pinned) + static void shadow_free_snapshot(struct domain *d, struct out_of_sync_entry *entry); static void remove_out_of_sync_entries(struct domain *d, unsigned long smfn); static void free_writable_pte_predictions(struct domain *d); +#if SHADOW_DEBUG +static void mark_shadows_as_reflecting_snapshot(struct domain *d, unsigned long gpfn); +#endif + /******** There's a per-domain shadow table spin lock which works fine for SMP @@ -62,6 +68,9 @@ shadow_promote(struct domain *d, unsigned long gpfn, unsigned long gmfn, __shadow_sync_mfn(d, gmfn); } + if ( !shadow_mode_refcounts(d) ) + return 1; + if ( unlikely(page_is_page_table(page)) ) return 1; @@ -89,7 +98,7 @@ shadow_promote(struct domain *d, unsigned long gpfn, unsigned long gmfn, // TLB flushes required when promoting a writable page, and also deal // with any outstanding (external) writable refs to this page (by // refusing to promote it). The pinning headache complicates this - // code -- it would all much get simpler if we stop using + // code -- it would all get much simpler if we stop using // shadow_lock() and move the shadow code to BIGLOCK(). // if ( unlikely(!get_page(page, d)) ) @@ -130,6 +139,9 @@ shadow_promote(struct domain *d, unsigned long gpfn, unsigned long gmfn, static inline void shadow_demote(struct domain *d, unsigned long gpfn, unsigned long gmfn) { + if ( !shadow_mode_refcounts(d) ) + return; + ASSERT(frame_table[gmfn].count_info & PGC_page_table); if ( shadow_max_pgtable_type(d, gpfn, NULL) == PGT_none ) @@ -210,7 +222,7 @@ alloc_shadow_page(struct domain *d, else { page = alloc_domheap_page(NULL); - void *l1 = map_domain_mem(page_to_pfn(page) << PAGE_SHIFT); + void *l1 = map_domain_mem(page_to_phys(page)); memset(l1, 0, PAGE_SIZE); unmap_domain_mem(l1); } @@ -312,7 +324,7 @@ free_shadow_l1_table(struct domain *d, unsigned long smfn) for ( i = min; i <= max; i++ ) { - put_page_from_l1e(pl1e[i], d); + shadow_put_page_from_l1e(pl1e[i], d); pl1e[i] = l1e_empty(); } @@ -348,21 +360,20 @@ free_shadow_hl2_table(struct domain *d, unsigned long smfn) static void inline free_shadow_l2_table(struct domain *d, unsigned long smfn) { - unsigned long *pl2e = map_domain_mem(smfn << PAGE_SHIFT); + l2_pgentry_t *pl2e = map_domain_mem(smfn << PAGE_SHIFT); int i, external = shadow_mode_external(d); for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ ) if ( external || is_guest_l2_slot(i) ) - if ( pl2e[i] & _PAGE_PRESENT ) - put_shadow_ref(pl2e[i] >> PAGE_SHIFT); + if ( l2e_get_flags(pl2e[i]) & _PAGE_PRESENT ) + put_shadow_ref(l2e_get_pfn(pl2e[i])); if ( (PGT_base_page_table == PGT_l2_page_table) && shadow_mode_translate(d) && !external ) { // free the ref to the hl2 // - put_shadow_ref(pl2e[l2_table_offset(LINEAR_PT_VIRT_START)] - >> PAGE_SHIFT); + put_shadow_ref(l2e_get_pfn(pl2e[l2_table_offset(LINEAR_PT_VIRT_START)])); } unmap_domain_mem(pl2e); @@ -428,6 +439,26 @@ void free_shadow_page(unsigned long smfn) free_domheap_page(page); } +void +remove_shadow(struct domain *d, unsigned long gpfn, u32 stype) +{ + unsigned long smfn; + + //printk("%s(gpfn=%lx, type=%x)\n", __func__, gpfn, stype); + + shadow_lock(d); + + while ( stype >= PGT_l1_shadow ) + { + smfn = __shadow_status(d, gpfn, stype); + if ( smfn && MFN_PINNED(smfn) ) + shadow_unpin(smfn); + stype -= PGT_l1_shadow; + } + + shadow_unlock(d); +} + static void inline release_out_of_sync_entry(struct domain *d, struct out_of_sync_entry *entry) { @@ -537,15 +568,22 @@ static void free_shadow_pages(struct domain *d) // free_out_of_sync_state(d); - // second, remove any outstanding refs from ed->arch.shadow_table... + // second, remove any outstanding refs from ed->arch.shadow_table + // and CR3. // for_each_exec_domain(d, ed) { if ( pagetable_val(ed->arch.shadow_table) ) { - put_shadow_ref(pagetable_val(ed->arch.shadow_table) >> PAGE_SHIFT); + put_shadow_ref(pagetable_get_pfn(ed->arch.shadow_table)); ed->arch.shadow_table = mk_pagetable(0); } + + if ( ed->arch.monitor_shadow_ref ) + { + put_shadow_ref(ed->arch.monitor_shadow_ref); + ed->arch.monitor_shadow_ref = 0; + } } // For external shadows, remove the monitor table's refs @@ -584,7 +622,6 @@ static void free_shadow_pages(struct domain *d) // under us... First, collect the list of pinned pages, then // free them. // -#define PINNED(_x) (frame_table[_x].u.inuse.type_info & PGT_pinned) for ( i = 0; i < shadow_ht_buckets; i++ ) { u32 count; @@ -596,7 +633,7 @@ static void free_shadow_pages(struct domain *d) count = 0; for ( x = &d->arch.shadow_ht[i]; x != NULL; x = x->next ) - if ( PINNED(x->smfn) ) + if ( MFN_PINNED(x->smfn) ) count++; if ( !count ) continue; @@ -604,7 +641,7 @@ static void free_shadow_pages(struct domain *d) mfn_list = xmalloc_array(unsigned long, count); count = 0; for ( x = &d->arch.shadow_ht[i]; x != NULL; x = x->next ) - if ( PINNED(x->smfn) ) + if ( MFN_PINNED(x->smfn) ) mfn_list[count++] = x->smfn; while ( count ) @@ -613,7 +650,18 @@ static void free_shadow_pages(struct domain *d) } xfree(mfn_list); } -#undef PINNED + + // Now free the pre-zero'ed pages from the domain + // + struct list_head *list_ent, *tmp; + list_for_each_safe(list_ent, tmp, &d->arch.free_shadow_frames) + { + list_del(list_ent); + perfc_decr(free_l1_pages); + + struct pfn_info *page = list_entry(list_ent, struct pfn_info, list); + free_domheap_page(page); + } shadow_audit(d, 0); @@ -624,9 +672,9 @@ void shadow_mode_init(void) { } -int _shadow_mode_enabled(struct domain *d) +int _shadow_mode_refcounts(struct domain *d) { - return shadow_mode_enabled(d); + return shadow_mode_refcounts(d); } static void alloc_monitor_pagetable(struct exec_domain *ed) @@ -706,7 +754,7 @@ void free_monitor_pagetable(struct exec_domain *ed) /* * Then free monitor_table. */ - mfn = (pagetable_val(ed->arch.monitor_table)) >> PAGE_SHIFT; + mfn = pagetable_get_pfn(ed->arch.monitor_table); free_domheap_page(&frame_table[mfn]); ed->arch.monitor_table = mk_pagetable(0); @@ -714,7 +762,9 @@ void free_monitor_pagetable(struct exec_domain *ed) } int -set_p2m_entry(struct domain *d, unsigned long pfn, unsigned long mfn) +set_p2m_entry(struct domain *d, unsigned long pfn, unsigned long mfn, + struct map_dom_mem_cache *l2cache, + struct map_dom_mem_cache *l1cache) { unsigned long phystab = pagetable_val(d->arch.phys_table); l2_pgentry_t *l2, l2e; @@ -724,26 +774,29 @@ set_p2m_entry(struct domain *d, unsigned long pfn, unsigned long mfn) ASSERT( phystab ); - l2 = map_domain_mem(phystab); + l2 = map_domain_mem_with_cache(phystab, l2cache); l2e = l2[l2_table_offset(va)]; - if ( !l2e_get_value(l2e) ) /* FIXME: check present bit? */ + if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) ) { l1page = alloc_domheap_page(NULL); if ( !l1page ) + { + unmap_domain_mem_with_cache(l2, l2cache); return 0; + } - l1 = map_domain_mem(page_to_pfn(l1page) << PAGE_SHIFT); + l1 = map_domain_mem_with_cache(page_to_phys(l1page), l1cache); memset(l1, 0, PAGE_SIZE); - unmap_domain_mem(l1); + unmap_domain_mem_with_cache(l1, l1cache); l2e = l2e_create_pfn(page_to_pfn(l1page), __PAGE_HYPERVISOR); l2[l2_table_offset(va)] = l2e; } - unmap_domain_mem(l2); + unmap_domain_mem_with_cache(l2, l2cache); - l1 = map_domain_mem(l2e_get_phys(l2e)); + l1 = map_domain_mem_with_cache(l2e_get_phys(l2e), l1cache); l1[l1_table_offset(va)] = l1e_create_pfn(mfn, __PAGE_HYPERVISOR); - unmap_domain_mem(l1); + unmap_domain_mem_with_cache(l1, l1cache); return 1; } @@ -755,14 +808,16 @@ alloc_p2m_table(struct domain *d) struct pfn_info *page, *l2page; l2_pgentry_t *l2; unsigned long mfn, pfn; + struct map_dom_mem_cache l2cache = MAP_DOM_MEM_CACHE_INIT; + struct map_dom_mem_cache l1cache = MAP_DOM_MEM_CACHE_INIT; l2page = alloc_domheap_page(NULL); if ( !l2page ) return 0; - d->arch.phys_table = mk_pagetable(page_to_pfn(l2page) << PAGE_SHIFT); - l2 = map_domain_mem(page_to_pfn(l2page) << PAGE_SHIFT); + d->arch.phys_table = mk_pagetable(page_to_phys(l2page)); + l2 = map_domain_mem_with_cache(page_to_phys(l2page), &l2cache); memset(l2, 0, PAGE_SIZE); - unmap_domain_mem(l2); + unmap_domain_mem_with_cache(l2, &l2cache); list_ent = d->page_list.next; while ( list_ent != &d->page_list ) @@ -773,7 +828,7 @@ alloc_p2m_table(struct domain *d) ASSERT(pfn != INVALID_M2P_ENTRY); ASSERT(pfn < (1u<<20)); - set_p2m_entry(d, pfn, mfn); + set_p2m_entry(d, pfn, mfn, &l2cache, &l1cache); list_ent = page->list.next; } @@ -787,12 +842,15 @@ alloc_p2m_table(struct domain *d) if ( (pfn != INVALID_M2P_ENTRY) && (pfn < (1u<<20)) ) { - set_p2m_entry(d, pfn, mfn); + set_p2m_entry(d, pfn, mfn, &l2cache, &l1cache); } list_ent = page->list.next; } + unmap_domain_mem_cache(&l2cache); + unmap_domain_mem_cache(&l1cache); + return 1; } @@ -915,13 +973,13 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode) { // external guests provide their own memory for their P2M maps. // - ASSERT( d == page_get_owner(&frame_table[pagetable_val( - d->arch.phys_table)>>PAGE_SHIFT]) ); + ASSERT( d == page_get_owner( + &frame_table[pagetable_get_pfn(d->arch.phys_table)]) ); } } printk("audit1\n"); - _audit_domain(d, AUDIT_ALREADY_LOCKED | AUDIT_ERRORS_OK); + _audit_domain(d, AUDIT_SHADOW_ALREADY_LOCKED | AUDIT_ERRORS_OK); printk("audit1 done\n"); // Get rid of any shadow pages from any previous shadow mode. @@ -929,15 +987,9 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode) free_shadow_pages(d); printk("audit2\n"); - _audit_domain(d, AUDIT_ALREADY_LOCKED | AUDIT_ERRORS_OK); + _audit_domain(d, AUDIT_SHADOW_ALREADY_LOCKED | AUDIT_ERRORS_OK); printk("audit2 done\n"); - // Turn off writable page tables. - // It doesn't mix with shadow mode. - // And shadow mode offers a superset of functionality. - // - vm_assist(d, VMASST_CMD_disable, VMASST_TYPE_writable_pagetables); - /* * Tear down it's counts by disassembling its page-table-based ref counts. * Also remove CR3's gcount/tcount. @@ -959,23 +1011,27 @@ int __shadow_mode_enable(struct domain *d, unsigned int mode) * Assert that no pages are left with L1/L2/L3/L4 type. */ audit_adjust_pgtables(d, -1, 1); + d->arch.shadow_mode = mode; - struct list_head *list_ent = d->page_list.next; - while ( list_ent != &d->page_list ) + if ( shadow_mode_refcounts(d) ) { - struct pfn_info *page = list_entry(list_ent, struct pfn_info, list); - if ( !get_page_type(page, PGT_writable_page) ) - BUG(); - put_page_type(page); + struct list_head *list_ent = d->page_list.next; + while ( list_ent != &d->page_list ) + { + struct pfn_info *page = list_entry(list_ent, struct pfn_info, list); + if ( !get_page_type(page, PGT_writable_page) ) + BUG(); + put_page_type(page); - list_ent = page->list.next; + list_ent = page->list.next; + } } audit_adjust_pgtables(d, 1, 1); printk("audit3\n"); - _audit_domain(d, AUDIT_ALREADY_LOCKED); + _audit_domain(d, AUDIT_SHADOW_ALREADY_LOCKED | AUDIT_ERRORS_OK); printk("audit3 done\n"); return 0; @@ -1120,8 +1176,8 @@ void __shadow_mode_disable(struct domain *d) * Currently this does not fix up page ref counts, so it is valid to call * only when a domain is being destroyed. */ - BUG_ON(!test_bit(DF_DYING, &d->d_flags)); - d->arch.shadow_tainted_refcnts = 1; + BUG_ON(!test_bit(DF_DYING, &d->d_flags) && shadow_mode_refcounts(d)); + d->arch.shadow_tainted_refcnts = shadow_mode_refcounts(d); free_shadow_pages(d); free_writable_pte_predictions(d); @@ -1138,11 +1194,17 @@ void __shadow_mode_disable(struct domain *d) } } #endif - + d->arch.shadow_mode = 0; free_shadow_ht_entries(d); free_out_of_sync_entries(d); + + struct exec_domain *ed; + for_each_exec_domain(d, ed) + { + update_pagetables(ed); + } } static int shadow_mode_table_op( @@ -1281,6 +1343,7 @@ int shadow_mode_control(struct domain *d, dom0_shadow_control_t *sc) switch ( op ) { case DOM0_SHADOW_CONTROL_OP_OFF: + __shadow_sync_all(d); __shadow_mode_disable(d); break; @@ -1298,7 +1361,7 @@ int shadow_mode_control(struct domain *d, dom0_shadow_control_t *sc) case DOM0_SHADOW_CONTROL_OP_ENABLE_TRANSLATE: free_shadow_pages(d); rc = __shadow_mode_enable( - d, d->arch.shadow_mode|SHM_enable|SHM_translate); + d, d->arch.shadow_mode|SHM_enable|SHM_refcounts|SHM_translate); break; default: @@ -1560,23 +1623,23 @@ void shadow_map_l1_into_current_l2(unsigned long va) if ( init_table ) { + l1_pgentry_t sl1e; + int index = l1_table_offset(va); + int min = 1, max = 0; + gpl1e = &(linear_pg_table[l1_linear_offset(va) & ~(L1_PAGETABLE_ENTRIES-1)]); spl1e = &(shadow_linear_pg_table[l1_linear_offset(va) & ~(L1_PAGETABLE_ENTRIES-1)]); - l1_pgentry_t sl1e; - int index = l1_table_offset(va); - int min = 1, max = 0; - for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) { l1pte_propagate_from_guest(d, gpl1e[i], &sl1e); if ( (l1e_get_flags(sl1e) & _PAGE_PRESENT) && - !shadow_get_page_from_l1e(sl1e, d) ) + unlikely(!shadow_get_page_from_l1e(sl1e, d)) ) sl1e = l1e_empty(); - if ( l1e_get_value(sl1e) == 0 ) /* FIXME: check flags? */ + if ( l1e_get_flags(sl1e) == 0 ) { // First copy entries from 0 until first invalid. // Then copy entries from index until first invalid. @@ -1695,7 +1758,8 @@ shadow_make_snapshot( if ( !get_shadow_ref(smfn) ) BUG(); - if ( shadow_max_pgtable_type(d, gpfn, &sl1mfn) == PGT_l1_shadow ) + if ( shadow_mode_refcounts(d) && + (shadow_max_pgtable_type(d, gpfn, &sl1mfn) == PGT_l1_shadow) ) min_max = pfn_to_page(sl1mfn)->tlbflush_timestamp; pfn_to_page(smfn)->tlbflush_timestamp = min_max; @@ -1748,7 +1812,18 @@ shadow_mark_mfn_out_of_sync(struct exec_domain *ed, unsigned long gpfn, ASSERT(spin_is_locked(&d->arch.shadow_lock)); ASSERT(pfn_valid(mfn)); - ASSERT((page->u.inuse.type_info & PGT_type_mask) == PGT_writable_page); + +#ifndef NDEBUG + u32 type = page->u.inuse.type_info & PGT_type_mask; + if ( shadow_mode_refcounts(d) ) + { + ASSERT(type == PGT_writable_page); + } + else + { + ASSERT(type && (type < PGT_l4_page_table)); + } +#endif FSH_LOG("%s(gpfn=%lx, mfn=%lx) c=%08x t=%08x", __func__, gpfn, mfn, page->count_info, page->u.inuse.type_info); @@ -1766,6 +1841,10 @@ shadow_mark_mfn_out_of_sync(struct exec_domain *ed, unsigned long gpfn, entry->snapshot_mfn = shadow_make_snapshot(d, gpfn, mfn); entry->writable_pl1e = -1; +#if SHADOW_DEBUG + mark_shadows_as_reflecting_snapshot(d, gpfn); +#endif + // increment guest's ref count to represent the entry in the // full shadow out-of-sync list. // @@ -1859,7 +1938,7 @@ static int snapshot_entry_matches( int __shadow_out_of_sync(struct exec_domain *ed, unsigned long va) { struct domain *d = ed->domain; - unsigned long l2mfn = pagetable_val(ed->arch.guest_table) >> PAGE_SHIFT; + unsigned long l2mfn = pagetable_get_pfn(ed->arch.guest_table); l2_pgentry_t l2e; unsigned long l1mfn; @@ -1867,6 +1946,10 @@ int __shadow_out_of_sync(struct exec_domain *ed, unsigned long va) perfc_incrc(shadow_out_of_sync_calls); + // PERF BUG: snapshot_entry_matches will call map_domain_mem() on the l2 + // page, but it's already available at ed->arch.guest_vtable... + // Ditto for the sl2 page and ed->arch.shadow_vtable. + // if ( page_out_of_sync(&frame_table[l2mfn]) && !snapshot_entry_matches(ed, l2mfn, l2_table_offset(va)) ) return 1; @@ -1881,6 +1964,10 @@ int __shadow_out_of_sync(struct exec_domain *ed, unsigned long va) if ( !VALID_MFN(l1mfn) ) return 0; + // PERF BUG: snapshot_entry_matches will call map_domain_mem() on the l1 + // page, but it's already available at linear_pg_table[l1_linear_offset()]. + // Ditto for the sl1 page and shadow_linear_pg_table[]... + // if ( page_out_of_sync(&frame_table[l1mfn]) && !snapshot_entry_matches(ed, l1mfn, l1_table_offset(va)) ) return 1; @@ -2002,7 +2089,7 @@ static u32 remove_all_write_access_in_ptpage( found++; pt[i] = new; if ( is_l1_shadow ) - put_page_from_l1e(old, d); + shadow_put_page_from_l1e(old, d); #if 0 printk("removed write access to pfn=%lx mfn=%lx in smfn=%lx entry %x " @@ -2060,8 +2147,7 @@ int shadow_remove_all_write_access( // write_refs = (frame_table[readonly_gmfn].u.inuse.type_info & PGT_count_mask); - if ( write_refs && - (frame_table[readonly_gmfn].u.inuse.type_info & PGT_pinned) ) + if ( write_refs && MFN_PINNED(readonly_gmfn) ) { write_refs--; } @@ -2141,7 +2227,7 @@ static u32 remove_all_access_in_page( count++; if ( is_l1_shadow ) - put_page_from_l1e(ol2e, d); + shadow_put_page_from_l1e(ol2e, d); else /* must be an hl2 page */ put_page(&frame_table[forbidden_gmfn]); } @@ -2210,8 +2296,23 @@ static int resync_all(struct domain *d, u32 stype) if ( entry->snapshot_mfn == SHADOW_SNAPSHOT_ELSEWHERE ) continue; - if ( !(smfn = __shadow_status(d, entry->gpfn, stype)) ) - continue; + smfn = __shadow_status(d, entry->gpfn, stype); + + if ( !smfn ) + { + if ( shadow_mode_refcounts(d) ) + continue; + + // For light weight shadows, even when no shadow page exists, + // we need to resync the refcounts to the new contents of the + // guest page. + // This only applies when we have writable page tables. + // + if ( (stype == PGT_l1_shadow) && !VM_ASSIST(d, VMASST_TYPE_writable_pagetables) ) + continue; + if ( (stype != PGT_l1_shadow) && !shadow_mode_write_all(d) ) + continue; + } FSH_LOG("resyncing t=%08x gpfn=%lx gmfn=%lx smfn=%lx snapshot_mfn=%lx", stype, entry->gpfn, entry->gmfn, smfn, entry->snapshot_mfn); @@ -2221,12 +2322,29 @@ static int resync_all(struct domain *d, u32 stype) // guest = map_domain_mem(entry->gmfn << PAGE_SHIFT); snapshot = map_domain_mem(entry->snapshot_mfn << PAGE_SHIFT); - shadow = map_domain_mem(smfn << PAGE_SHIFT); + + if ( smfn ) + shadow = map_domain_mem(smfn << PAGE_SHIFT); + else + shadow = NULL; + unshadow = 0; switch ( stype ) { case PGT_l1_shadow: { + l1_pgentry_t *guest1 = guest; + l1_pgentry_t *shadow1 = shadow; + l1_pgentry_t *snapshot1 = snapshot; + + ASSERT(VM_ASSIST(d, VMASST_TYPE_writable_pagetables)); + + if ( !shadow_mode_refcounts(d) ) + revalidate_l1(d, guest1, snapshot1); + + if ( !smfn ) + break; + u32 min_max_shadow = pfn_to_page(smfn)->tlbflush_timestamp; int min_shadow = SHADOW_MIN(min_max_shadow); int max_shadow = SHADOW_MAX(min_max_shadow); @@ -2236,10 +2354,6 @@ static int resync_all(struct domain *d, u32 stype) int min_snapshot = SHADOW_MIN(min_max_snapshot); int max_snapshot = SHADOW_MAX(min_max_snapshot); - l1_pgentry_t *guest1 = guest; - l1_pgentry_t *shadow1 = shadow; - l1_pgentry_t *snapshot1 = snapshot; - changed = 0; for ( i = min_shadow; i <= max_shadow; i++ ) @@ -2270,6 +2384,9 @@ static int resync_all(struct domain *d, u32 stype) l2_pgentry_t *shadow2 = shadow; l2_pgentry_t *snapshot2 = snapshot; + ASSERT(shadow_mode_write_all(d)); + BUG_ON(!shadow_mode_refcounts(d)); // not yet implemented + changed = 0; for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ ) { @@ -2295,8 +2412,7 @@ static int resync_all(struct domain *d, u32 stype) // Need a better solution long term. if ( !(l2e_get_flags(new_pde) & _PAGE_PRESENT) && unlikely(l2e_get_value(new_pde) != 0) && - !unshadow && - (frame_table[smfn].u.inuse.type_info & PGT_pinned) ) + !unshadow && MFN_PINNED(smfn) ) unshadow = 1; } if ( max == -1 ) @@ -2311,6 +2427,9 @@ static int resync_all(struct domain *d, u32 stype) l2_pgentry_t *snapshot2 = snapshot; l1_pgentry_t *shadow2 = shadow; + ASSERT(shadow_mode_write_all(d)); + BUG_ON(!shadow_mode_refcounts(d)); // not yet implemented + changed = 0; for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ ) { @@ -2338,7 +2457,8 @@ static int resync_all(struct domain *d, u32 stype) BUG(); } - unmap_domain_mem(shadow); + if ( smfn ) + unmap_domain_mem(shadow); unmap_domain_mem(snapshot); unmap_domain_mem(guest); @@ -2351,7 +2471,7 @@ static int resync_all(struct domain *d, u32 stype) unsigned long hl2mfn; if ( (hl2mfn = __shadow_status(d, entry->gpfn, PGT_hl2_shadow)) && - (frame_table[hl2mfn].u.inuse.type_info & PGT_pinned) ) + MFN_PINNED(hl2mfn) ) shadow_unpin(hl2mfn); } } @@ -2388,7 +2508,7 @@ void __shadow_sync_all(struct domain *d) !shadow_get_page_from_l1e(npte, d) ) BUG(); *ppte = npte; - put_page_from_l1e(opte, d); + shadow_put_page_from_l1e(opte, d); unmap_domain_mem(ppte); } @@ -2475,13 +2595,23 @@ int shadow_fault(unsigned long va, struct xen_regs *regs) /* Write fault? */ if ( regs->error_code & 2 ) { + int allow_writes = 0; + if ( unlikely(!(l1e_get_flags(gpte) & _PAGE_RW)) ) { - /* Write fault on a read-only mapping. */ - SH_VVLOG("shadow_fault - EXIT: wr fault on RO page (%lx)", - l1e_get_value(gpte)); - perfc_incrc(shadow_fault_bail_ro_mapping); - goto fail; + if ( shadow_mode_page_writable(d, l1e_get_pfn(gpte)) ) + { + allow_writes = 1; + l1e_add_flags(&gpte, _PAGE_RW); + } + else + { + /* Write fault on a read-only mapping. */ + SH_VVLOG("shadow_fault - EXIT: wr fault on RO page (%lx)", + l1e_get_value(gpte)); + perfc_incrc(shadow_fault_bail_ro_mapping); + goto fail; + } } if ( !l1pte_write_fault(ed, &gpte, &spte, va) ) @@ -2491,6 +2621,9 @@ int shadow_fault(unsigned long va, struct xen_regs *regs) shadow_unlock(d); return 0; } + + if ( allow_writes ) + l1e_remove_flags(&gpte, _PAGE_RW); } else { @@ -2506,21 +2639,22 @@ int shadow_fault(unsigned long va, struct xen_regs *regs) /* * STEP 3. Write the modified shadow PTE and guest PTE back to the tables. */ - - /* XXX Watch out for read-only L2 entries! (not used in Linux). */ - if ( unlikely(__copy_to_user(&linear_pg_table[l1_linear_offset(va)], - &gpte, sizeof(gpte))) ) + if ( l1e_has_changed(&orig_gpte, &gpte, PAGE_FLAG_MASK) ) { - printk("shadow_fault() failed, crashing domain %d " - "due to a read-only L2 page table (gpde=%lx), va=%lx\n", - d->id, l2e_get_value(gpde), va); - domain_crash_synchronous(); - } + /* XXX Watch out for read-only L2 entries! (not used in Linux). */ + if ( unlikely(__copy_to_user(&linear_pg_table[l1_linear_offset(va)], + &gpte, sizeof(gpte))) ) + { + printk("%s() failed, crashing domain %d " + "due to a read-only L2 page table (gpde=%lx), va=%lx\n", + __func__, d->id, l2e_get_value(gpde), va); + domain_crash_synchronous(); + } - // if necessary, record the page table page as dirty - if ( unlikely(shadow_mode_log_dirty(d)) && - l1e_has_changed(&orig_gpte, &gpte, PAGE_FLAG_MASK)) - mark_dirty(d, __gpfn_to_mfn(d, l2e_get_pfn(gpde))); + // if necessary, record the page table page as dirty + if ( unlikely(shadow_mode_log_dirty(d)) ) + __mark_dirty(d, __gpfn_to_mfn(d, l2e_get_pfn(gpde))); + } shadow_set_l1e(va, spte, 1); @@ -2537,6 +2671,109 @@ int shadow_fault(unsigned long va, struct xen_regs *regs) return 0; } +void shadow_l1_normal_pt_update( + struct domain *d, + unsigned long pa, l1_pgentry_t gpte, + struct map_dom_mem_cache *cache) +{ + unsigned long sl1mfn; + l1_pgentry_t *spl1e, spte; + + shadow_lock(d); + + sl1mfn = __shadow_status(current->domain, pa >> PAGE_SHIFT, PGT_l1_shadow); + if ( sl1mfn ) + { + SH_VVLOG("shadow_l1_normal_pt_update pa=%p, gpte=%08lx", + (void *)pa, l1e_get_value(gpte)); + l1pte_propagate_from_guest(current->domain, gpte, &spte); + + spl1e = map_domain_mem_with_cache(sl1mfn << PAGE_SHIFT, cache); + spl1e[(pa & ~PAGE_MASK) / sizeof(l1_pgentry_t)] = spte; + unmap_domain_mem_with_cache(spl1e, cache); + } + + shadow_unlock(d); +} + +void shadow_l2_normal_pt_update( + struct domain *d, + unsigned long pa, l2_pgentry_t gpde, + struct map_dom_mem_cache *cache) +{ + unsigned long sl2mfn; + l2_pgentry_t *spl2e; + + shadow_lock(d); + + sl2mfn = __shadow_status(current->domain, pa >> PAGE_SHIFT, PGT_l2_shadow); + if ( sl2mfn ) + { + SH_VVLOG("shadow_l2_normal_pt_update pa=%p, gpde=%08lx", + (void *)pa, l2e_get_value(gpde)); + spl2e = map_domain_mem_with_cache(sl2mfn << PAGE_SHIFT, cache); + validate_pde_change(d, gpde, + &spl2e[(pa & ~PAGE_MASK) / sizeof(l2_pgentry_t)]); + unmap_domain_mem_with_cache(spl2e, cache); + } + + shadow_unlock(d); +} + +#ifdef __x86_64__ +void shadow_l3_normal_pt_update( + struct domain *d, + unsigned long pa, l3_pgentry_t gpde, + struct map_dom_mem_cache *cache) +{ + BUG(); // not yet implemented +} + +void shadow_l4_normal_pt_update( + struct domain *d, + unsigned long pa, l4_pgentry_t gpde, + struct map_dom_mem_cache *cache) +{ + BUG(); // not yet implemented +} +#endif + +int shadow_do_update_va_mapping(unsigned long va, + l1_pgentry_t val, + struct exec_domain *ed) +{ + struct domain *d = ed->domain; + l1_pgentry_t spte; + int rc = 0; + + shadow_lock(d); + + //printk("%s(va=%p, val=%p)\n", __func__, (void *)va, (void *)l1e_get_value(val)); + + // This is actually overkill - we don't need to sync the L1 itself, + // just everything involved in getting to this L1 (i.e. we need + // linear_pg_table[l1_linear_offset(va)] to be in sync)... + // + __shadow_sync_va(ed, va); + + l1pte_propagate_from_guest(d, val, &spte); + shadow_set_l1e(va, spte, 0); + + /* + * If we're in log-dirty mode then we need to note that we've updated + * the PTE in the PT-holding page. We need the machine frame number + * for this. + */ + if ( shadow_mode_log_dirty(d) ) + __mark_dirty(d, va_to_l1mfn(ed, va)); + +// out: + shadow_unlock(d); + + return rc; +} + + /* * What lives where in the 32-bit address space in the various shadow modes, * and what it uses to get/maintain that mapping. @@ -2566,7 +2803,7 @@ int shadow_fault(unsigned long va, struct xen_regs *regs) void __update_pagetables(struct exec_domain *ed) { struct domain *d = ed->domain; - unsigned long gmfn = pagetable_val(ed->arch.guest_table) >> PAGE_SHIFT; + unsigned long gmfn = pagetable_get_pfn(ed->arch.guest_table); unsigned long gpfn = __mfn_to_gpfn(d, gmfn); unsigned long smfn, hl2mfn, old_smfn; @@ -2595,7 +2832,7 @@ void __update_pagetables(struct exec_domain *ed) smfn = shadow_l2_table(d, gpfn, gmfn); if ( !get_shadow_ref(smfn) ) BUG(); - old_smfn = pagetable_val(ed->arch.shadow_table) >> PAGE_SHIFT; + old_smfn = pagetable_get_pfn(ed->arch.shadow_table); ed->arch.shadow_table = mk_pagetable(smfn << PAGE_SHIFT); if ( old_smfn ) put_shadow_ref(old_smfn); @@ -2665,6 +2902,47 @@ void __update_pagetables(struct exec_domain *ed) #if SHADOW_DEBUG +// The following is entirely for _check_pagetable()'s benefit. +// _check_pagetable() wants to know whether a given entry in a +// shadow page table is supposed to be the shadow of the guest's +// current entry, or the shadow of the entry held in the snapshot +// taken above. +// +// Here, we mark all currently existing entries as reflecting +// the snapshot, above. All other places in xen that update +// the shadow will keep the shadow in sync with the guest's +// entries (via l1pte_propagate_from_guest and friends), which clear +// the SHADOW_REFLECTS_SNAPSHOT bit. +// +static void +mark_shadows_as_reflecting_snapshot(struct domain *d, unsigned long gpfn) +{ + unsigned long smfn; + l1_pgentry_t *l1e; + l2_pgentry_t *l2e; + unsigned i; + + if ( (smfn = __shadow_status(d, gpfn, PGT_l1_shadow)) ) + { + l1e = map_domain_mem(smfn << PAGE_SHIFT); + for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) + if ( is_guest_l1_slot(i) && + (l1e_get_flags(l1e[i]) & _PAGE_PRESENT) ) + l1e_add_flags(&l1e[i], SHADOW_REFLECTS_SNAPSHOT); + unmap_domain_mem(l1e); + } + + if ( (smfn = __shadow_status(d, gpfn, PGT_l2_shadow)) ) + { + l2e = map_domain_mem(smfn << PAGE_SHIFT); + for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ ) + if ( is_guest_l2_slot(i) && + (l2e_get_flags(l2e[i]) & _PAGE_PRESENT) ) + l2e_add_flags(&l2e[i], SHADOW_REFLECTS_SNAPSHOT); + unmap_domain_mem(l2e); + } +} + // BUG: these are not SMP safe... static int sh_l2_present; static int sh_l1_present; @@ -2687,96 +2965,109 @@ int shadow_status_noswap; #define FAIL(_f, _a...) \ do { \ - printk("XXX %s-FAIL (%d,%d,%d)" _f " at %s(%d)\n", \ + printk("XXX %s-FAIL (%d,%d,%d) " _f " at %s(%d)\n", \ sh_check_name, level, l2_idx, l1_idx, ## _a, \ __FILE__, __LINE__); \ - printk("g=%lx s=%lx &g=%p &s=%p" \ - " v2m(&g)=%08lx v2m(&s)=%08lx ea=%08x\n", \ - l1e_get_value(gpte), l1e_get_value(spte), pgpte, pspte, \ - v2m(ed, pgpte), v2m(ed, pspte), \ + printk("guest_pte=%lx eff_guest_pte=%lx shadow_pte=%lx " \ + "snapshot_pte=%lx &guest=%p &shadow=%p &snap=%p " \ + "v2m(&guest)=%p v2m(&shadow)=%p v2m(&snap)=%p ea=%08x\n", \ + l1e_get_value(guest_pte), l1e_get_value(eff_guest_pte), \ + l1e_get_value(shadow_pte), l1e_get_value(snapshot_pte), \ + p_guest_pte, p_shadow_pte, p_snapshot_pte, \ + (void *)v2m(ed, p_guest_pte), (void *)v2m(ed, p_shadow_pte), \ + (void *)v2m(ed, p_snapshot_pte), \ (l2_idx << L2_PAGETABLE_SHIFT) | \ (l1_idx << L1_PAGETABLE_SHIFT)); \ errors++; \ } while ( 0 ) static int check_pte( - struct exec_domain *ed, l1_pgentry_t *pgpte, l1_pgentry_t *pspte, - int level, int l2_idx, int l1_idx, int oos_ptes) + struct exec_domain *ed, + l1_pgentry_t *p_guest_pte, + l1_pgentry_t *p_shadow_pte, + l1_pgentry_t *p_snapshot_pte, + int level, int l2_idx, int l1_idx) { struct domain *d = ed->domain; - l1_pgentry_t gpte = *pgpte; - l1_pgentry_t spte = *pspte; - unsigned long mask, gpfn, smfn, gmfn; - int errors = 0; + l1_pgentry_t guest_pte = *p_guest_pte; + l1_pgentry_t shadow_pte = *p_shadow_pte; + l1_pgentry_t snapshot_pte = p_snapshot_pte ? *p_snapshot_pte : l1e_empty(); + l1_pgentry_t eff_guest_pte; + unsigned long mask, eff_guest_pfn, eff_guest_mfn, shadow_mfn; + int errors = 0, guest_writable; int page_table_page; - if ( (l1e_get_value(spte) == 0) || - (l1e_get_value(spte) == 0xdeadface) || - (l1e_get_value(spte) == 0x00000E00) ) + if ( (l1e_get_value(shadow_pte) == 0) || + (l1e_get_value(shadow_pte) == 0xdeadface) || + (l1e_get_value(shadow_pte) == 0x00000E00) ) return errors; /* always safe */ - if ( !(l1e_get_flags(spte) & _PAGE_PRESENT) ) - FAIL("Non zero not present spte"); + if ( !(l1e_get_flags(shadow_pte) & _PAGE_PRESENT) ) + FAIL("Non zero not present shadow_pte"); if ( level == 2 ) sh_l2_present++; if ( level == 1 ) sh_l1_present++; - if ( !(l1e_get_flags(gpte) & _PAGE_PRESENT) ) + if ( (l1e_get_flags(shadow_pte) & SHADOW_REFLECTS_SNAPSHOT) && p_snapshot_pte ) + eff_guest_pte = snapshot_pte; + else + eff_guest_pte = guest_pte; + + if ( !(l1e_get_flags(eff_guest_pte) & _PAGE_PRESENT) ) FAIL("Guest not present yet shadow is"); - mask = ~(_PAGE_GLOBAL|_PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_RW|PAGE_MASK); + mask = ~(_PAGE_GLOBAL|_PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_RW|_PAGE_AVAIL|PAGE_MASK); - if ( (l1e_get_value(spte) & mask) != (l1e_get_value(gpte) & mask) ) + if ( ((l1e_get_value(shadow_pte) & mask) != (l1e_get_value(eff_guest_pte) & mask)) ) FAIL("Corrupt?"); if ( (level == 1) && - (l1e_get_flags(spte) & _PAGE_DIRTY) && - !(l1e_get_flags(gpte) & _PAGE_DIRTY) && !oos_ptes ) + (l1e_get_flags(shadow_pte) & _PAGE_DIRTY) && + !(l1e_get_flags(eff_guest_pte) & _PAGE_DIRTY) ) FAIL("Dirty coherence"); - if ( (l1e_get_flags(spte) & _PAGE_ACCESSED) && - !(l1e_get_flags(gpte) & _PAGE_ACCESSED) && !oos_ptes ) + if ( (l1e_get_flags(shadow_pte) & _PAGE_ACCESSED) && + !(l1e_get_flags(eff_guest_pte) & _PAGE_ACCESSED) ) FAIL("Accessed coherence"); - if ( l1e_get_flags(spte) & _PAGE_GLOBAL ) + if ( l1e_get_flags(shadow_pte) & _PAGE_GLOBAL ) FAIL("global bit set in shadow"); - smfn = l1e_get_pfn(spte); - gpfn = l1e_get_pfn(gpte); - gmfn = __gpfn_to_mfn(d, gpfn); + eff_guest_pfn = l1e_get_pfn(eff_guest_pte); + eff_guest_mfn = __gpfn_to_mfn(d, eff_guest_pfn); + shadow_mfn = l1e_get_pfn(shadow_pte); - if ( !VALID_MFN(gmfn) ) - FAIL("%s: invalid gpfn=%lx gpte=%lx\n", __func__, gpfn, - l1e_get_value(gpte)); + if ( !VALID_MFN(eff_guest_mfn) && !shadow_mode_refcounts(d) ) + FAIL("%s: invalid eff_guest_pfn=%lx eff_guest_pte=%lx\n", __func__, eff_guest_pfn, + l1e_get_value(eff_guest_pte)); - page_table_page = mfn_is_page_table(gmfn); + page_table_page = mfn_is_page_table(eff_guest_mfn); - if ( (l1e_get_flags(spte) & _PAGE_RW ) && - !(l1e_get_flags(gpte) & _PAGE_RW) && !oos_ptes ) + guest_writable = + (l1e_get_flags(eff_guest_pte) & _PAGE_RW) || + (VM_ASSIST(d, VMASST_TYPE_writable_pagetables) && (level == 1) && mfn_out_of_sync(eff_guest_mfn)); + + if ( (l1e_get_flags(shadow_pte) & _PAGE_RW ) && !guest_writable ) { - printk("gpfn=%lx gmfn=%lx smfn=%lx t=0x%08x page_table_page=%d " - "oos_ptes=%d\n", - gpfn, gmfn, smfn, - frame_table[gmfn].u.inuse.type_info, - page_table_page, oos_ptes); + printk("eff_guest_pfn=%lx eff_guest_mfn=%lx shadow_mfn=%lx t=0x%08x page_table_page=%d\n", + eff_guest_pfn, eff_guest_mfn, shadow_mfn, + frame_table[eff_guest_mfn].u.inuse.type_info, + page_table_page); FAIL("RW coherence"); } if ( (level == 1) && - (l1e_get_flags(spte) & _PAGE_RW ) && - !((l1e_get_flags(gpte) & _PAGE_RW) && - (l1e_get_flags(gpte) & _PAGE_DIRTY)) && - !oos_ptes ) + (l1e_get_flags(shadow_pte) & _PAGE_RW ) && + !(guest_writable && (l1e_get_flags(eff_guest_pte) & _PAGE_DIRTY)) ) { - printk("gpfn=%lx gmfn=%lx smfn=%lx t=0x%08x page_table_page=%d " - "oos_ptes=%d\n", - gpfn, gmfn, smfn, - frame_table[gmfn].u.inuse.type_info, - page_table_page, oos_ptes); + printk("eff_guest_pfn=%lx eff_guest_mfn=%lx shadow_mfn=%lx t=0x%08x page_table_page=%d\n", + eff_guest_pfn, eff_guest_mfn, shadow_mfn, + frame_table[eff_guest_mfn].u.inuse.type_info, + page_table_page); FAIL("RW2 coherence"); } - if ( gmfn == smfn ) + if ( eff_guest_mfn == shadow_mfn ) { if ( level > 1 ) FAIL("Linear map ???"); /* XXX this will fail on BSD */ @@ -2788,9 +3079,9 @@ static int check_pte( if ( level == 2 ) { - if ( __shadow_status(d, gpfn, PGT_l1_shadow) != smfn ) - FAIL("smfn problem gpfn=%lx smfn=%lx", gpfn, - __shadow_status(d, gpfn, PGT_l1_shadow)); + if ( __shadow_status(d, eff_guest_pfn, PGT_l1_shadow) != shadow_mfn ) + FAIL("shadow_mfn problem eff_guest_pfn=%lx shadow_mfn=%lx", eff_guest_pfn, + __shadow_status(d, eff_guest_pfn, PGT_l1_shadow)); } else BUG(); // XXX -- not handled yet. @@ -2807,24 +3098,29 @@ static int check_l1_table( { struct domain *d = ed->domain; int i; - l1_pgentry_t *gpl1e, *spl1e; - int errors = 0, oos_ptes = 0; + unsigned long snapshot_mfn; + l1_pgentry_t *p_guest, *p_shadow, *p_snapshot = NULL; + int errors = 0; if ( page_out_of_sync(pfn_to_page(gmfn)) ) { - gmfn = __shadow_status(d, gpfn, PGT_snapshot); - oos_ptes = 1; - ASSERT(gmfn); + snapshot_mfn = __shadow_status(d, gpfn, PGT_snapshot); + ASSERT(snapshot_mfn); + p_snapshot = map_domain_mem(snapshot_mfn << PAGE_SHIFT); } - gpl1e = map_domain_mem(gmfn << PAGE_SHIFT); - spl1e = map_domain_mem(smfn << PAGE_SHIFT); + p_guest = map_domain_mem(gmfn << PAGE_SHIFT); + p_shadow = map_domain_mem(smfn << PAGE_SHIFT); for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) - errors += check_pte(ed, &gpl1e[i], &spl1e[i], 1, l2_idx, i, oos_ptes); + errors += check_pte(ed, p_guest+i, p_shadow+i, + p_snapshot ? p_snapshot+i : NULL, + 1, l2_idx, i); - unmap_domain_mem(spl1e); - unmap_domain_mem(gpl1e); + unmap_domain_mem(p_shadow); + unmap_domain_mem(p_guest); + if ( p_snapshot ) + unmap_domain_mem(p_snapshot); return errors; } @@ -2909,7 +3205,8 @@ int check_l2_table( errors += check_pte(ed, (l1_pgentry_t*)(&gpl2e[i]), /* Hmm, dirty ... */ (l1_pgentry_t*)(&spl2e[i]), - 2, i, 0, 0); + NULL, + 2, i, 0); unmap_domain_mem(spl2e); unmap_domain_mem(gpl2e); diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 948dd1802b..4f87b7f96f 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -270,7 +270,8 @@ asmlinkage int do_page_fault(struct xen_regs *regs) perfc_incrc(page_faults); - if ( likely(VM_ASSIST(d, VMASST_TYPE_writable_pagetables)) ) + if ( likely(VM_ASSIST(d, VMASST_TYPE_writable_pagetables) && + !shadow_mode_enabled(d)) ) { LOCK_BIGLOCK(d); if ( unlikely(d->arch.ptwr[PTWR_PT_ACTIVE].l1va) && @@ -286,8 +287,6 @@ asmlinkage int do_page_fault(struct xen_regs *regs) ((regs->error_code & 3) == 3) && /* write-protection fault */ ptwr_do_page_fault(d, addr) ) { - if ( unlikely(shadow_mode_enabled(d)) ) - (void)shadow_fault(addr, regs); UNLOCK_BIGLOCK(d); return EXCRET_fault_fixed; } diff --git a/xen/arch/x86/vmx.c b/xen/arch/x86/vmx.c index db82c73eac..b677b9dc24 100644 --- a/xen/arch/x86/vmx.c +++ b/xen/arch/x86/vmx.c @@ -672,7 +672,7 @@ static int vmx_set_cr0(unsigned long value) d->arch.arch_vmx.cpu_cr3); domain_crash_synchronous(); /* need to take a clean path */ } - old_base_mfn = pagetable_val(d->arch.guest_table) >> PAGE_SHIFT; + old_base_mfn = pagetable_get_pfn(d->arch.guest_table); if (old_base_mfn) put_page(pfn_to_page(old_base_mfn)); @@ -798,7 +798,7 @@ static int mov_to_cr(int gp, int cr, struct xen_regs *regs) "Invalid CR3 value=%lx", value); domain_crash_synchronous(); /* need to take a clean path */ } - old_base_mfn = pagetable_val(d->arch.guest_table) >> PAGE_SHIFT; + old_base_mfn = pagetable_get_pfn(d->arch.guest_table); d->arch.guest_table = mk_pagetable(mfn << PAGE_SHIFT); if (old_base_mfn) put_page(pfn_to_page(old_base_mfn)); diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h index 014fa7e45d..cf4e88bc6d 100644 --- a/xen/include/asm-x86/mm.h +++ b/xen/include/asm-x86/mm.h @@ -150,7 +150,7 @@ extern void invalidate_shadow_ldt(struct exec_domain *d); extern int shadow_remove_all_write_access( struct domain *d, unsigned long gpfn, unsigned long gmfn); extern u32 shadow_remove_all_access( struct domain *d, unsigned long gmfn); -extern int _shadow_mode_enabled(struct domain *d); +extern int _shadow_mode_refcounts(struct domain *d); static inline void put_page(struct pfn_info *page) { @@ -182,7 +182,7 @@ static inline int get_page(struct pfn_info *page, unlikely((nx & PGC_count_mask) == 0) || /* Count overflow? */ unlikely(d != _domain) ) /* Wrong owner? */ { - if ( !_shadow_mode_enabled(domain) ) + if ( !_shadow_mode_refcounts(domain) ) DPRINTK("Error pfn %lx: rd=%p, od=%p, caf=%08x, taf=%08x\n", page_to_pfn(page), domain, unpickle_domptr(d), x, page->u.inuse.type_info); @@ -315,14 +315,21 @@ int ptwr_init(struct domain *); void ptwr_destroy(struct domain *); void ptwr_flush(struct domain *, const int); int ptwr_do_page_fault(struct domain *, unsigned long); +int revalidate_l1(struct domain *, l1_pgentry_t *, l1_pgentry_t *); #define cleanup_writable_pagetable(_d) \ do { \ - if ( unlikely(VM_ASSIST((_d), VMASST_TYPE_writable_pagetables)) ) { \ - if ( (_d)->arch.ptwr[PTWR_PT_ACTIVE].l1va ) \ - ptwr_flush((_d), PTWR_PT_ACTIVE); \ - if ( (_d)->arch.ptwr[PTWR_PT_INACTIVE].l1va ) \ - ptwr_flush((_d), PTWR_PT_INACTIVE); \ + if ( likely(VM_ASSIST((_d), VMASST_TYPE_writable_pagetables)) ) \ + { \ + if ( likely(!shadow_mode_enabled(_d)) ) \ + { \ + if ( (_d)->arch.ptwr[PTWR_PT_ACTIVE].l1va ) \ + ptwr_flush((_d), PTWR_PT_ACTIVE); \ + if ( (_d)->arch.ptwr[PTWR_PT_INACTIVE].l1va ) \ + ptwr_flush((_d), PTWR_PT_INACTIVE); \ + } \ + else \ + shadow_sync_all(_d); \ } \ } while ( 0 ) @@ -330,9 +337,9 @@ int audit_adjust_pgtables(struct domain *d, int dir, int noisy); #ifndef NDEBUG -#define AUDIT_ALREADY_LOCKED ( 1u << 0 ) -#define AUDIT_ERRORS_OK ( 1u << 1 ) -#define AUDIT_QUIET ( 1u << 2 ) +#define AUDIT_SHADOW_ALREADY_LOCKED ( 1u << 0 ) +#define AUDIT_ERRORS_OK ( 1u << 1 ) +#define AUDIT_QUIET ( 1u << 2 ) void _audit_domain(struct domain *d, int flags); #define audit_domain(_d) _audit_domain((_d), AUDIT_ERRORS_OK) diff --git a/xen/include/asm-x86/page.h b/xen/include/asm-x86/page.h index a925f90fc8..59e582e4cd 100644 --- a/xen/include/asm-x86/page.h +++ b/xen/include/asm-x86/page.h @@ -23,6 +23,7 @@ #ifndef __ASSEMBLY__ typedef struct { unsigned long pt_lo; } pagetable_t; #define pagetable_val(_x) ((_x).pt_lo) +#define pagetable_get_pfn(_x) ((_x).pt_lo >> PAGE_SHIFT) #define mk_pagetable(_x) ( (pagetable_t) { (_x) } ) #endif @@ -103,6 +104,7 @@ extern void paging_init(void); #define _PAGE_PAT 0x080UL #define _PAGE_PSE 0x080UL #define _PAGE_GLOBAL 0x100UL +#define _PAGE_AVAIL 0xe00UL #define __PAGE_HYPERVISOR \ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h index 88ea9e6dac..146b75ed9d 100644 --- a/xen/include/asm-x86/shadow.h +++ b/xen/include/asm-x86/shadow.h @@ -33,11 +33,17 @@ /* Shadow PT operation mode : shadow-mode variable in arch_domain. */ #define SHM_enable (1<<0) /* we're in one of the shadow modes */ -#define SHM_log_dirty (1<<1) /* enable log dirty mode */ -#define SHM_translate (1<<2) /* do p2m tranaltion on guest tables */ -#define SHM_external (1<<3) /* external page table, not used by Xen */ +#define SHM_refcounts (1<<1) /* refcounts based on shadow tables instead of + guest tables */ +#define SHM_write_all (1<<2) /* allow write access to all guest pt pages, + regardless of pte write permissions */ +#define SHM_log_dirty (1<<3) /* enable log dirty mode */ +#define SHM_translate (1<<4) /* do p2m tranaltion on guest tables */ +#define SHM_external (1<<5) /* external page table, not used by Xen */ #define shadow_mode_enabled(_d) ((_d)->arch.shadow_mode) +#define shadow_mode_refcounts(_d) ((_d)->arch.shadow_mode & SHM_refcounts) +#define shadow_mode_write_all(_d) ((_d)->arch.shadow_mode & SHM_write_all) #define shadow_mode_log_dirty(_d) ((_d)->arch.shadow_mode & SHM_log_dirty) #define shadow_mode_translate(_d) ((_d)->arch.shadow_mode & SHM_translate) #define shadow_mode_external(_d) ((_d)->arch.shadow_mode & SHM_external) @@ -72,7 +78,29 @@ extern void free_monitor_pagetable(struct exec_domain *ed); extern void __shadow_sync_all(struct domain *d); extern int __shadow_out_of_sync(struct exec_domain *ed, unsigned long va); extern int set_p2m_entry( - struct domain *d, unsigned long pfn, unsigned long mfn); + struct domain *d, unsigned long pfn, unsigned long mfn, + struct map_dom_mem_cache *l2cache, + struct map_dom_mem_cache *l1cache); +extern void remove_shadow(struct domain *d, unsigned long gpfn, u32 stype); + +extern void shadow_l1_normal_pt_update(struct domain *d, + unsigned long pa, l1_pgentry_t l1e, + struct map_dom_mem_cache *cache); +extern void shadow_l2_normal_pt_update(struct domain *d, + unsigned long pa, l2_pgentry_t l2e, + struct map_dom_mem_cache *cache); +#ifdef __x86_64__ +extern void shadow_l3_normal_pt_update(struct domain *d, + unsigned long pa, l3_pgentry_t l3e, + struct map_dom_mem_cache *cache); +extern void shadow_l4_normal_pt_update(struct domain *d, + unsigned long pa, l4_pgentry_t l4e, + struct map_dom_mem_cache *cache); +#endif +extern int shadow_do_update_va_mapping(unsigned long va, + l1_pgentry_t val, + struct exec_domain *ed); + static inline unsigned long __shadow_status( struct domain *d, unsigned long gpfn, unsigned long stype); @@ -82,7 +110,13 @@ extern void vmx_shadow_clear_state(struct domain *); static inline int page_is_page_table(struct pfn_info *page) { - return page->count_info & PGC_page_table; + struct domain *owner = page_get_owner(page); + + if ( owner && shadow_mode_refcounts(owner) ) + return page->count_info & PGC_page_table; + + u32 type_info = page->u.inuse.type_info & PGT_type_mask; + return type_info && (type_info <= PGT_l4_page_table); } static inline int mfn_is_page_table(unsigned long mfn) @@ -90,7 +124,7 @@ static inline int mfn_is_page_table(unsigned long mfn) if ( !pfn_valid(mfn) ) return 0; - return frame_table[mfn].count_info & PGC_page_table; + return page_is_page_table(pfn_to_page(mfn)); } static inline int page_out_of_sync(struct pfn_info *page) @@ -103,7 +137,7 @@ static inline int mfn_out_of_sync(unsigned long mfn) if ( !pfn_valid(mfn) ) return 0; - return frame_table[mfn].count_info & PGC_out_of_sync; + return page_out_of_sync(pfn_to_page(mfn)); } @@ -191,10 +225,12 @@ static inline void shadow_mode_disable(struct domain *d) : (mfn) ) #define __gpfn_to_mfn(_d, gpfn) \ - ( (shadow_mode_translate(_d)) \ - ? ({ ASSERT(current->domain == (_d)); \ - phys_to_machine_mapping(gpfn); }) \ - : (gpfn) ) + ({ \ + ASSERT(current->domain == (_d)); \ + (shadow_mode_translate(_d)) \ + ? phys_to_machine_mapping(gpfn) \ + : (gpfn); \ + }) #define __gpfn_to_mfn_foreign(_d, gpfn) \ ( (shadow_mode_translate(_d)) \ @@ -237,6 +273,8 @@ struct out_of_sync_entry { #if SHADOW_DEBUG extern int shadow_status_noswap; +#define _SHADOW_REFLECTS_SNAPSHOT ( 9) +#define SHADOW_REFLECTS_SNAPSHOT (1u << _SHADOW_REFLECTS_SNAPSHOT) #endif #ifdef VERBOSE @@ -292,15 +330,18 @@ shadow_get_page_from_l1e(l1_pgentry_t l1e, struct domain *d) ASSERT(l1e_get_flags(l1e) & _PAGE_PRESENT); + if ( !shadow_mode_refcounts(d) ) + return 1; + nl1e = l1e; l1e_remove_flags(&nl1e, _PAGE_GLOBAL); res = get_page_from_l1e(nl1e, d); if ( unlikely(!res) && IS_PRIV(d) && !shadow_mode_translate(d) && - !(l1e_get_flags(l1e) & L1_DISALLOW_MASK) && - (mfn = l1e_get_pfn(l1e)) && + !(l1e_get_flags(nl1e) & L1_DISALLOW_MASK) && + (mfn = l1e_get_pfn(nl1e)) && pfn_valid(mfn) && - (owner = page_get_owner(pfn_to_page(l1e_get_pfn(l1e)))) && + (owner = page_get_owner(pfn_to_page(mfn))) && (d != owner) ) { res = get_page_from_l1e(nl1e, owner); @@ -319,6 +360,103 @@ shadow_get_page_from_l1e(l1_pgentry_t l1e, struct domain *d) return res; } +static inline void +shadow_put_page_from_l1e(l1_pgentry_t l1e, struct domain *d) +{ + if ( !shadow_mode_refcounts(d) ) + return; + + put_page_from_l1e(l1e, d); +} + +static inline void +shadow_put_page_type(struct domain *d, struct pfn_info *page) +{ + if ( !shadow_mode_refcounts(d) ) + return; + + put_page_type(page); +} + +static inline int shadow_get_page(struct domain *d, + struct pfn_info *page, + struct domain *owner) +{ + if ( !shadow_mode_refcounts(d) ) + return 1; + return get_page(page, owner); +} + +static inline void shadow_put_page(struct domain *d, + struct pfn_info *page) +{ + if ( !shadow_mode_refcounts(d) ) + return; + put_page(page); +} + +/************************************************************************/ + +static inline int __mark_dirty(struct domain *d, unsigned int mfn) +{ + unsigned long pfn; + int rc = 0; + + ASSERT(spin_is_locked(&d->arch.shadow_lock)); + ASSERT(d->arch.shadow_dirty_bitmap != NULL); + + if ( !VALID_MFN(mfn) ) + return rc; + + // N.B. This doesn't use __mfn_to_gpfn(). + // This wants the nice compact set of PFNs from 0..domain's max, + // which __mfn_to_gpfn() only returns for translated domains. + // + pfn = machine_to_phys_mapping[mfn]; + + /* + * Values with the MSB set denote MFNs that aren't really part of the + * domain's pseudo-physical memory map (e.g., the shared info frame). + * Nothing to do here... + */ + if ( unlikely(IS_INVALID_M2P_ENTRY(pfn)) ) + return rc; + + if ( likely(pfn < d->arch.shadow_dirty_bitmap_size) ) + { + /* N.B. Can use non-atomic TAS because protected by shadow_lock. */ + if ( !__test_and_set_bit(pfn, d->arch.shadow_dirty_bitmap) ) + { + d->arch.shadow_dirty_count++; + rc = 1; + } + } +#ifndef NDEBUG + else if ( mfn < max_page ) + { + SH_LOG("mark_dirty OOR! mfn=%x pfn=%lx max=%x (dom %p)", + mfn, pfn, d->arch.shadow_dirty_bitmap_size, d); + SH_LOG("dom=%p caf=%08x taf=%08x", + page_get_owner(&frame_table[mfn]), + frame_table[mfn].count_info, + frame_table[mfn].u.inuse.type_info ); + } +#endif + + return rc; +} + + +static inline int mark_dirty(struct domain *d, unsigned int mfn) +{ + int rc; + shadow_lock(d); + rc = __mark_dirty(d, mfn); + shadow_unlock(d); + return rc; +} + + /************************************************************************/ static inline void @@ -350,10 +488,15 @@ static inline void __guest_set_l2e( struct exec_domain *ed, unsigned long va, l2_pgentry_t value) { + struct domain *d = ed->domain; + ed->arch.guest_vtable[l2_table_offset(va)] = value; - if ( unlikely(shadow_mode_translate(ed->domain)) ) + if ( unlikely(shadow_mode_translate(d)) ) update_hl2e(ed, va); + + if ( unlikely(shadow_mode_log_dirty(d)) ) + __mark_dirty(d, pagetable_get_pfn(ed->arch.guest_table)); } static inline void @@ -380,11 +523,12 @@ update_hl2e(struct exec_domain *ed, unsigned long va) if ( (l1e_has_changed(&old_hl2e, &new_hl2e, _PAGE_PRESENT)) ) { if ( (l1e_get_flags(new_hl2e) & _PAGE_PRESENT) && - !get_page(pfn_to_page(l1e_get_pfn(new_hl2e)), ed->domain) ) + !shadow_get_page(ed->domain, pfn_to_page(l1e_get_pfn(new_hl2e)), + ed->domain) ) new_hl2e = l1e_empty(); if ( l1e_get_flags(old_hl2e) & _PAGE_PRESENT ) { - put_page(pfn_to_page(l1e_get_pfn(old_hl2e))); + shadow_put_page(ed->domain, pfn_to_page(l1e_get_pfn(old_hl2e))); need_flush = 1; } } @@ -401,7 +545,7 @@ update_hl2e(struct exec_domain *ed, unsigned long va) static inline void shadow_drop_references( struct domain *d, struct pfn_info *page) { - if ( likely(!shadow_mode_enabled(d)) || + if ( likely(!shadow_mode_refcounts(d)) || ((page->u.inuse.type_info & PGT_count_mask) == 0) ) return; @@ -423,7 +567,7 @@ static inline void shadow_drop_references( static inline void shadow_sync_and_drop_references( struct domain *d, struct pfn_info *page) { - if ( likely(!shadow_mode_enabled(d)) ) + if ( likely(!shadow_mode_refcounts(d)) ) return; shadow_lock(d); @@ -520,64 +664,6 @@ shadow_unpin(unsigned long smfn) } -/************************************************************************/ - -static inline int __mark_dirty(struct domain *d, unsigned int mfn) -{ - unsigned long pfn; - int rc = 0; - - ASSERT(spin_is_locked(&d->arch.shadow_lock)); - ASSERT(d->arch.shadow_dirty_bitmap != NULL); - - if ( !VALID_MFN(mfn) ) - return rc; - - pfn = __mfn_to_gpfn(d, mfn); - - /* - * Values with the MSB set denote MFNs that aren't really part of the - * domain's pseudo-physical memory map (e.g., the shared info frame). - * Nothing to do here... - */ - if ( unlikely(IS_INVALID_M2P_ENTRY(pfn)) ) - return rc; - - if ( likely(pfn < d->arch.shadow_dirty_bitmap_size) ) - { - /* N.B. Can use non-atomic TAS because protected by shadow_lock. */ - if ( !__test_and_set_bit(pfn, d->arch.shadow_dirty_bitmap) ) - { - d->arch.shadow_dirty_count++; - rc = 1; - } - } -#ifndef NDEBUG - else if ( mfn < max_page ) - { - SH_LOG("mark_dirty OOR! mfn=%x pfn=%lx max=%x (dom %p)", - mfn, pfn, d->arch.shadow_dirty_bitmap_size, d); - SH_LOG("dom=%p caf=%08x taf=%08x\n", - page_get_owner(&frame_table[mfn]), - frame_table[mfn].count_info, - frame_table[mfn].u.inuse.type_info ); - } -#endif - - return rc; -} - - -static inline int mark_dirty(struct domain *d, unsigned int mfn) -{ - int rc; - shadow_lock(d); - rc = __mark_dirty(d, mfn); - shadow_unlock(d); - return rc; -} - - /************************************************************************/ extern void shadow_mark_va_out_of_sync( @@ -666,8 +752,10 @@ static inline void l1pte_propagate_from_guest( (_PAGE_PRESENT|_PAGE_ACCESSED)) && VALID_MFN(mfn = __gpfn_to_mfn(d, l1e_get_pfn(gpte))) ) { - spte = l1e_create_pfn(mfn, l1e_get_flags(gpte) & ~_PAGE_GLOBAL); - + spte = l1e_create_pfn(mfn, + l1e_get_flags(gpte) & + ~(_PAGE_GLOBAL | _PAGE_AVAIL)); + if ( shadow_mode_log_dirty(d) || !(l1e_get_flags(gpte) & _PAGE_DIRTY) || mfn_is_page_table(mfn) ) @@ -729,14 +817,13 @@ static inline void l2pde_general( spde = l2e_empty(); if ( (l2e_get_flags(gpde) & _PAGE_PRESENT) && (sl1mfn != 0) ) { - spde = l2e_create_pfn(sl1mfn, - l2e_get_flags(gpde) | _PAGE_RW | _PAGE_ACCESSED); - l2e_add_flags(&gpde, _PAGE_ACCESSED); /* N.B. PDEs do not have a dirty bit. */ + spde = l2e_create_pfn(sl1mfn, + (l2e_get_flags(gpde) | _PAGE_RW | _PAGE_ACCESSED) + & ~(_PAGE_AVAIL)); + + /* N.B. PDEs do not have a dirty bit. */ + l2e_add_flags(&gpde, _PAGE_ACCESSED); - // XXX mafetter: Hmm... - // Shouldn't the dirty log be checked/updated here? - // Actually, it needs to be done in this function's callers. - // *gpde_p = gpde; } @@ -769,34 +856,57 @@ validate_pte_change( l1_pgentry_t *shadow_pte_p) { l1_pgentry_t old_spte, new_spte; + int need_flush = 0; perfc_incrc(validate_pte_calls); -#if 0 - FSH_LOG("validate_pte(old=%lx new=%lx)", old_pte, new_pte); -#endif - - old_spte = *shadow_pte_p; l1pte_propagate_from_guest(d, new_pte, &new_spte); - // only do the ref counting if something important changed. - // - if ( ((l1e_get_value(old_spte) | l1e_get_value(new_spte)) & _PAGE_PRESENT ) && - l1e_has_changed(&old_spte, &new_spte, _PAGE_RW | _PAGE_PRESENT) ) + if ( shadow_mode_refcounts(d) ) { - perfc_incrc(validate_pte_changes); + old_spte = *shadow_pte_p; - if ( (l1e_get_flags(new_spte) & _PAGE_PRESENT) && - !shadow_get_page_from_l1e(new_spte, d) ) - new_spte = l1e_empty(); - if ( l1e_get_flags(old_spte) & _PAGE_PRESENT ) - put_page_from_l1e(old_spte, d); + if ( l1e_get_value(old_spte) == l1e_get_value(new_spte) ) + { + // No accounting required... + // + perfc_incrc(validate_pte_changes1); + } + else if ( l1e_get_value(old_spte) == (l1e_get_value(new_spte)|_PAGE_RW) ) + { + // Fast path for PTEs that have merely been write-protected + // (e.g., during a Unix fork()). A strict reduction in privilege. + // + perfc_incrc(validate_pte_changes2); + if ( likely(l1e_get_flags(new_spte) & _PAGE_PRESENT) ) + shadow_put_page_type(d, &frame_table[l1e_get_pfn(new_spte)]); + } + else if ( ((l1e_get_flags(old_spte) | l1e_get_flags(new_spte)) & + _PAGE_PRESENT ) && + l1e_has_changed(&old_spte, &new_spte, _PAGE_RW | _PAGE_PRESENT) ) + { + // only do the ref counting if something important changed. + // + perfc_incrc(validate_pte_changes3); + + if ( (l1e_get_flags(new_spte) & _PAGE_PRESENT) && + !shadow_get_page_from_l1e(new_spte, d) ) + new_spte = l1e_empty(); + if ( l1e_get_flags(old_spte) & _PAGE_PRESENT ) + { + shadow_put_page_from_l1e(old_spte, d); + need_flush = 1; + } + } + else + { + perfc_incrc(validate_pte_changes4); + } } *shadow_pte_p = new_spte; - // paranoia rules! - return 1; + return need_flush; } // returns true if a tlb flush is needed @@ -808,6 +918,7 @@ validate_hl2e_change( l1_pgentry_t *shadow_hl2e_p) { l1_pgentry_t old_hl2e, new_hl2e; + int need_flush = 0; perfc_incrc(validate_hl2e_calls); @@ -825,14 +936,15 @@ validate_hl2e_change( !get_page(pfn_to_page(l1e_get_pfn(new_hl2e)), d) ) new_hl2e = l1e_empty(); if ( l1e_get_flags(old_hl2e) & _PAGE_PRESENT ) + { put_page(pfn_to_page(l1e_get_pfn(old_hl2e))); + need_flush = 1; + } } *shadow_hl2e_p = new_hl2e; - // paranoia rules! - return 1; - + return need_flush; } // returns true if a tlb flush is needed @@ -844,15 +956,13 @@ validate_pde_change( l2_pgentry_t *shadow_pde_p) { l2_pgentry_t old_spde, new_spde; + int need_flush = 0; perfc_incrc(validate_pde_calls); old_spde = *shadow_pde_p; l2pde_propagate_from_guest(d, &new_gpde, &new_spde); - // XXX Shouldn't we propagate the new_gpde to the guest? - // And then mark the guest's L2 page as dirty? - // Only do the ref counting if something important changed. // if ( ((l2e_get_value(old_spde) | l2e_get_value(new_spde)) & _PAGE_PRESENT) && @@ -864,13 +974,15 @@ validate_pde_change( !get_shadow_ref(l2e_get_pfn(new_spde)) ) BUG(); if ( l2e_get_flags(old_spde) & _PAGE_PRESENT ) + { put_shadow_ref(l2e_get_pfn(old_spde)); + need_flush = 1; + } } *shadow_pde_p = new_spde; - // paranoia rules! - return 1; + return need_flush; } /*********************************************************************/ @@ -1035,10 +1147,19 @@ static inline unsigned long __shadow_status( { perfc_incrc(shadow_status_shortcut); #ifndef NDEBUG - ASSERT(___shadow_status(d, gpfn, stype) == 0); + if ( ___shadow_status(d, gpfn, stype) != 0 ) + { + printk("d->id=%d gpfn=%lx gmfn=%lx stype=%lx c=%x t=%x " + "mfn_out_of_sync(gmfn)=%d mfn_is_page_table(gmfn)=%d\n", + d->id, gpfn, gmfn, stype, + frame_table[gmfn].count_info, + frame_table[gmfn].u.inuse.type_info, + mfn_out_of_sync(gmfn), mfn_is_page_table(gmfn)); + BUG(); + } - // Undo the affects of the above ASSERT on ___shadow_status()'s perf - // counters. + // Undo the affects of the above call to ___shadow_status()'s perf + // counters, since that call is really just part of an assertion. // perfc_decrc(shadow_status_calls); perfc_decrc(shadow_status_miss); @@ -1056,12 +1177,12 @@ static inline unsigned long __shadow_status( * * Either returns PGT_none, or PGT_l{1,2,3,4}_page_table. */ -static inline unsigned long +static inline u32 shadow_max_pgtable_type(struct domain *d, unsigned long gpfn, unsigned long *smfn) { struct shadow_status *x; - unsigned long pttype = PGT_none, type; + u32 pttype = PGT_none, type; ASSERT(spin_is_locked(&d->arch.shadow_lock)); ASSERT(gpfn == (gpfn & PGT_mfn_mask)); @@ -1379,7 +1500,6 @@ shadow_set_l1e(unsigned long va, l1_pgentry_t new_spte, int create_l1_shadow) struct exec_domain *ed = current; struct domain *d = ed->domain; l2_pgentry_t sl2e; - l1_pgentry_t old_spte; #if 0 printk("shadow_set_l1e(va=%p, new_spte=%p, create=%d)\n", @@ -1424,17 +1544,20 @@ shadow_set_l1e(unsigned long va, l1_pgentry_t new_spte, int create_l1_shadow) } } - old_spte = shadow_linear_pg_table[l1_linear_offset(va)]; - - // only do the ref counting if something important changed. - // - if ( l1e_has_changed(&old_spte, &new_spte, _PAGE_RW | _PAGE_PRESENT) ) + if ( shadow_mode_refcounts(d) ) { - if ( (l1e_get_flags(new_spte) & _PAGE_PRESENT) && - !shadow_get_page_from_l1e(new_spte, d) ) - new_spte = l1e_empty(); - if ( l1e_get_flags(old_spte) & _PAGE_PRESENT ) - put_page_from_l1e(old_spte, d); + l1_pgentry_t old_spte = shadow_linear_pg_table[l1_linear_offset(va)]; + + // only do the ref counting if something important changed. + // + if ( l1e_has_changed(&old_spte, &new_spte, _PAGE_RW | _PAGE_PRESENT) ) + { + if ( (l1e_get_flags(new_spte) & _PAGE_PRESENT) && + !shadow_get_page_from_l1e(new_spte, d) ) + new_spte = l1e_empty(); + if ( l1e_get_flags(old_spte) & _PAGE_PRESENT ) + shadow_put_page_from_l1e(old_spte, d); + } } shadow_linear_pg_table[l1_linear_offset(va)] = new_spte; @@ -1444,6 +1567,27 @@ shadow_set_l1e(unsigned long va, l1_pgentry_t new_spte, int create_l1_shadow) /************************************************************************/ +static inline int +shadow_mode_page_writable(struct domain *d, unsigned long gpfn) +{ + unsigned long mfn = __gpfn_to_mfn(d, gpfn); + u32 type = frame_table[mfn].u.inuse.type_info & PGT_type_mask; + + if ( shadow_mode_refcounts(d) && + (type == PGT_writable_page) ) + type = shadow_max_pgtable_type(d, gpfn, NULL); + + if ( VM_ASSIST(d, VMASST_TYPE_writable_pagetables) && + (type == PGT_l1_page_table) ) + return 1; + + if ( shadow_mode_write_all(d) && + type && (type <= PGT_l4_page_table) ) + return 1; + + return 0; +} + static inline l1_pgentry_t gva_to_gpte(unsigned long gva) { l2_pgentry_t gpde; diff --git a/xen/include/asm-x86/x86_32/domain_page.h b/xen/include/asm-x86/x86_32/domain_page.h index f72bce7936..0220de530e 100644 --- a/xen/include/asm-x86/x86_32/domain_page.h +++ b/xen/include/asm-x86/x86_32/domain_page.h @@ -26,4 +26,51 @@ extern void *map_domain_mem(unsigned long pa); */ extern void unmap_domain_mem(void *va); +struct map_dom_mem_cache { + unsigned long pa; + void *va; +}; + +#define MAP_DOM_MEM_CACHE_INIT { .pa = 0 } + +static inline void * +map_domain_mem_with_cache(unsigned long pa, + struct map_dom_mem_cache *cache) +{ + if ( likely(cache != NULL) ) + { + if ( likely(cache->pa) ) + { + if ( likely((pa & PAGE_MASK) == (cache->pa & PAGE_MASK)) ) + goto done; + unmap_domain_mem(cache->va); + } + cache->pa = (pa & PAGE_MASK) | 1; + cache->va = map_domain_mem(cache->pa); + done: + return (void *)(((unsigned long)cache->va & PAGE_MASK) | + (pa & ~PAGE_MASK)); + } + + return map_domain_mem(pa); +} + +static inline void +unmap_domain_mem_with_cache(void *va, + struct map_dom_mem_cache *cache) +{ + if ( unlikely(!cache) ) + unmap_domain_mem(va); +} + +static inline void +unmap_domain_mem_cache(struct map_dom_mem_cache *cache) +{ + if ( likely(cache != NULL) && likely(cache->pa) ) + { + unmap_domain_mem(cache->va); + cache->pa = 0; + } +} + #endif /* __ASM_DOMAIN_PAGE_H__ */ diff --git a/xen/include/xen/lib.h b/xen/include/xen/lib.h index 313635f82a..91c34ce232 100644 --- a/xen/include/xen/lib.h +++ b/xen/include/xen/lib.h @@ -15,7 +15,7 @@ #define BUG_ON(_p) do { if (_p) BUG(); } while ( 0 ) #ifndef NDEBUG -#define ASSERT(_p) if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s\n", #_p , __LINE__, __FILE__); BUG(); } +#define ASSERT(_p) { if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s\n", #_p , __LINE__, __FILE__); BUG(); } } #else #define ASSERT(_p) ((void)0) #endif diff --git a/xen/include/xen/perfc_defn.h b/xen/include/xen/perfc_defn.h index 501851ec55..c7f2493a1a 100644 --- a/xen/include/xen/perfc_defn.h +++ b/xen/include/xen/perfc_defn.h @@ -86,12 +86,14 @@ PERFCOUNTER_CPU(resync_hl2, "resync HL2 page") PERFCOUNTER_CPU(shadow_make_snapshot, "snapshots created") PERFCOUNTER_CPU(shadow_mark_mfn_out_of_sync_calls, "calls to shadow_mk_out_of_sync") PERFCOUNTER_CPU(shadow_out_of_sync_calls, "calls to shadow_out_of_sync") -PERFCOUNTER_CPU(extra_va_update_sync, "extra syncs for bug in chk_pgtb") PERFCOUNTER_CPU(snapshot_entry_matches_calls, "calls to ss_entry_matches") PERFCOUNTER_CPU(snapshot_entry_matches_true, "ss_entry_matches returns true") PERFCOUNTER_CPU(validate_pte_calls, "calls to validate_pte_change") -PERFCOUNTER_CPU(validate_pte_changes, "validate_pte makes changes") +PERFCOUNTER_CPU(validate_pte_changes1, "validate_pte makes changes1") +PERFCOUNTER_CPU(validate_pte_changes2, "validate_pte makes changes2") +PERFCOUNTER_CPU(validate_pte_changes3, "validate_pte makes changes3") +PERFCOUNTER_CPU(validate_pte_changes4, "validate_pte makes changes4") PERFCOUNTER_CPU(validate_pde_calls, "calls to validate_pde_change") PERFCOUNTER_CPU(validate_pde_changes, "validate_pde makes changes") PERFCOUNTER_CPU(shadow_get_page_fail, "shadow_get_page_from_l1e fails" ) From ff10f688f94a8a297595f17c03fe6d19b3eb4cc8 Mon Sep 17 00:00:00 2001 From: "sd386@font.cl.cam.ac.uk" Date: Mon, 9 May 2005 16:52:35 +0000 Subject: [PATCH 26/54] bitkeeper revision 1.1346.1.4 (427f9553IVi9yymg7Hp6J5wwxNl-7Q) fixed CPU locking --- xen/common/schedule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 5a38a07507..9a04aae4c3 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -369,7 +369,7 @@ long sched_adjdom(struct sched_adjdom_cmd *cmd) cpu = ed->processor; if (!__get_cpu_bit(cpu, have_lock)) { /* if we don't have a lock on this CPU: acquire it*/ - if (!spin_trylock(&schedule_data[cpu].schedule_lock)) { + if (spin_trylock(&schedule_data[cpu].schedule_lock)) { /*we have this lock!*/ __set_cpu_bit(cpu, have_lock); succ = 1; From 1bcec9a36b45639bd6bb6b6c56d8649f9fe2b8a8 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 9 May 2005 17:45:01 +0000 Subject: [PATCH 27/54] bitkeeper revision 1.1389.5.38 (427fa19dBMqmd2zGoBa8AA2fKxF9Ug) SEDF merge fixes. Signed-off-by: Keir Fraser --- xen/common/sched_sedf.c | 82 ++++++++++++++++++++--------------------- xen/common/schedule.c | 1 - 2 files changed, 41 insertions(+), 42 deletions(-) diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c index 893f861c89..e10c7783b8 100644 --- a/xen/common/sched_sedf.c +++ b/xen/common/sched_sedf.c @@ -120,7 +120,7 @@ struct sedf_cpu_info { struct list_head extraq[2]; }; -#define EDOM_INFO(d) ((struct sedf_edom_info *)((d)->ed_sched_priv)) +#define EDOM_INFO(d) ((struct sedf_edom_info *)((d)->sched_priv)) #define CPU_INFO(cpu) ((struct sedf_cpu_info *)schedule_data[cpu].sched_priv) #define LIST(d) (&EDOM_INFO(d)->list) #define EXTRALIST(d,i) (&(EDOM_INFO(d)->extralist[i])) @@ -163,7 +163,7 @@ static inline void extraq_del(struct exec_domain *d, int i) struct list_head *list = EXTRALIST(d,i); ASSERT(extraq_on(d,i)); PRINT(3, "Removing domain %i.%i from L%i extraq\n", d->domain->id, - d->eid, i); + d->id, i); list_del(list); list->next = NULL; ASSERT(!extraq_on(d, i)); @@ -181,7 +181,7 @@ static inline void extraq_add_sort_update(struct exec_domain *d, int i, int sub) ASSERT(!extraq_on(d,i)); PRINT(3, "Adding domain %i.%i (score= %i, short_pen= %lli) to L%i "\ - "extraq\n", d->domain->id, d->eid, EDOM_INFO(d)->score[i], + "extraq\n", d->domain->id, d->id, EDOM_INFO(d)->score[i], EDOM_INFO(d)->short_block_lost_tot, i); /*iterate through all elements to find our "hole" and on our way update all the other scores*/ @@ -193,10 +193,10 @@ static inline void extraq_add_sort_update(struct exec_domain *d, int i, int sub) else PRINT(4,"\tbehind domain %i.%i (score= %i)\n", curinf->exec_domain->domain->id, - curinf->exec_domain->eid, curinf->score[i]); + curinf->exec_domain->id, curinf->score[i]); } /*cur now contains the element, before which we'll enqueue*/ - PRINT(3, "\tlist_add to %x\n", cur->prev); + PRINT(3, "\tlist_add to %p\n", cur->prev); list_add(EXTRALIST(d,i),cur->prev); /*continue updating the extraq*/ @@ -206,24 +206,24 @@ static inline void extraq_add_sort_update(struct exec_domain *d, int i, int sub) curinf = list_entry(cur,struct sedf_edom_info, extralist[i]); curinf->score[i] -= sub; - PRINT(4, "\tupdating domain %i.%i (score= %llu)\n", + PRINT(4, "\tupdating domain %i.%i (score= %u)\n", curinf->exec_domain->domain->id, - curinf->exec_domain->eid, curinf->score[i]); + curinf->exec_domain->id, curinf->score[i]); } ASSERT(extraq_on(d,i)); } static inline void extraq_check(struct exec_domain *d) { if (extraq_on(d, EXTRA_UTIL_Q)) { - PRINT(2,"Dom %i.%i is on L1 extraQ\n",d->domain->id, d->eid); + PRINT(2,"Dom %i.%i is on L1 extraQ\n",d->domain->id, d->id); if (!(EDOM_INFO(d)->status & EXTRA_AWARE) && !extra_runs(EDOM_INFO(d))) { extraq_del(d, EXTRA_UTIL_Q); PRINT(2,"Removed dom %i.%i from L1 extraQ\n", - d->domain->id, d->eid); + d->domain->id, d->id); } } else { PRINT(2,"Dom %i.%i is NOT on L1 extraQ\n",d->domain->id, - d->eid); + d->id); if ((EDOM_INFO(d)->status & EXTRA_AWARE) && sedf_runnable(d)) { #if (EXTRA == EXTRA_ROUNDR) @@ -235,7 +235,7 @@ static inline void extraq_check(struct exec_domain *d) { ; #endif PRINT(2,"Added dom %i.%i to L1 extraQ\n",d->domain->id, - d->eid); + d->id); } } } @@ -267,7 +267,7 @@ static inline void __del_from_queue(struct exec_domain *d) struct list_head *list = LIST(d); ASSERT(__task_on_queue(d)); PRINT(3,"Removing domain %i.%i (bop= %llu) from runq/waitq\n", d->domain->id, - d->eid, PERIOD_BEGIN(EDOM_INFO(d))); + d->id, PERIOD_BEGIN(EDOM_INFO(d))); list_del(list); list->next = NULL; ASSERT(!__task_on_queue(d)); @@ -284,7 +284,7 @@ static inline void list_insert_sort(struct list_head *list, break; } /*cur now contains the element, before which we'll enqueue*/ - PRINT(3,"\tlist_add to %x\n",cur->prev); + PRINT(3,"\tlist_add to %p\n",cur->prev); list_add(element, cur->prev); } #define DOMAIN_COMPARER(name, field, comp1, comp2) \ @@ -308,7 +308,7 @@ DOMAIN_COMPARER(waitq, list, PERIOD_BEGIN(d1), PERIOD_BEGIN(d2)) static inline void __add_to_waitqueue_sort(struct exec_domain *d) { ASSERT(!__task_on_queue(d)); PRINT(3,"Adding domain %i.%i (bop= %llu) to waitq\n", d->domain->id, - d->eid, PERIOD_BEGIN(EDOM_INFO(d))); + d->id, PERIOD_BEGIN(EDOM_INFO(d))); list_insert_sort(WAITQ(d->processor), LIST(d), waitq_comp); ASSERT(__task_on_queue(d)); } @@ -321,7 +321,7 @@ static inline void __add_to_waitqueue_sort(struct exec_domain *d) { DOMAIN_COMPARER(runq, list, d1->deadl_abs, d2->deadl_abs) static inline void __add_to_runqueue_sort(struct exec_domain *d) { PRINT(3,"Adding domain %i.%i (deadl= %llu) to runq\n", d->domain->id, - d->eid, EDOM_INFO(d)->deadl_abs); + d->id, EDOM_INFO(d)->deadl_abs); list_insert_sort(RUNQ(d->processor), LIST(d), runq_comp); } @@ -346,16 +346,16 @@ static int sedf_init_scheduler() { /* Allocates memory for per domain private scheduling data*/ static int sedf_alloc_task(struct exec_domain *d) { PRINT(2,"sedf_alloc_task was called, domain-id %i.%i\n",d->domain->id, - d->eid); + d->id); if (d->domain->sched_priv == NULL) { if ((d->domain->sched_priv = xmalloc(struct sedf_dom_info)) == NULL ) return -1; memset(d->domain->sched_priv, 0, sizeof(struct sedf_dom_info)); } - if ((d->ed_sched_priv = xmalloc(struct sedf_edom_info)) == NULL ) + if ((d->sched_priv = xmalloc(struct sedf_edom_info)) == NULL ) return -1; - memset(d->ed_sched_priv, 0, sizeof(struct sedf_edom_info)); + memset(d->sched_priv, 0, sizeof(struct sedf_edom_info)); return 0; } @@ -366,7 +366,7 @@ static void sedf_add_task(struct exec_domain *d) inf->exec_domain = d; PRINT(2,"sedf_add_task was called, domain-id %i.%i\n",d->domain->id, - d->eid); + d->id); if (d->domain->id==0) { /*set dom0 to something useful to boot the machine*/ @@ -405,22 +405,22 @@ static void sedf_free_task(struct domain *d) for (i = 0; i < MAX_VIRT_CPUS; i++) if ( d->exec_domain[i] ) { - ASSERT(d->exec_domain[i]->ed_sched_priv != NULL); - xfree(d->exec_domain[i]->ed_sched_priv); + ASSERT(d->exec_domain[i]->sched_priv != NULL); + xfree(d->exec_domain[i]->sched_priv); } } /* Initialises idle task */ static int sedf_init_idle_task(struct exec_domain *d) { PRINT(2,"sedf_init_idle_task was called, domain-id %i.%i\n", - d->domain->id, d->eid); + d->domain->id, d->id); if ( sedf_alloc_task(d) < 0 ) return -1; sedf_add_task(d); EDOM_INFO(d)->deadl_abs = 0; EDOM_INFO(d)->status &= ~SEDF_ASLEEP; - set_bit(EDF_RUNNING, &d->ed_flags); + set_bit(EDF_RUNNING, &d->flags); /*the idle task doesn't have to turn up on any list...*/ return 0; } @@ -496,7 +496,7 @@ struct list_head* waitq) { list_for_each_safe(cur, tmp, waitq) { curinf = list_entry(cur, struct sedf_edom_info, list); PRINT(4,"\tLooking @ dom %i.%i\n", - curinf->exec_domain->domain->id, curinf->exec_domain->eid); + curinf->exec_domain->domain->id, curinf->exec_domain->id); if (PERIOD_BEGIN(curinf) <= now) { __del_from_queue(curinf->exec_domain); __add_to_runqueue_sort(curinf->exec_domain); @@ -511,12 +511,12 @@ struct list_head* waitq) { list_for_each_safe(cur, tmp, runq) { curinf = list_entry(cur,struct sedf_edom_info,list); PRINT(4,"\tLooking @ dom %i.%i\n", - curinf->exec_domain->domain->id, curinf->exec_domain->eid); + curinf->exec_domain->domain->id, curinf->exec_domain->id); if (unlikely(curinf->slice == 0)) { /*ignore domains with empty slice*/ PRINT(4,"\tUpdating zero-slice domain %i.%i\n", curinf->exec_domain->domain->id, - curinf->exec_domain->eid); + curinf->exec_domain->id); __del_from_queue(curinf->exec_domain); /*move them to their next period*/ @@ -534,7 +534,7 @@ struct list_head* waitq) { "slice (%llu / %llu) now: %llu "\ "cputime: %llu\n", curinf->exec_domain->domain->id, - curinf->exec_domain->eid, + curinf->exec_domain->id, curinf->deadl_abs, curinf->slice, now, curinf->cputime); __del_from_queue(curinf->exec_domain); @@ -600,11 +600,11 @@ static inline void desched_extra_dom(s_time_t now, struct exec_domain* d) { /*inf->short_block_lost_tot -= EXTRA_QUANTUM;*/ inf->short_block_lost_tot -= now - inf->sched_start_abs; PRINT(3,"Domain %i.%i: Short_block_loss: %lli\n", - inf->exec_domain->domain->id, inf->exec_domain->eid, + inf->exec_domain->domain->id, inf->exec_domain->id, inf->short_block_lost_tot); if (inf->short_block_lost_tot <= 0) { PRINT(4,"Domain %i.%i compensated short block loss!\n", - inf->exec_domain->domain->id, inf->exec_domain->eid); + inf->exec_domain->domain->id, inf->exec_domain->id); /*we have (over-)compensated our block penalty*/ inf->short_block_lost_tot = 0; /*we don't want a place on the penalty queue anymore!*/ @@ -807,14 +807,14 @@ sched_done: } static void sedf_sleep(struct exec_domain *d) { - PRINT(2,"sedf_sleep was called, domain-id %i.%i\n",d->domain->id, d->eid); + PRINT(2,"sedf_sleep was called, domain-id %i.%i\n",d->domain->id, d->id); if (is_idle_task(d->domain)) return; EDOM_INFO(d)->status |= SEDF_ASLEEP; - if ( test_bit(EDF_RUNNING, &d->ed_flags) ) { + if ( test_bit(EDF_RUNNING, &d->flags) ) { #ifdef ADV_SCHED_HISTO adv_sched_hist_start(d->processor); #endif @@ -1139,14 +1139,14 @@ void sedf_wake(struct exec_domain *d) { s_time_t now = NOW(); struct sedf_edom_info* inf = EDOM_INFO(d); - PRINT(3, "sedf_wake was called, domain-id %i.%i\n",d->domain->id, d->eid); + PRINT(3, "sedf_wake was called, domain-id %i.%i\n",d->domain->id, d->id); if (unlikely(is_idle_task(d->domain))) return; if ( unlikely(__task_on_queue(d)) ) { PRINT(3,"\tdomain %i.%i is already in some queue\n", - d->domain->id, d->eid); + d->domain->id, d->id); return; } ASSERT(!sedf_runnable(d)); @@ -1159,7 +1159,7 @@ void sedf_wake(struct exec_domain *d) { inf->deadl_abs = now + inf->slice; PRINT(3,"waking up domain %i.%i (deadl= %llu period= %llu "\ - "now= %llu)\n", d->domain->id, d->eid, inf->deadl_abs, + "now= %llu)\n", d->domain->id, d->id, inf->deadl_abs, inf->period, now); #ifdef SEDF_STATS inf->block_tot++; @@ -1221,7 +1221,7 @@ void sedf_wake(struct exec_domain *d) { } } PRINT(3,"woke up domain %i.%i (deadl= %llu period= %llu "\ - "now= %llu)\n", d->domain->id, d->eid, inf->deadl_abs, + "now= %llu)\n", d->domain->id, d->id, inf->deadl_abs, inf->period, now); if (PERIOD_BEGIN(inf) > now) { __add_to_waitqueue_sort(d); @@ -1256,23 +1256,23 @@ void sedf_wake(struct exec_domain *d) { /*Print a lot of use-{full, less} information about a domains in the system*/ static void sedf_dump_domain(struct exec_domain *d) { - printk("%i.%i has=%c ", d->domain->id, d->eid, - test_bit(EDF_RUNNING, &d->ed_flags) ? 'T':'F'); + printk("%i.%i has=%c ", d->domain->id, d->id, + test_bit(EDF_RUNNING, &d->flags) ? 'T':'F'); printk("p=%llu sl=%llu ddl=%llu w=%hu c=%llu sc=%i xtr(%s)=%llu ew=%hu", EDOM_INFO(d)->period, EDOM_INFO(d)->slice, EDOM_INFO(d)->deadl_abs, EDOM_INFO(d)->weight, d->cpu_time, EDOM_INFO(d)->score[EXTRA_UTIL_Q], (EDOM_INFO(d)->status & EXTRA_AWARE) ? "yes" : "no", EDOM_INFO(d)->extra_time_tot, EDOM_INFO(d)->extraweight); if (d->cpu_time !=0) - printf(" (%lu%)", (EDOM_INFO(d)->extra_time_tot * 100) + printf(" (%llu%%)", (EDOM_INFO(d)->extra_time_tot * 100) / d->cpu_time); #ifdef SEDF_STATS if (EDOM_INFO(d)->block_time_tot!=0) - printf(" pen=%lu%", (EDOM_INFO(d)->penalty_time_tot * 100) / + printf(" pen=%llu%%", (EDOM_INFO(d)->penalty_time_tot * 100) / EDOM_INFO(d)->block_time_tot); if (EDOM_INFO(d)->block_tot!=0) - printf("\n blks=%lu sh=%lu (%lu%) (shc=%lu (%lu%) shex=%i "\ - "shexsl=%i) l=%lu (%lu%) avg: b=%llu p=%llu", + printf("\n blks=%u sh=%u (%u%%) (shc=%u (%u%%) shex=%i "\ + "shexsl=%i) l=%u (%u%%) avg: b=%llu p=%llu", EDOM_INFO(d)->block_tot, EDOM_INFO(d)->short_block_tot, (EDOM_INFO(d)->short_block_tot * 100) / EDOM_INFO(d)->block_tot, EDOM_INFO(d)->short_cont, diff --git a/xen/common/schedule.c b/xen/common/schedule.c index f6acf2cd5a..fb2db1b30f 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -296,7 +296,6 @@ long do_sched_op(unsigned long op) case SCHEDOP_shutdown: { - TRACE_3D(TRC_SCHED_SHUTDOWN, current->domain->id, current->id, TRACE_3D(TRC_SCHED_SHUTDOWN, current->domain->id, current->id, (op >> SCHEDOP_reasonshift)); domain_shutdown((u8)(op >> SCHEDOP_reasonshift)); From 24edf4b8989a60f108982ee44590df856a8fc9b2 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 9 May 2005 17:50:11 +0000 Subject: [PATCH 28/54] bitkeeper revision 1.1389.10.1 (427fa2d3ZV92f_ErvLuIzWbV1f67QA) Phase 1 of upgrading platform code to be derived from Linux 2.6.11 rather than 2.4.x. Signed-off-by: Keir Fraser --- .rootkeys | 30 +- xen/arch/x86/Makefile | 1 + xen/arch/x86/Rules.mk | 4 +- xen/arch/x86/acpi.c | 729 -------- xen/arch/x86/acpi/boot.c | 912 ++++++++++ xen/arch/x86/apic.c | 19 +- xen/arch/x86/i8259.c | 10 +- xen/arch/x86/io_apic.c | 1610 ++++++++++------- xen/arch/x86/irq.c | 1 - xen/arch/x86/microcode.c | 7 - xen/arch/x86/mpparse.c | 716 +++----- xen/arch/x86/mtrr/main.c | 1 + xen/arch/x86/nmi.c | 10 +- xen/arch/x86/physdev.c | 2 - xen/arch/x86/smpboot.c | 32 +- xen/arch/x86/x86_32/asm-offsets.c | 2 +- xen/arch/x86/x86_32/mm.c | 2 +- xen/arch/x86/x86_32/traps.c | 8 +- xen/arch/x86/x86_64/mm.c | 2 +- xen/common/bitmap.c | 365 ++++ xen/common/xmalloc.c | 2 +- xen/drivers/acpi/tables.c | 61 +- xen/include/acpi/acconfig.h | 31 +- xen/include/acpi/acexcep.h | 10 +- xen/include/acpi/acglobal.h | 81 +- xen/include/acpi/achware.h | 43 +- xen/include/acpi/aclocal.h | 54 +- xen/include/acpi/acmacros.h | 63 +- xen/include/acpi/acobject.h | 31 +- xen/include/acpi/acoutput.h | 4 +- xen/include/acpi/acpi.h | 2 +- xen/include/acpi/acpi_bus.h | 69 +- xen/include/acpi/acpi_drivers.h | 284 +-- xen/include/acpi/acpiosxf.h | 38 +- xen/include/acpi/acpixf.h | 45 +- xen/include/acpi/acstruct.h | 27 +- xen/include/acpi/actbl.h | 33 +- xen/include/acpi/actbl1.h | 2 +- xen/include/acpi/actbl2.h | 94 +- xen/include/acpi/actypes.h | 149 +- xen/include/acpi/acutils.h | 43 +- xen/include/acpi/platform/acenv.h | 23 +- xen/include/acpi/platform/acgcc.h | 4 +- xen/include/acpi/platform/aclinux.h | 6 +- xen/include/asm-ia64/config.h | 8 - xen/include/asm-x86/apic.h | 58 +- xen/include/asm-x86/apicdef.h | 279 ++- xen/include/asm-x86/config.h | 4 + xen/include/asm-x86/domain.h | 2 + xen/include/asm-x86/fixmap.h | 33 +- xen/include/asm-x86/io_apic.h | 150 +- xen/include/asm-x86/io_ports.h | 30 - xen/include/asm-x86/irq.h | 52 +- xen/include/asm-x86/mach-default/apm.h | 75 + xen/include/asm-x86/mach-default/bios_ebda.h | 15 + xen/include/asm-x86/mach-default/do_timer.h | 85 + xen/include/asm-x86/mach-default/entry_arch.h | 34 + xen/include/asm-x86/mach-default/io_ports.h | 30 + .../asm-x86/mach-default/irq_vectors.h | 96 + .../asm-x86/mach-default/irq_vectors_limits.h | 21 + xen/include/asm-x86/mach-default/mach_apic.h | 133 ++ .../asm-x86/mach-default/mach_apicdef.h | 13 + xen/include/asm-x86/mach-default/mach_ipi.h | 30 + .../asm-x86/mach-default/mach_mpparse.h | 28 + .../asm-x86/mach-default/mach_mpspec.h | 8 + .../asm-x86/mach-default/mach_reboot.h | 30 + xen/include/asm-x86/mach-default/mach_time.h | 122 ++ xen/include/asm-x86/mach-default/mach_timer.h | 48 + xen/include/asm-x86/mach-default/mach_traps.h | 29 + .../asm-x86/mach-default/mach_wakecpu.h | 41 + .../asm-x86/mach-default/pci-functions.h | 19 + .../asm-x86/mach-default/setup_arch_post.h | 40 + .../asm-x86/mach-default/setup_arch_pre.h | 5 + .../asm-x86/mach-default/smpboot_hooks.h | 44 + xen/include/asm-x86/mach_apic.h | 32 - xen/include/asm-x86/mpspec.h | 280 +-- xen/include/asm-x86/mpspec_def.h | 188 ++ xen/include/asm-x86/page.h | 2 - xen/include/asm-x86/processor.h | 15 +- xen/include/asm-x86/smp.h | 100 +- xen/include/asm-x86/smpboot.h | 116 -- xen/include/asm-x86/system.h | 1 + xen/include/asm-x86/time.h | 2 +- xen/include/xen/acpi.h | 126 +- xen/include/xen/bitmap.h | 249 +++ xen/include/xen/bitops.h | 129 ++ xen/include/xen/config.h | 6 +- xen/include/xen/cpumask.h | 25 + xen/include/xen/irq.h | 3 +- xen/include/xen/smp.h | 19 + xen/include/xen/spinlock.h | 3 + xen/include/xen/types.h | 6 + 92 files changed, 5466 insertions(+), 3060 deletions(-) delete mode 100644 xen/arch/x86/acpi.c create mode 100644 xen/arch/x86/acpi/boot.c create mode 100644 xen/common/bitmap.c delete mode 100644 xen/include/asm-x86/io_ports.h create mode 100644 xen/include/asm-x86/mach-default/apm.h create mode 100644 xen/include/asm-x86/mach-default/bios_ebda.h create mode 100644 xen/include/asm-x86/mach-default/do_timer.h create mode 100644 xen/include/asm-x86/mach-default/entry_arch.h create mode 100644 xen/include/asm-x86/mach-default/io_ports.h create mode 100644 xen/include/asm-x86/mach-default/irq_vectors.h create mode 100644 xen/include/asm-x86/mach-default/irq_vectors_limits.h create mode 100644 xen/include/asm-x86/mach-default/mach_apic.h create mode 100644 xen/include/asm-x86/mach-default/mach_apicdef.h create mode 100644 xen/include/asm-x86/mach-default/mach_ipi.h create mode 100644 xen/include/asm-x86/mach-default/mach_mpparse.h create mode 100644 xen/include/asm-x86/mach-default/mach_mpspec.h create mode 100644 xen/include/asm-x86/mach-default/mach_reboot.h create mode 100644 xen/include/asm-x86/mach-default/mach_time.h create mode 100644 xen/include/asm-x86/mach-default/mach_timer.h create mode 100644 xen/include/asm-x86/mach-default/mach_traps.h create mode 100644 xen/include/asm-x86/mach-default/mach_wakecpu.h create mode 100644 xen/include/asm-x86/mach-default/pci-functions.h create mode 100644 xen/include/asm-x86/mach-default/setup_arch_post.h create mode 100644 xen/include/asm-x86/mach-default/setup_arch_pre.h create mode 100644 xen/include/asm-x86/mach-default/smpboot_hooks.h delete mode 100644 xen/include/asm-x86/mach_apic.h create mode 100644 xen/include/asm-x86/mpspec_def.h create mode 100644 xen/include/xen/bitmap.h create mode 100644 xen/include/xen/bitops.h create mode 100644 xen/include/xen/cpumask.h diff --git a/.rootkeys b/.rootkeys index cfb01fda7d..c3afd372dd 100644 --- a/.rootkeys +++ b/.rootkeys @@ -1185,7 +1185,7 @@ 427664f5eygrc3nEhI3RKf0Y37PzyA xen/arch/ia64/xentime.c 3ddb79bcZbRBzT3elFWSX7u6NtMagQ xen/arch/x86/Makefile 3ddb79bcBQF85CfLS4i1WGZ4oLLaCA xen/arch/x86/Rules.mk -3e5636e5FAYZ5_vQnmgwFJfSdmO5Mw xen/arch/x86/acpi.c +3e5636e5FAYZ5_vQnmgwFJfSdmO5Mw xen/arch/x86/acpi/boot.c 3ddb79bcsjinG9k1KcvbVBuas1R2dA xen/arch/x86/apic.c 42360b3244-Q6BpEKhR_A1YtG1wPNQ xen/arch/x86/audit.c 3ddb79c4yGZ7_22QAFFwPzqP4NSHwA xen/arch/x86/boot/mkelf32.c @@ -1247,6 +1247,7 @@ 422f27c8J9DQfCpegccMid59XhSmGA xen/arch/x86/x86_emulate.c 3ddb79bdff-gj-jFGKjOejeHLqL8Lg xen/common/Makefile 3e397e66AyyD5fYraAySWuwi9uqSXg xen/common/ac_timer.c +427fa2d0J0LU2s5oKbsM0nTZ2iyd2Q xen/common/bitmap.c 3ddb79bdLX_P6iB7ILiblRLWvebapg xen/common/dom0_ops.c 3e6377e4i0c9GtKN65e99OtRbw3AZw xen/common/dom_mem_ops.c 3ddb79bdYO5D8Av12NHqPeSviav7cg xen/common/domain.c @@ -1341,13 +1342,33 @@ 4204e7acwXDo-5iAAiO2eQbtDeYZXA xen/include/asm-x86/init.h 3ddb79c3fQ_O3o5NHK2N8AJdk0Ea4Q xen/include/asm-x86/io.h 3ddb79c2TKeScYHQZreTdHqYNLbehQ xen/include/asm-x86/io_apic.h -42605109qxLSrHVE2SRhGXmgk907iw xen/include/asm-x86/io_ports.h 3ddb79c2L7rTlFzazOLW1XuSZefpFw xen/include/asm-x86/irq.h 404f1b93OjLO4bFfBXYNaJdIqlNz-Q xen/include/asm-x86/ldt.h -4260510aYPj2kr6rMbBfMxcvvmXndQ xen/include/asm-x86/mach_apic.h +427fa2d0m8MOSSXT13zgb-q0fGA_Dw xen/include/asm-x86/mach-default/apm.h +427fa2d0suK9Av7vsAXhsQxZjqpc_Q xen/include/asm-x86/mach-default/bios_ebda.h +427fa2d0yC3KzLozoeK3Xa3uGVfIdw xen/include/asm-x86/mach-default/do_timer.h +427fa2d0bWQkR1mW5OBYxn07AN-bDw xen/include/asm-x86/mach-default/entry_arch.h +427fa2d0-SWcuwbdSypo4953bc2JdQ xen/include/asm-x86/mach-default/io_ports.h +427fa2d0eyAl7LAeO-SVV4IW7lZPGQ xen/include/asm-x86/mach-default/irq_vectors.h +427fa2d0df7VWG4KKpnKbKR2Cbd1_w xen/include/asm-x86/mach-default/irq_vectors_limits.h +4260510aYPj2kr6rMbBfMxcvvmXndQ xen/include/asm-x86/mach-default/mach_apic.h +427fa2d0I3FWjE2tWdOhlEOJn7stcg xen/include/asm-x86/mach-default/mach_apicdef.h +427fa2d093fDS2gOBLcl7Yndzl7HmA xen/include/asm-x86/mach-default/mach_ipi.h +427fa2d0Y7bD35d-FvDAeiJDIdRw2A xen/include/asm-x86/mach-default/mach_mpparse.h +427fa2d0aLQgE9e1GY9ZP5jrMOC8pQ xen/include/asm-x86/mach-default/mach_mpspec.h +427fa2d0fJ5nNn5ydJuOaZIL6F2fjQ xen/include/asm-x86/mach-default/mach_reboot.h +427fa2d0VlN555TE68TjKMsrOoFXNA xen/include/asm-x86/mach-default/mach_time.h +427fa2d0C0jWTKYjy7WJjGKeujSpSg xen/include/asm-x86/mach-default/mach_timer.h +427fa2d0UXLiS1scpNrK26ZT6Oes3g xen/include/asm-x86/mach-default/mach_traps.h +427fa2d0OfglYyfpDTD5DII4M0uZRw xen/include/asm-x86/mach-default/mach_wakecpu.h +427fa2d0_OBPxdi5Qo04JWgZhz7BFA xen/include/asm-x86/mach-default/pci-functions.h +427fa2d0mrTtXrliqDfLuJc5LLVXaA xen/include/asm-x86/mach-default/setup_arch_post.h +427fa2d0Uoo7gC61Kep6Yy7Os367Hg xen/include/asm-x86/mach-default/setup_arch_pre.h +427fa2d1EKnA8zCq2QLHiGOUqOgszg xen/include/asm-x86/mach-default/smpboot_hooks.h 3ddb79c3I98vWcQR8xEo34JMJ4Ahyw xen/include/asm-x86/mc146818rtc.h 40ec25fd7cSvbP7Biw91zaU_g0xsEQ xen/include/asm-x86/mm.h 3ddb79c3n_UbPuxlkNxvvLycClIkxA xen/include/asm-x86/mpspec.h +427fa2d1eJRenftJJnRyLsHKl1ghtA xen/include/asm-x86/mpspec_def.h 3ddb79c2wa0dA_LGigxOelSGbJ284Q xen/include/asm-x86/msr.h 41aaf567Mi3OishhvrCtET1y-mxQBg xen/include/asm-x86/mtrr.h 41a61536MFhNalgbVmYGXAhQsPTZNw xen/include/asm-x86/multicall.h @@ -1409,11 +1430,14 @@ 3ddb79c25UE59iu4JJcbRalx95mvcg xen/include/public/xen.h 3e397e66m2tO3s-J8Jnr7Ws_tGoPTg xen/include/xen/ac_timer.h 40715b2epYl2jBbxzz9CI2rgIca7Zg xen/include/xen/acpi.h +427fa2d1wyoVbvCyZRLposYjA_D_4g xen/include/xen/bitmap.h +427fa2d1ItcC_yWuBUkhc7adedP5ow xen/include/xen/bitops.h 3ddb79c0c0cX_DZE209-Bb-Rx1v-Aw xen/include/xen/cache.h 41f2cea7Yna7xc0X9fyavIjoSFFeVg xen/include/xen/compile.h.in 3f840f12CkbYSlwMrY2S11Mpyxg7Nw xen/include/xen/compiler.h 3ddb79c259jh8hE7vre_8NuE7nwNSA xen/include/xen/config.h 3eb165e0eawr3R-p2ZQtSdLWtLRN_A xen/include/xen/console.h +427fa2d1bQCWgEQqTTh5MjG4MPEH9g xen/include/xen/cpumask.h 3ddb79c1V44RD26YqCUm-kqIupM37A xen/include/xen/ctype.h 3ddb79c05DdHQ0UxX_jKsXdR4QlMCA xen/include/xen/delay.h 40f2b4a2hC3HtChu-ArD8LyojxWMjg xen/include/xen/domain.h diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index 42d828f7f5..ddb605e9cf 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -3,6 +3,7 @@ include $(BASEDIR)/Rules.mk OBJS += $(patsubst %.S,%.o,$(wildcard $(TARGET_SUBARCH)/*.S)) OBJS += $(patsubst %.c,%.o,$(wildcard $(TARGET_SUBARCH)/*.c)) +OBJS += $(patsubst %.c,%.o,$(wildcard acpi/*.c)) OBJS += $(patsubst %.c,%.o,$(wildcard mtrr/*.c)) OBJS := $(subst $(TARGET_SUBARCH)/asm-offsets.o,,$(OBJS)) diff --git a/xen/arch/x86/Rules.mk b/xen/arch/x86/Rules.mk index 915a646bed..f21be04704 100644 --- a/xen/arch/x86/Rules.mk +++ b/xen/arch/x86/Rules.mk @@ -2,8 +2,8 @@ # x86-specific definitions CFLAGS += -nostdinc -fno-builtin -fno-common -fno-strict-aliasing -CFLAGS += -iwithprefix include -Wall -Werror -pipe -CFLAGS += -I$(BASEDIR)/include -Wno-pointer-arith -Wredundant-decls +CFLAGS += -iwithprefix include -Wall -Werror -Wno-pointer-arith -pipe +CFLAGS += -I$(BASEDIR)/include -I$(BASEDIR)/include/asm-x86/mach-default ifeq ($(optimize),y) CFLAGS += -O3 -fomit-frame-pointer diff --git a/xen/arch/x86/acpi.c b/xen/arch/x86/acpi.c deleted file mode 100644 index 4d3cc212b1..0000000000 --- a/xen/arch/x86/acpi.c +++ /dev/null @@ -1,729 +0,0 @@ -/* - * acpi.c - Architecture-Specific Low-Level ACPI Support - * - * Copyright (C) 2001, 2002 Paul Diefenbaugh - * Copyright (C) 2001 Jun Nakajima - * Copyright (C) 2001 Patrick Mochel - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define PREFIX "ACPI: " - -int acpi_lapic; -int acpi_ioapic; -int acpi_strict; - -acpi_interrupt_flags acpi_sci_flags __initdata; -int acpi_sci_override_gsi __initdata; -/* -------------------------------------------------------------------------- - Boot-time Configuration - -------------------------------------------------------------------------- */ - -int acpi_noirq __initdata = 0; /* skip ACPI IRQ initialization */ -int acpi_ht __initdata = 1; /* enable HT */ - -enum acpi_irq_model_id acpi_irq_model; - - -/* - * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END, - * to map the target physical address. The problem is that set_fixmap() - * provides a single page, and it is possible that the page is not - * sufficient. - * By using this area, we can map up to MAX_IO_APICS pages temporarily, - * i.e. until the next __va_range() call. - * - * Important Safety Note: The fixed I/O APIC page numbers are *subtracted* - * from the fixed base. That's why we start at FIX_IO_APIC_BASE_END and - * count idx down while incrementing the phys address. - */ -char *__acpi_map_table(unsigned long phys, unsigned long size) -{ - unsigned long base, offset, mapped_size; - int idx; - - if (phys + size < 8*1024*1024) - return __va(phys); - - offset = phys & (PAGE_SIZE - 1); - mapped_size = PAGE_SIZE - offset; - set_fixmap(FIX_ACPI_END, phys); - base = fix_to_virt(FIX_ACPI_END); - - /* - * Most cases can be covered by the below. - */ - idx = FIX_ACPI_END; - while (mapped_size < size) { - if (--idx < FIX_ACPI_BEGIN) - return 0; /* cannot handle this */ - phys += PAGE_SIZE; - set_fixmap(idx, phys); - mapped_size += PAGE_SIZE; - } - - return ((char *) base + offset); -} - - -#ifdef CONFIG_X86_LOCAL_APIC - -static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; - - -static int __init -acpi_parse_madt ( - unsigned long phys_addr, - unsigned long size) -{ - struct acpi_table_madt *madt = NULL; - - if (!phys_addr || !size) - return -EINVAL; - - madt = (struct acpi_table_madt *) __acpi_map_table(phys_addr, size); - if (!madt) { - printk(KERN_WARNING PREFIX "Unable to map MADT\n"); - return -ENODEV; - } - - if (madt->lapic_address) - acpi_lapic_addr = (u64) madt->lapic_address; - - printk(KERN_INFO PREFIX "Local APIC address 0x%08x\n", - madt->lapic_address); - - detect_clustered_apic(madt->header.oem_id, madt->header.oem_table_id); - - return 0; -} - - -static int __init -acpi_parse_lapic ( - acpi_table_entry_header *header) -{ - struct acpi_table_lapic *processor = NULL; - - processor = (struct acpi_table_lapic*) header; - if (!processor) - return -EINVAL; - - acpi_table_print_madt_entry(header); - - mp_register_lapic ( - processor->id, /* APIC ID */ - processor->flags.enabled); /* Enabled? */ - - return 0; -} - - -static int __init -acpi_parse_lapic_addr_ovr ( - acpi_table_entry_header *header) -{ - struct acpi_table_lapic_addr_ovr *lapic_addr_ovr = NULL; - - lapic_addr_ovr = (struct acpi_table_lapic_addr_ovr*) header; - if (!lapic_addr_ovr) - return -EINVAL; - - acpi_lapic_addr = lapic_addr_ovr->address; - - return 0; -} - -static int __init -acpi_parse_lapic_nmi ( - acpi_table_entry_header *header) -{ - struct acpi_table_lapic_nmi *lapic_nmi = NULL; - - lapic_nmi = (struct acpi_table_lapic_nmi*) header; - if (!lapic_nmi) - return -EINVAL; - - acpi_table_print_madt_entry(header); - - if (lapic_nmi->lint != 1) - printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n"); - - return 0; -} - -#endif /*CONFIG_X86_LOCAL_APIC*/ - -#if defined(CONFIG_X86_IO_APIC) /*&& defined(CONFIG_ACPI_INTERPRETER)*/ - -static int __init -acpi_parse_ioapic ( - acpi_table_entry_header *header) -{ - struct acpi_table_ioapic *ioapic = NULL; - - ioapic = (struct acpi_table_ioapic*) header; - if (!ioapic) - return -EINVAL; - - acpi_table_print_madt_entry(header); - - mp_register_ioapic ( - ioapic->id, - ioapic->address, - ioapic->global_irq_base); - - return 0; -} - -#ifdef CONFIG_ACPI_INTERPRETER -/* - * Parse Interrupt Source Override for the ACPI SCI - */ -static void -acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger) -{ - if (trigger == 0) /* compatible SCI trigger is level */ - trigger = 3; - - if (polarity == 0) /* compatible SCI polarity is low */ - polarity = 3; - - /* Command-line over-ride via acpi_sci= */ - if (acpi_sci_flags.trigger) - trigger = acpi_sci_flags.trigger; - - if (acpi_sci_flags.polarity) - polarity = acpi_sci_flags.polarity; - - /* - * mp_config_acpi_legacy_irqs() already setup IRQs < 16 - * If GSI is < 16, this will update its flags, - * else it will create a new mp_irqs[] entry. - */ - mp_override_legacy_irq(gsi, polarity, trigger, gsi); - - /* - * stash over-ride to indicate we've been here - * and for later update of acpi_fadt - */ - acpi_sci_override_gsi = gsi; - return; -} -#endif - -static int __init -acpi_parse_fadt(unsigned long phys, unsigned long size) -{ - struct fadt_descriptor_rev2 *fadt =0; - - fadt = (struct fadt_descriptor_rev2*) __acpi_map_table(phys,size); - if (!fadt) { - printk(KERN_WARNING PREFIX "Unable to map FADT\n"); - return 0; - } - -#ifdef CONFIG_ACPI_INTERPRETER - /* initialize sci_int early for INT_SRC_OVR MADT parsing */ - acpi_fadt.sci_int = fadt->sci_int; -#endif - - return 0; -} - - -static int __init -acpi_parse_int_src_ovr ( - acpi_table_entry_header *header) -{ - struct acpi_table_int_src_ovr *intsrc = NULL; - - intsrc = (struct acpi_table_int_src_ovr*) header; - if (!intsrc) - return -EINVAL; - - acpi_table_print_madt_entry(header); - -#ifdef CONFIG_ACPI_INTERPRETER - if (intsrc->bus_irq == acpi_fadt.sci_int) { - acpi_sci_ioapic_setup(intsrc->global_irq, - intsrc->flags.polarity, intsrc->flags.trigger); - return 0; - } -#endif - - mp_override_legacy_irq ( - intsrc->bus_irq, - intsrc->flags.polarity, - intsrc->flags.trigger, - intsrc->global_irq); - - return 0; -} - - -static int __init -acpi_parse_nmi_src ( - acpi_table_entry_header *header) -{ - struct acpi_table_nmi_src *nmi_src = NULL; - - nmi_src = (struct acpi_table_nmi_src*) header; - if (!nmi_src) - return -EINVAL; - - acpi_table_print_madt_entry(header); - - /* TBD: Support nimsrc entries? */ - - return 0; -} - -#endif /*CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER*/ - - -static unsigned long __init -acpi_scan_rsdp ( - unsigned long start, - unsigned long length) -{ - unsigned long offset = 0; - unsigned long sig_len = sizeof("RSD PTR ") - 1; - - /* - * Scan all 16-byte boundaries of the physical memory region for the - * RSDP signature. - */ - for (offset = 0; offset < length; offset += 16) { - if (strncmp((char *) (start + offset), "RSD PTR ", sig_len)) - continue; - return (start + offset); - } - - return 0; -} - - -unsigned long __init -acpi_find_rsdp (void) -{ - unsigned long rsdp_phys = 0; - - /* - * Scan memory looking for the RSDP signature. First search EBDA (low - * memory) paragraphs and then search upper memory (E0000-FFFFF). - */ - rsdp_phys = acpi_scan_rsdp (0, 0x400); - if (!rsdp_phys) - rsdp_phys = acpi_scan_rsdp (0xE0000, 0x20000); - - return rsdp_phys; -} - - -/* - * acpi_boot_init() - * called from setup_arch(), always. - * 1. maps ACPI tables for later use - * 2. enumerates lapics - * 3. enumerates io-apics - * - * side effects: - * acpi_lapic = 1 if LAPIC found - * acpi_ioapic = 1 if IOAPIC found - * if (acpi_lapic && acpi_ioapic) smp_found_config = 1; - * if acpi_blacklisted() disable_acpi() - * acpi_irq_model=... - * ... - * - * return value: (currently ignored) - * 0: success - * !0: failure - */ -int __init -acpi_boot_init (void) -{ - int result = 0; - - if (acpi_disabled && !acpi_ht) - return(1); - - /* - * The default interrupt routing model is PIC (8259). This gets - * overriden if IOAPICs are enumerated (below). - */ - acpi_irq_model = ACPI_IRQ_MODEL_PIC; - - /* - * Initialize the ACPI boot-time table parser. - */ - result = acpi_table_init(); - if (result) { - disable_acpi(); - return result; - } - - result = acpi_blacklisted(); - if (result) { - printk(KERN_NOTICE PREFIX "BIOS listed in blacklist, disabling ACPI support\n"); - disable_acpi(); - return result; - } - -#ifdef CONFIG_X86_LOCAL_APIC - - /* - * MADT - * ---- - * Parse the Multiple APIC Description Table (MADT), if exists. - * Note that this table provides platform SMP configuration - * information -- the successor to MPS tables. - */ - - result = acpi_table_parse(ACPI_APIC, acpi_parse_madt); - if (!result) { - return 0; - } - else if (result < 0) { - printk(KERN_ERR PREFIX "Error parsing MADT\n"); - return result; - } - else if (result > 1) - printk(KERN_WARNING PREFIX "Multiple MADT tables exist\n"); - - /* - * Local APIC - * ---------- - * Note that the LAPIC address is obtained from the MADT (32-bit value) - * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value). - */ - - result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr); - if (result < 0) { - printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); - return result; - } - - mp_register_lapic_address(acpi_lapic_addr); - - result = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic); - if (!result) { - printk(KERN_ERR PREFIX "No LAPIC entries present\n"); - /* TBD: Cleanup to allow fallback to MPS */ - return -ENODEV; - } - else if (result < 0) { - printk(KERN_ERR PREFIX "Error parsing LAPIC entry\n"); - /* TBD: Cleanup to allow fallback to MPS */ - return result; - } - - result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi); - if (result < 0) { - printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); - /* TBD: Cleanup to allow fallback to MPS */ - return result; - } - - acpi_lapic = 1; - -#endif /*CONFIG_X86_LOCAL_APIC*/ - -#if defined(CONFIG_X86_IO_APIC) /*&& defined(CONFIG_ACPI_INTERPRETER)*/ - - /* - * I/O APIC - * -------- - */ - -#if 0 - /* - * ACPI interpreter is required to complete interrupt setup, - * so if it is off, don't enumerate the io-apics with ACPI. - * If MPS is present, it will handle them, - * otherwise the system will stay in PIC mode - */ - if (acpi_disabled || acpi_noirq) { - return 1; - } -#endif - - /* - * if "noapic" boot option, don't look for IO-APICs - */ - if (ioapic_setup_disabled()) { - printk(KERN_INFO PREFIX "Skipping IOAPIC probe " - "due to 'noapic' option.\n"); - return 1; - } - - - result = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic); - if (!result) { - printk(KERN_ERR PREFIX "No IOAPIC entries present\n"); - return -ENODEV; - } - else if (result < 0) { - printk(KERN_ERR PREFIX "Error parsing IOAPIC entry\n"); - return result; - } - - /* Build a default routing table for legacy (ISA) interrupts. */ - mp_config_acpi_legacy_irqs(); - - /* Record sci_int for use when looking for MADT sci_int override */ - acpi_table_parse(ACPI_FADT, acpi_parse_fadt); - - result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr); - if (result < 0) { - printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); - /* TBD: Cleanup to allow fallback to MPS */ - return result; - } - -#ifdef CONFIG_ACPI_INTERPRETER - /* - * If BIOS did not supply an INT_SRC_OVR for the SCI - * pretend we got one so we can set the SCI flags. - */ - if (!acpi_sci_override_gsi) - acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0); -#endif - - result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src); - if (result < 0) { - printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); - /* TBD: Cleanup to allow fallback to MPS */ - return result; - } - - acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; - - acpi_irq_balance_set(NULL); - - acpi_ioapic = 1; - - if (acpi_lapic && acpi_ioapic) - smp_found_config = 1; - -#endif /*CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER*/ - - return 0; -} - - -#ifdef CONFIG_ACPI_BUS -/* - * acpi_pic_sci_set_trigger() - * - * use ELCR to set PIC-mode trigger type for SCI - * - * If a PIC-mode SCI is not recognized or gives spurious IRQ7's - * it may require Edge Trigger -- use "acpi_sci=edge" - * - * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers - * for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge. - * ECLR1 is IRQ's 0-7 (IRQ 0, 1, 2 must be 0) - * ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0) - */ - -void __init -acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) -{ - unsigned char mask = 1 << (irq & 7); - unsigned int port = 0x4d0 + (irq >> 3); - unsigned char val = inb(port); - - - printk(PREFIX "IRQ%d SCI:", irq); - if (!(val & mask)) { - printk(" Edge"); - - if (trigger == 3) { - printk(" set to Level"); - outb(val | mask, port); - } - } else { - printk(" Level"); - - if (trigger == 1) { - printk(" set to Edge"); - outb(val & ~mask, port); - } - } - printk(" Trigger.\n"); -} - -#endif /* CONFIG_ACPI_BUS */ - - -/* -------------------------------------------------------------------------- - Low-Level Sleep Support - -------------------------------------------------------------------------- */ - -#ifdef CONFIG_ACPI_SLEEP - -#define DEBUG - -#ifdef DEBUG -#include -#endif - -/* address in low memory of the wakeup routine. */ -unsigned long acpi_wakeup_address = 0; - -/* new page directory that we will be using */ -static pmd_t *pmd; - -/* saved page directory */ -static pmd_t saved_pmd; - -/* page which we'll use for the new page directory */ -static pte_t *ptep; - -extern unsigned long FASTCALL(acpi_copy_wakeup_routine(unsigned long)); - -/* - * acpi_create_identity_pmd - * - * Create a new, identity mapped pmd. - * - * Do this by creating new page directory, and marking all the pages as R/W - * Then set it as the new Page Middle Directory. - * And, of course, flush the TLB so it takes effect. - * - * We save the address of the old one, for later restoration. - */ -static void acpi_create_identity_pmd (void) -{ - pgd_t *pgd; - int i; - - ptep = (pte_t*)__get_free_page(GFP_KERNEL); - - /* fill page with low mapping */ - for (i = 0; i < PTRS_PER_PTE; i++) - set_pte(ptep + i, mk_pte_phys(i << PAGE_SHIFT, PAGE_SHARED)); - - pgd = pgd_offset(current->active_mm, 0); - pmd = pmd_alloc(current->mm,pgd, 0); - - /* save the old pmd */ - saved_pmd = *pmd; - - /* set the new one */ - set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(ptep))); - - /* flush the TLB */ - local_flush_tlb(); -} - -/* - * acpi_restore_pmd - * - * Restore the old pmd saved by acpi_create_identity_pmd and - * free the page that said function alloc'd - */ -static void acpi_restore_pmd (void) -{ - set_pmd(pmd, saved_pmd); - local_flush_tlb(); - free_page((unsigned long)ptep); -} - -/** - * acpi_save_state_mem - save kernel state - * - * Create an identity mapped page table and copy the wakeup routine to - * low memory. - */ -int acpi_save_state_mem (void) -{ - acpi_create_identity_pmd(); - acpi_copy_wakeup_routine(acpi_wakeup_address); - - return 0; -} - -/** - * acpi_save_state_disk - save kernel state to disk - * - */ -int acpi_save_state_disk (void) -{ - return 1; -} - -/* - * acpi_restore_state - */ -void acpi_restore_state_mem (void) -{ - acpi_restore_pmd(); -} - -/** - * acpi_reserve_bootmem - do _very_ early ACPI initialisation - * - * We allocate a page in low memory for the wakeup - * routine for when we come back from a sleep state. The - * runtime allocator allows specification of <16M pages, but not - * <1M pages. - */ -void __init acpi_reserve_bootmem(void) -{ - acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE); - if (!acpi_wakeup_address) - printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n"); -} - -void do_suspend_lowlevel_s4bios(int resume) -{ - if (!resume) { - save_processor_context(); - acpi_save_register_state((unsigned long)&&acpi_sleep_done); - acpi_enter_sleep_state_s4bios(); - return; - } -acpi_sleep_done: - restore_processor_context(); -} - - -#endif /*CONFIG_ACPI_SLEEP*/ - diff --git a/xen/arch/x86/acpi/boot.c b/xen/arch/x86/acpi/boot.c new file mode 100644 index 0000000000..971b3d352c --- /dev/null +++ b/xen/arch/x86/acpi/boot.c @@ -0,0 +1,912 @@ +/* + * boot.c - Architecture-Specific Low-Level ACPI Boot Support + * + * Copyright (C) 2001, 2002 Paul Diefenbaugh + * Copyright (C) 2001 Jun Nakajima + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int sbf_port; /* XXX XEN */ + +#ifdef CONFIG_X86_64 + +static inline void acpi_madt_oem_check(char *oem_id, char *oem_table_id) { } +extern void __init clustered_apic_check(void); +static inline int ioapic_setup_disabled(void) { return 0; } +#include + +#else /* X86 */ + +#ifdef CONFIG_X86_LOCAL_APIC +#include +#include +#endif /* CONFIG_X86_LOCAL_APIC */ + +#endif /* X86 */ + +#define BAD_MADT_ENTRY(entry, end) ( \ + (!entry) || (unsigned long)entry + sizeof(*entry) > end || \ + ((acpi_table_entry_header *)entry)->length != sizeof(*entry)) + +#define PREFIX "ACPI: " + +#ifdef CONFIG_ACPI_PCI +int acpi_noirq __initdata; /* skip ACPI IRQ initialization */ +int acpi_pci_disabled __initdata; /* skip ACPI PCI scan and IRQ initialization */ +#else +int acpi_noirq __initdata = 1; +int acpi_pci_disabled __initdata = 1; +#endif +int acpi_ht __initdata = 1; /* enable HT */ + +int acpi_lapic; +int acpi_ioapic; +int acpi_strict; +EXPORT_SYMBOL(acpi_strict); + +acpi_interrupt_flags acpi_sci_flags __initdata; +int acpi_sci_override_gsi __initdata; +int acpi_skip_timer_override __initdata; + +#ifdef CONFIG_X86_LOCAL_APIC +static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; +#endif + +#ifndef __HAVE_ARCH_CMPXCHG +#warning ACPI uses CMPXCHG, i486 and later hardware +#endif + +#define MAX_MADT_ENTRIES 256 +u8 x86_acpiid_to_apicid[MAX_MADT_ENTRIES] = + { [0 ... MAX_MADT_ENTRIES-1] = 0xff }; +EXPORT_SYMBOL(x86_acpiid_to_apicid); + +/* -------------------------------------------------------------------------- + Boot-time Configuration + -------------------------------------------------------------------------- */ + +/* + * The default interrupt routing model is PIC (8259). This gets + * overriden if IOAPICs are enumerated (below). + */ +enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PIC; + +#ifdef CONFIG_X86_64 + +/* rely on all ACPI tables being in the direct mapping */ +char *__acpi_map_table(unsigned long phys_addr, unsigned long size) +{ + if (!phys_addr || !size) + return NULL; + + if (phys_addr < (end_pfn_map << PAGE_SHIFT)) + return __va(phys_addr); + + return NULL; +} + +#else + +/* + * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END, + * to map the target physical address. The problem is that set_fixmap() + * provides a single page, and it is possible that the page is not + * sufficient. + * By using this area, we can map up to MAX_IO_APICS pages temporarily, + * i.e. until the next __va_range() call. + * + * Important Safety Note: The fixed I/O APIC page numbers are *subtracted* + * from the fixed base. That's why we start at FIX_IO_APIC_BASE_END and + * count idx down while incrementing the phys address. + */ +char *__acpi_map_table(unsigned long phys, unsigned long size) +{ + unsigned long base, offset, mapped_size; + int idx; + + if (phys + size < 8*1024*1024) + return __va(phys); + + offset = phys & (PAGE_SIZE - 1); + mapped_size = PAGE_SIZE - offset; + set_fixmap(FIX_ACPI_END, phys); + base = fix_to_virt(FIX_ACPI_END); + + /* + * Most cases can be covered by the below. + */ + idx = FIX_ACPI_END; + while (mapped_size < size) { + if (--idx < FIX_ACPI_BEGIN) + return NULL; /* cannot handle this */ + phys += PAGE_SIZE; + set_fixmap(idx, phys); + mapped_size += PAGE_SIZE; + } + + return ((unsigned char *) base + offset); +} +#endif + +#ifdef CONFIG_PCI_MMCONFIG +static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) +{ + struct acpi_table_mcfg *mcfg; + + if (!phys_addr || !size) + return -EINVAL; + + mcfg = (struct acpi_table_mcfg *) __acpi_map_table(phys_addr, size); + if (!mcfg) { + printk(KERN_WARNING PREFIX "Unable to map MCFG\n"); + return -ENODEV; + } + + if (mcfg->base_reserved) { + printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n"); + return -ENODEV; + } + + pci_mmcfg_base_addr = mcfg->base_address; + + return 0; +} +#else +#define acpi_parse_mcfg NULL +#endif /* !CONFIG_PCI_MMCONFIG */ + +#ifdef CONFIG_X86_LOCAL_APIC +static int __init +acpi_parse_madt ( + unsigned long phys_addr, + unsigned long size) +{ + struct acpi_table_madt *madt = NULL; + + if (!phys_addr || !size) + return -EINVAL; + + madt = (struct acpi_table_madt *) __acpi_map_table(phys_addr, size); + if (!madt) { + printk(KERN_WARNING PREFIX "Unable to map MADT\n"); + return -ENODEV; + } + + if (madt->lapic_address) { + acpi_lapic_addr = (u64) madt->lapic_address; + + printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n", + madt->lapic_address); + } + + acpi_madt_oem_check(madt->header.oem_id, madt->header.oem_table_id); + + return 0; +} + + +static int __init +acpi_parse_lapic ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_lapic *processor = NULL; + + processor = (struct acpi_table_lapic*) header; + + if (BAD_MADT_ENTRY(processor, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + /* no utility in registering a disabled processor */ + if (processor->flags.enabled == 0) + return 0; + + x86_acpiid_to_apicid[processor->acpi_id] = processor->id; + + mp_register_lapic ( + processor->id, /* APIC ID */ + processor->flags.enabled); /* Enabled? */ + + return 0; +} + +static int __init +acpi_parse_lapic_addr_ovr ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_lapic_addr_ovr *lapic_addr_ovr = NULL; + + lapic_addr_ovr = (struct acpi_table_lapic_addr_ovr*) header; + + if (BAD_MADT_ENTRY(lapic_addr_ovr, end)) + return -EINVAL; + + acpi_lapic_addr = lapic_addr_ovr->address; + + return 0; +} + +static int __init +acpi_parse_lapic_nmi ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_lapic_nmi *lapic_nmi = NULL; + + lapic_nmi = (struct acpi_table_lapic_nmi*) header; + + if (BAD_MADT_ENTRY(lapic_nmi, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + if (lapic_nmi->lint != 1) + printk(KERN_WARNING PREFIX "NMI not connected to LINT 1!\n"); + + return 0; +} + + +#endif /*CONFIG_X86_LOCAL_APIC*/ + +#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_ACPI_INTERPRETER) + +static int __init +acpi_parse_ioapic ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_ioapic *ioapic = NULL; + + ioapic = (struct acpi_table_ioapic*) header; + + if (BAD_MADT_ENTRY(ioapic, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + mp_register_ioapic ( + ioapic->id, + ioapic->address, + ioapic->global_irq_base); + + return 0; +} + +/* + * Parse Interrupt Source Override for the ACPI SCI + */ +static void +acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger) +{ + if (trigger == 0) /* compatible SCI trigger is level */ + trigger = 3; + + if (polarity == 0) /* compatible SCI polarity is low */ + polarity = 3; + + /* Command-line over-ride via acpi_sci= */ + if (acpi_sci_flags.trigger) + trigger = acpi_sci_flags.trigger; + + if (acpi_sci_flags.polarity) + polarity = acpi_sci_flags.polarity; + + /* + * mp_config_acpi_legacy_irqs() already setup IRQs < 16 + * If GSI is < 16, this will update its flags, + * else it will create a new mp_irqs[] entry. + */ + mp_override_legacy_irq(gsi, polarity, trigger, gsi); + + /* + * stash over-ride to indicate we've been here + * and for later update of acpi_fadt + */ + acpi_sci_override_gsi = gsi; + return; +} + +static int __init +acpi_parse_int_src_ovr ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_int_src_ovr *intsrc = NULL; + + intsrc = (struct acpi_table_int_src_ovr*) header; + + if (BAD_MADT_ENTRY(intsrc, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + if (intsrc->bus_irq == acpi_fadt.sci_int) { + acpi_sci_ioapic_setup(intsrc->global_irq, + intsrc->flags.polarity, intsrc->flags.trigger); + return 0; + } + + if (acpi_skip_timer_override && + intsrc->bus_irq == 0 && intsrc->global_irq == 2) { + printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n"); + return 0; + } + + mp_override_legacy_irq ( + intsrc->bus_irq, + intsrc->flags.polarity, + intsrc->flags.trigger, + intsrc->global_irq); + + return 0; +} + + +static int __init +acpi_parse_nmi_src ( + acpi_table_entry_header *header, const unsigned long end) +{ + struct acpi_table_nmi_src *nmi_src = NULL; + + nmi_src = (struct acpi_table_nmi_src*) header; + + if (BAD_MADT_ENTRY(nmi_src, end)) + return -EINVAL; + + acpi_table_print_madt_entry(header); + + /* TBD: Support nimsrc entries? */ + + return 0; +} + +#endif /* CONFIG_X86_IO_APIC */ + +#ifdef CONFIG_ACPI_BUS + +/* + * acpi_pic_sci_set_trigger() + * + * use ELCR to set PIC-mode trigger type for SCI + * + * If a PIC-mode SCI is not recognized or gives spurious IRQ7's + * it may require Edge Trigger -- use "acpi_sci=edge" + * + * Port 0x4d0-4d1 are ECLR1 and ECLR2, the Edge/Level Control Registers + * for the 8259 PIC. bit[n] = 1 means irq[n] is Level, otherwise Edge. + * ECLR1 is IRQ's 0-7 (IRQ 0, 1, 2 must be 0) + * ECLR2 is IRQ's 8-15 (IRQ 8, 13 must be 0) + */ + +void __init +acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) +{ + unsigned int mask = 1 << irq; + unsigned int old, new; + + /* Real old ELCR mask */ + old = inb(0x4d0) | (inb(0x4d1) << 8); + + /* + * If we use ACPI to set PCI irq's, then we should clear ELCR + * since we will set it correctly as we enable the PCI irq + * routing. + */ + new = acpi_noirq ? old : 0; + + /* + * Update SCI information in the ELCR, it isn't in the PCI + * routing tables.. + */ + switch (trigger) { + case 1: /* Edge - clear */ + new &= ~mask; + break; + case 3: /* Level - set */ + new |= mask; + break; + } + + if (old == new) + return; + + printk(PREFIX "setting ELCR to %04x (from %04x)\n", new, old); + outb(new, 0x4d0); + outb(new >> 8, 0x4d1); +} + + +#endif /* CONFIG_ACPI_BUS */ + +int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) +{ +#ifdef CONFIG_X86_IO_APIC + if (use_pci_vector() && !platform_legacy_irq(gsi)) + *irq = IO_APIC_VECTOR(gsi); + else +#endif + *irq = gsi; + return 0; +} + +unsigned int acpi_register_gsi(u32 gsi, int edge_level, int active_high_low) +{ + unsigned int irq; + unsigned int plat_gsi = gsi; + +#ifdef CONFIG_PCI + /* + * Make sure all (legacy) PCI IRQs are set as level-triggered. + */ + if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) { + extern void eisa_set_level_irq(unsigned int irq); + + if (edge_level == ACPI_LEVEL_SENSITIVE) + eisa_set_level_irq(gsi); + } +#endif + +#ifdef CONFIG_X86_IO_APIC + if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) { + plat_gsi = mp_register_gsi(gsi, edge_level, active_high_low); + } +#endif + acpi_gsi_to_irq(plat_gsi, &irq); + return irq; +} +EXPORT_SYMBOL(acpi_register_gsi); + +/* + * ACPI based hotplug support for CPU + */ +#ifdef CONFIG_ACPI_HOTPLUG_CPU +int +acpi_map_lsapic(acpi_handle handle, int *pcpu) +{ + /* TBD */ + return -EINVAL; +} +EXPORT_SYMBOL(acpi_map_lsapic); + + +int +acpi_unmap_lsapic(int cpu) +{ + /* TBD */ + return -EINVAL; +} +EXPORT_SYMBOL(acpi_unmap_lsapic); +#endif /* CONFIG_ACPI_HOTPLUG_CPU */ + +static unsigned long __init +acpi_scan_rsdp ( + unsigned long start, + unsigned long length) +{ + unsigned long offset = 0; + unsigned long sig_len = sizeof("RSD PTR ") - 1; + + /* + * Scan all 16-byte boundaries of the physical memory region for the + * RSDP signature. + */ + for (offset = 0; offset < length; offset += 16) { + if (strncmp((char *) (start + offset), "RSD PTR ", sig_len)) + continue; + return (start + offset); + } + + return 0; +} + +static int __init acpi_parse_sbf(unsigned long phys_addr, unsigned long size) +{ + struct acpi_table_sbf *sb; + + if (!phys_addr || !size) + return -EINVAL; + + sb = (struct acpi_table_sbf *) __acpi_map_table(phys_addr, size); + if (!sb) { + printk(KERN_WARNING PREFIX "Unable to map SBF\n"); + return -ENODEV; + } + + sbf_port = sb->sbf_cmos; /* Save CMOS port */ + + return 0; +} + + +#ifdef CONFIG_HPET_TIMER + +static int __init acpi_parse_hpet(unsigned long phys, unsigned long size) +{ + struct acpi_table_hpet *hpet_tbl; + + if (!phys || !size) + return -EINVAL; + + hpet_tbl = (struct acpi_table_hpet *) __acpi_map_table(phys, size); + if (!hpet_tbl) { + printk(KERN_WARNING PREFIX "Unable to map HPET\n"); + return -ENODEV; + } + + if (hpet_tbl->addr.space_id != ACPI_SPACE_MEM) { + printk(KERN_WARNING PREFIX "HPET timers must be located in " + "memory.\n"); + return -1; + } + +#ifdef CONFIG_X86_64 + vxtime.hpet_address = hpet_tbl->addr.addrl | + ((long) hpet_tbl->addr.addrh << 32); + + printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", + hpet_tbl->id, vxtime.hpet_address); +#else /* X86 */ + { + extern unsigned long hpet_address; + + hpet_address = hpet_tbl->addr.addrl; + printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n", + hpet_tbl->id, hpet_address); + } +#endif /* X86 */ + + return 0; +} +#else +#define acpi_parse_hpet NULL +#endif + +#ifdef CONFIG_X86_PM_TIMER +extern u32 pmtmr_ioport; +#endif + +static int __init acpi_parse_fadt(unsigned long phys, unsigned long size) +{ + struct fadt_descriptor_rev2 *fadt = NULL; + + fadt = (struct fadt_descriptor_rev2*) __acpi_map_table(phys,size); + if(!fadt) { + printk(KERN_WARNING PREFIX "Unable to map FADT\n"); + return 0; + } + +#ifdef CONFIG_ACPI_INTERPRETER + /* initialize sci_int early for INT_SRC_OVR MADT parsing */ + acpi_fadt.sci_int = fadt->sci_int; +#endif + +#ifdef CONFIG_X86_PM_TIMER + /* detect the location of the ACPI PM Timer */ + if (fadt->revision >= FADT2_REVISION_ID) { + /* FADT rev. 2 */ + if (fadt->xpm_tmr_blk.address_space_id != ACPI_ADR_SPACE_SYSTEM_IO) + return 0; + + pmtmr_ioport = fadt->xpm_tmr_blk.address; + } else { + /* FADT rev. 1 */ + pmtmr_ioport = fadt->V1_pm_tmr_blk; + } + if (pmtmr_ioport) + printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n", pmtmr_ioport); +#endif + return 0; +} + + +unsigned long __init +acpi_find_rsdp (void) +{ + unsigned long rsdp_phys = 0; + +#if 0 + if (efi_enabled) { + if (efi.acpi20) + return __pa(efi.acpi20); + else if (efi.acpi) + return __pa(efi.acpi); + } +#endif + /* + * Scan memory looking for the RSDP signature. First search EBDA (low + * memory) paragraphs and then search upper memory (E0000-FFFFF). + */ + rsdp_phys = acpi_scan_rsdp (0, 0x400); + if (!rsdp_phys) + rsdp_phys = acpi_scan_rsdp (0xE0000, 0xFFFFF); + + return rsdp_phys; +} + +#ifdef CONFIG_X86_LOCAL_APIC +/* + * Parse LAPIC entries in MADT + * returns 0 on success, < 0 on error + */ +static int __init +acpi_parse_madt_lapic_entries(void) +{ + int count; + + /* + * Note that the LAPIC address is obtained from the MADT (32-bit value) + * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value). + */ + + count = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0); + if (count < 0) { + printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); + return count; + } + + mp_register_lapic_address(acpi_lapic_addr); + + count = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic, + MAX_APICS); + if (!count) { + printk(KERN_ERR PREFIX "No LAPIC entries present\n"); + /* TBD: Cleanup to allow fallback to MPS */ + return -ENODEV; + } + else if (count < 0) { + printk(KERN_ERR PREFIX "Error parsing LAPIC entry\n"); + /* TBD: Cleanup to allow fallback to MPS */ + return count; + } + + count = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0); + if (count < 0) { + printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); + /* TBD: Cleanup to allow fallback to MPS */ + return count; + } + return 0; +} +#endif /* CONFIG_X86_LOCAL_APIC */ + +#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_ACPI_INTERPRETER) +/* + * Parse IOAPIC related entries in MADT + * returns 0 on success, < 0 on error + */ +static int __init +acpi_parse_madt_ioapic_entries(void) +{ + int count; + + /* + * ACPI interpreter is required to complete interrupt setup, + * so if it is off, don't enumerate the io-apics with ACPI. + * If MPS is present, it will handle them, + * otherwise the system will stay in PIC mode + */ + if (acpi_disabled || acpi_noirq) { + return -ENODEV; + } + + /* + * if "noapic" boot option, don't look for IO-APICs + */ + if (skip_ioapic_setup) { + printk(KERN_INFO PREFIX "Skipping IOAPIC probe " + "due to 'noapic' option.\n"); + return -ENODEV; + } + + count = acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic, MAX_IO_APICS); + if (!count) { + printk(KERN_ERR PREFIX "No IOAPIC entries present\n"); + return -ENODEV; + } + else if (count < 0) { + printk(KERN_ERR PREFIX "Error parsing IOAPIC entry\n"); + return count; + } + + count = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, NR_IRQ_VECTORS); + if (count < 0) { + printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); + /* TBD: Cleanup to allow fallback to MPS */ + return count; + } + + /* + * If BIOS did not supply an INT_SRC_OVR for the SCI + * pretend we got one so we can set the SCI flags. + */ + if (!acpi_sci_override_gsi) + acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0); + + /* Fill in identity legacy mapings where no override */ + mp_config_acpi_legacy_irqs(); + + count = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, NR_IRQ_VECTORS); + if (count < 0) { + printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); + /* TBD: Cleanup to allow fallback to MPS */ + return count; + } + + return 0; +} +#else +static inline int acpi_parse_madt_ioapic_entries(void) +{ + return -1; +} +#endif /* !(CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER) */ + + +static void __init +acpi_process_madt(void) +{ +#ifdef CONFIG_X86_LOCAL_APIC + int count, error; + + count = acpi_table_parse(ACPI_APIC, acpi_parse_madt); + if (count >= 1) { + + /* + * Parse MADT LAPIC entries + */ + error = acpi_parse_madt_lapic_entries(); + if (!error) { + acpi_lapic = 1; + + /* + * Parse MADT IO-APIC entries + */ + error = acpi_parse_madt_ioapic_entries(); + if (!error) { + acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; + acpi_irq_balance_set(NULL); + acpi_ioapic = 1; + + smp_found_config = 1; + clustered_apic_check(); + } + } + if (error == -EINVAL) { + /* + * Dell Precision Workstation 410, 610 come here. + */ + printk(KERN_ERR PREFIX "Invalid BIOS MADT, disabling ACPI\n"); + disable_acpi(); + } + } +#endif + return; +} + +/* + * acpi_boot_table_init() and acpi_boot_init() + * called from setup_arch(), always. + * 1. checksums all tables + * 2. enumerates lapics + * 3. enumerates io-apics + * + * acpi_table_init() is separate to allow reading SRAT without + * other side effects. + * + * side effects of acpi_boot_init: + * acpi_lapic = 1 if LAPIC found + * acpi_ioapic = 1 if IOAPIC found + * if (acpi_lapic && acpi_ioapic) smp_found_config = 1; + * if acpi_blacklisted() acpi_disabled = 1; + * acpi_irq_model=... + * ... + * + * return value: (currently ignored) + * 0: success + * !0: failure + */ + +int __init +acpi_boot_table_init(void) +{ + int error; + + /* + * If acpi_disabled, bail out + * One exception: acpi=ht continues far enough to enumerate LAPICs + */ + if (acpi_disabled && !acpi_ht) + return 1; + + /* + * Initialize the ACPI boot-time table parser. + */ + error = acpi_table_init(); + if (error) { + disable_acpi(); + return error; + } + +#if 0 /*def __i386__*/ + check_acpi_pci(); +#endif + + acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); + + /* + * blacklist may disable ACPI entirely + */ + error = acpi_blacklisted(); + if (error) { + extern int acpi_force; + + if (acpi_force) { + printk(KERN_WARNING PREFIX "acpi=force override\n"); + } else { + printk(KERN_WARNING PREFIX "Disabling ACPI support\n"); + disable_acpi(); + return error; + } + } + + return 0; +} + + +int __init acpi_boot_init(void) +{ + /* + * If acpi_disabled, bail out + * One exception: acpi=ht continues far enough to enumerate LAPICs + */ + if (acpi_disabled && !acpi_ht) + return 1; + + acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); + + /* + * set sci_int and PM timer address + */ + acpi_table_parse(ACPI_FADT, acpi_parse_fadt); + + /* + * Process the Multiple APIC Description Table (MADT), if present + */ + acpi_process_madt(); + + acpi_table_parse(ACPI_HPET, acpi_parse_hpet); + acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg); + + return 0; +} + diff --git a/xen/arch/x86/apic.c b/xen/arch/x86/apic.c index 766a10ed7c..f368608635 100644 --- a/xen/arch/x86/apic.c +++ b/xen/arch/x86/apic.c @@ -34,14 +34,27 @@ #include #include #include -#include -#include +#include +#include /* Using APIC to generate smp_local_timer_interrupt? */ int using_apic_timer = 0; +int apic_verbosity; + static int enabled_via_apicbase; +int get_physical_broadcast(void) +{ + unsigned int lvr, version; + lvr = apic_read(APIC_LVR); + version = GET_APIC_VERSION(lvr); + if (!APIC_INTEGRATED(version) || version >= 0x14) + return 0xff; + else + return 0xf; +} + int get_maxlvt(void) { unsigned int v, ver, maxlvt; @@ -907,7 +920,7 @@ int __init APIC_init_uniprocessor (void) #ifdef CONFIG_SMP cpu_online_map = 1; #endif - phys_cpu_present_map = 1; + phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid); apic_write_around(APIC_ID, boot_cpu_physical_apicid); setup_local_APIC(); diff --git a/xen/arch/x86/i8259.c b/xen/arch/x86/i8259.c index 62eb07ada0..8111260050 100644 --- a/xen/arch/x86/i8259.c +++ b/xen/arch/x86/i8259.c @@ -45,7 +45,7 @@ BUILD_COMMON_IRQ() /* * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts: - * (these are usually mapped to vectors 0x30-0x3f) + * (these are usually mapped to vectors 0x20-0x2f) */ BUILD_16_IRQS(0x0) @@ -58,7 +58,7 @@ BUILD_16_IRQS(0x0) * of these. Plus, more powerful systems might have more than 64 * IO-APIC registers. * - * (these are usually mapped into the 0x30-0xff vector range) + * (these are usually mapped into the 0x20-0xff vector range) */ BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3) BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7) @@ -101,7 +101,7 @@ BUILD_SMP_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \ IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f) - void *interrupt[NR_IRQS] = { + void (*interrupt[NR_IRQS])(void) = { IRQLIST_16(0x0), #ifdef CONFIG_X86_IO_APIC @@ -341,7 +341,7 @@ void __init init_8259A(int auto_eoi) * outb_p - this has to work on a wide range of PC hardware. */ outb_p(0x11, 0x20); /* ICW1: select 8259A-1 init */ - outb_p(0x30 + 0, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x30-0x37 */ + outb_p(0x20 + 0, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */ outb_p(0x04, 0x21); /* 8259A-1 (the master) has a slave on IR2 */ if (auto_eoi) outb_p(0x03, 0x21); /* master does Auto EOI */ @@ -349,7 +349,7 @@ void __init init_8259A(int auto_eoi) outb_p(0x01, 0x21); /* master expects normal EOI */ outb_p(0x11, 0xA0); /* ICW1: select 8259A-2 init */ - outb_p(0x30 + 8, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x38-0x3f */ + outb_p(0x20 + 8, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */ outb_p(0x02, 0xA1); /* 8259A-2 is a slave on master's IR2 */ outb_p(0x01, 0xA1); /* (slave's support for AEOI in flat mode is to be investigated) */ diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c index 5ed95ff5f8..929117c95c 100644 --- a/xen/arch/x86/io_apic.c +++ b/xen/arch/x86/io_apic.c @@ -25,26 +25,20 @@ #include #include #include -#include -#include +#include #include -#include -#include +#include #include #include -#include +#include +#include -#ifdef CONFIG_X86_IO_APIC +int (*ioapic_renumber_irq)(int ioapic, int irq); +atomic_t irq_mis_count; -#undef APIC_LOCKUP_DEBUG - -#define APIC_LOCKUP_DEBUG - -static spinlock_t ioapic_lock = SPIN_LOCK_UNLOCKED; - -unsigned int int_dest_addr_mode = APIC_DEST_LOGICAL; -unsigned char int_delivery_mode = dest_LowestPrio; +static DEFINE_SPINLOCK(ioapic_lock); +int skip_ioapic_setup; /* * # of IRQ routing registers @@ -69,12 +63,20 @@ static struct irq_pin_list { int apic, pin, next; } irq_2_pin[PIN_MAP_SIZE]; +int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; +#ifdef CONFIG_PCI_MSI +#define vector_to_irq(vector) \ + (platform_legacy_irq(vector) ? vector : vector_irq[vector]) +#else +#define vector_to_irq(vector) (vector) +#endif + /* * The common case is 1:1 IRQ<->pin mappings. Sometimes there are * shared ISA-space IRQs, so we have to support them. We are super * fast in the common case, and fast for shared ISA-space IRQs. */ -static void __init add_pin_to_irq(unsigned int irq, int apic, int pin) +static void add_pin_to_irq(unsigned int irq, int apic, int pin) { static int first_free_entry = NR_IRQS; struct irq_pin_list *entry = irq_2_pin + irq; @@ -112,36 +114,48 @@ static void __init replace_pin_at_irq(unsigned int irq, } } -#define __DO_ACTION(R, ACTION, FINAL) \ - \ -{ \ - int pin; \ - struct irq_pin_list *entry = irq_2_pin + irq; \ - \ - for (;;) { \ - unsigned int reg; \ - pin = entry->pin; \ - if (pin == -1) \ - break; \ - reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \ - reg ACTION; \ - io_apic_write(entry->apic, 0x10 + R + pin*2, reg); \ - if (!entry->next) \ - break; \ - entry = irq_2_pin + entry->next; \ - } \ - FINAL; \ +static void __modify_IO_APIC_irq (unsigned int irq, unsigned long enable, unsigned long disable) +{ + struct irq_pin_list *entry = irq_2_pin + irq; + unsigned int pin, reg; + + for (;;) { + pin = entry->pin; + if (pin == -1) + break; + reg = io_apic_read(entry->apic, 0x10 + pin*2); + reg &= ~disable; + reg |= enable; + io_apic_modify(entry->apic, 0x10 + pin*2, reg); + if (!entry->next) + break; + entry = irq_2_pin + entry->next; + } } -#define DO_ACTION(name,R,ACTION, FINAL) \ - \ - static void name##_IO_APIC_irq (unsigned int irq) \ - __DO_ACTION(R, ACTION, FINAL) +/* mask = 1 */ +static void __mask_IO_APIC_irq (unsigned int irq) +{ + __modify_IO_APIC_irq(irq, 0x00010000, 0); +} -DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic) ) -DO_ACTION( __unmask, 0, &= 0xfffeffff, ) -DO_ACTION( __edge, 0, &= 0xffff7fff, ) -DO_ACTION( __level, 0, |= 0x00008000, ) +/* mask = 0 */ +static void __unmask_IO_APIC_irq (unsigned int irq) +{ + __modify_IO_APIC_irq(irq, 0, 0x00010000); +} + +/* mask = 1, trigger = 0 */ +static void __mask_and_edge_IO_APIC_irq (unsigned int irq) +{ + __modify_IO_APIC_irq(irq, 0x00010000, 0x00008000); +} + +/* mask = 0, trigger = 1 */ +static void __unmask_and_level_IO_APIC_irq (unsigned int irq) +{ + __modify_IO_APIC_irq(irq, 0x00008000, 0x00010000); +} static void mask_IO_APIC_irq (unsigned int irq) { @@ -165,7 +179,7 @@ void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) { struct IO_APIC_route_entry entry; unsigned long flags; - + /* Check delivery_mode to be sure we're not clearing an SMI pin */ spin_lock_irqsave(&ioapic_lock, flags); *(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin); @@ -194,85 +208,467 @@ static void clear_IO_APIC (void) clear_IO_APIC_pin(apic, pin); } -static void set_ioapic_affinity (unsigned int irq, unsigned long mask) +static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) { unsigned long flags; - - /* - * Only the first 8 bits are valid. - */ - mask = mask << 24; + int pin; + struct irq_pin_list *entry = irq_2_pin + irq; + unsigned int apicid_value; + + apicid_value = cpu_mask_to_apicid(cpumask); + /* Prepare to do the io_apic_write */ + apicid_value = apicid_value << 24; spin_lock_irqsave(&ioapic_lock, flags); - __DO_ACTION(1, = mask, ) + for (;;) { + pin = entry->pin; + if (pin == -1) + break; + io_apic_write(entry->apic, 0x10 + 1 + pin*2, apicid_value); + if (!entry->next) + break; + entry = irq_2_pin + entry->next; + } spin_unlock_irqrestore(&ioapic_lock, flags); } -#define balance_irq(_irq) ((void)0) +#if defined(CONFIG_IRQBALANCE) +# include /* kernel_thread() */ +# include /* kstat */ +# include /* kmalloc() */ +# include /* time_after() */ + +# ifdef CONFIG_BALANCED_IRQ_DEBUG +# define TDprintk(x...) do { printk("<%ld:%s:%d>: ", jiffies, __FILE__, __LINE__); printk(x); } while (0) +# define Dprintk(x...) do { TDprintk(x); } while (0) +# else +# define TDprintk(x...) +# define Dprintk(x...) +# endif -/* - * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to - * specific CPU-side IRQs. - */ +cpumask_t __cacheline_aligned pending_irq_balance_cpumask[NR_IRQS]; -#define MAX_PIRQS 8 -int pirq_entries [MAX_PIRQS]; -int pirqs_enabled; +#define IRQBALANCE_CHECK_ARCH -999 +static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH; +static int physical_balance = 0; -int skip_ioapic_setup; -#if 0 +struct irq_cpu_info { + unsigned long * last_irq; + unsigned long * irq_delta; + unsigned long irq; +} irq_cpu_data[NR_CPUS]; -static int __init noioapic_setup(char *str) +#define CPU_IRQ(cpu) (irq_cpu_data[cpu].irq) +#define LAST_CPU_IRQ(cpu,irq) (irq_cpu_data[cpu].last_irq[irq]) +#define IRQ_DELTA(cpu,irq) (irq_cpu_data[cpu].irq_delta[irq]) + +#define IDLE_ENOUGH(cpu,now) \ + (idle_cpu(cpu) && ((now) - irq_stat[(cpu)].idle_timestamp > 1)) + +#define IRQ_ALLOWED(cpu, allowed_mask) cpu_isset(cpu, allowed_mask) + +#define CPU_TO_PACKAGEINDEX(i) (first_cpu(cpu_sibling_map[i])) + +#define MAX_BALANCED_IRQ_INTERVAL (5*HZ) +#define MIN_BALANCED_IRQ_INTERVAL (HZ/2) +#define BALANCED_IRQ_MORE_DELTA (HZ/10) +#define BALANCED_IRQ_LESS_DELTA (HZ) + +long balanced_irq_interval = MAX_BALANCED_IRQ_INTERVAL; + +static unsigned long move(int curr_cpu, cpumask_t allowed_mask, + unsigned long now, int direction) { - skip_ioapic_setup = 1; - return 1; + int search_idle = 1; + int cpu = curr_cpu; + + goto inside; + + do { + if (unlikely(cpu == curr_cpu)) + search_idle = 0; +inside: + if (direction == 1) { + cpu++; + if (cpu >= NR_CPUS) + cpu = 0; + } else { + cpu--; + if (cpu == -1) + cpu = NR_CPUS-1; + } + } while (!cpu_online(cpu) || !IRQ_ALLOWED(cpu,allowed_mask) || + (search_idle && !IDLE_ENOUGH(cpu,now))); + + return cpu; } -__setup("noapic", noioapic_setup); - -static int __init ioapic_setup(char *str) +static inline void balance_irq(int cpu, int irq) { - skip_ioapic_setup = 0; - return 1; -} + unsigned long now = jiffies; + cpumask_t allowed_mask; + unsigned int new_cpu; + + if (irqbalance_disabled) + return; -__setup("apic", ioapic_setup); + cpus_and(allowed_mask, cpu_online_map, irq_affinity[irq]); + new_cpu = move(cpu, allowed_mask, now, 1); + if (cpu != new_cpu) { + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; - - -static int __init ioapic_pirq_setup(char *str) -{ - int i, max; - int ints[MAX_PIRQS+1]; - - get_options(str, ARRAY_SIZE(ints), ints); - - for (i = 0; i < MAX_PIRQS; i++) - pirq_entries[i] = -1; - - pirqs_enabled = 1; - printk(KERN_INFO "PIRQ redirection, working around broken MP-BIOS.\n"); - max = MAX_PIRQS; - if (ints[0] < MAX_PIRQS) - max = ints[0]; - - for (i = 0; i < max; i++) { - printk(KERN_DEBUG "... PIRQ%d -> IRQ %d\n", i, ints[i+1]); - /* - * PIRQs are mapped upside down, usually. - */ - pirq_entries[MAX_PIRQS-i-1] = ints[i+1]; + spin_lock_irqsave(&desc->lock, flags); + pending_irq_balance_cpumask[irq] = cpumask_of_cpu(new_cpu); + spin_unlock_irqrestore(&desc->lock, flags); } - return 1; } -__setup("pirq=", ioapic_pirq_setup); +static inline void rotate_irqs_among_cpus(unsigned long useful_load_threshold) +{ + int i, j; + Dprintk("Rotating IRQs among CPUs.\n"); + for (i = 0; i < NR_CPUS; i++) { + for (j = 0; cpu_online(i) && (j < NR_IRQS); j++) { + if (!irq_desc[j].action) + continue; + /* Is it a significant load ? */ + if (IRQ_DELTA(CPU_TO_PACKAGEINDEX(i),j) < + useful_load_threshold) + continue; + balance_irq(i, j); + } + } + balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL, + balanced_irq_interval - BALANCED_IRQ_LESS_DELTA); + return; +} -#endif +static void do_irq_balance(void) +{ + int i, j; + unsigned long max_cpu_irq = 0, min_cpu_irq = (~0); + unsigned long move_this_load = 0; + int max_loaded = 0, min_loaded = 0; + int load; + unsigned long useful_load_threshold = balanced_irq_interval + 10; + int selected_irq; + int tmp_loaded, first_attempt = 1; + unsigned long tmp_cpu_irq; + unsigned long imbalance = 0; + cpumask_t allowed_mask, target_cpu_mask, tmp; + + for (i = 0; i < NR_CPUS; i++) { + int package_index; + CPU_IRQ(i) = 0; + if (!cpu_online(i)) + continue; + package_index = CPU_TO_PACKAGEINDEX(i); + for (j = 0; j < NR_IRQS; j++) { + unsigned long value_now, delta; + /* Is this an active IRQ? */ + if (!irq_desc[j].action) + continue; + if ( package_index == i ) + IRQ_DELTA(package_index,j) = 0; + /* Determine the total count per processor per IRQ */ + value_now = (unsigned long) kstat_cpu(i).irqs[j]; + + /* Determine the activity per processor per IRQ */ + delta = value_now - LAST_CPU_IRQ(i,j); + + /* Update last_cpu_irq[][] for the next time */ + LAST_CPU_IRQ(i,j) = value_now; + + /* Ignore IRQs whose rate is less than the clock */ + if (delta < useful_load_threshold) + continue; + /* update the load for the processor or package total */ + IRQ_DELTA(package_index,j) += delta; + + /* Keep track of the higher numbered sibling as well */ + if (i != package_index) + CPU_IRQ(i) += delta; + /* + * We have sibling A and sibling B in the package + * + * cpu_irq[A] = load for cpu A + load for cpu B + * cpu_irq[B] = load for cpu B + */ + CPU_IRQ(package_index) += delta; + } + } + /* Find the least loaded processor package */ + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; + if (i != CPU_TO_PACKAGEINDEX(i)) + continue; + if (min_cpu_irq > CPU_IRQ(i)) { + min_cpu_irq = CPU_IRQ(i); + min_loaded = i; + } + } + max_cpu_irq = ULONG_MAX; + +tryanothercpu: + /* Look for heaviest loaded processor. + * We may come back to get the next heaviest loaded processor. + * Skip processors with trivial loads. + */ + tmp_cpu_irq = 0; + tmp_loaded = -1; + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; + if (i != CPU_TO_PACKAGEINDEX(i)) + continue; + if (max_cpu_irq <= CPU_IRQ(i)) + continue; + if (tmp_cpu_irq < CPU_IRQ(i)) { + tmp_cpu_irq = CPU_IRQ(i); + tmp_loaded = i; + } + } + + if (tmp_loaded == -1) { + /* In the case of small number of heavy interrupt sources, + * loading some of the cpus too much. We use Ingo's original + * approach to rotate them around. + */ + if (!first_attempt && imbalance >= useful_load_threshold) { + rotate_irqs_among_cpus(useful_load_threshold); + return; + } + goto not_worth_the_effort; + } + + first_attempt = 0; /* heaviest search */ + max_cpu_irq = tmp_cpu_irq; /* load */ + max_loaded = tmp_loaded; /* processor */ + imbalance = (max_cpu_irq - min_cpu_irq) / 2; + + Dprintk("max_loaded cpu = %d\n", max_loaded); + Dprintk("min_loaded cpu = %d\n", min_loaded); + Dprintk("max_cpu_irq load = %ld\n", max_cpu_irq); + Dprintk("min_cpu_irq load = %ld\n", min_cpu_irq); + Dprintk("load imbalance = %lu\n", imbalance); + + /* if imbalance is less than approx 10% of max load, then + * observe diminishing returns action. - quit + */ + if (imbalance < (max_cpu_irq >> 3)) { + Dprintk("Imbalance too trivial\n"); + goto not_worth_the_effort; + } + +tryanotherirq: + /* if we select an IRQ to move that can't go where we want, then + * see if there is another one to try. + */ + move_this_load = 0; + selected_irq = -1; + for (j = 0; j < NR_IRQS; j++) { + /* Is this an active IRQ? */ + if (!irq_desc[j].action) + continue; + if (imbalance <= IRQ_DELTA(max_loaded,j)) + continue; + /* Try to find the IRQ that is closest to the imbalance + * without going over. + */ + if (move_this_load < IRQ_DELTA(max_loaded,j)) { + move_this_load = IRQ_DELTA(max_loaded,j); + selected_irq = j; + } + } + if (selected_irq == -1) { + goto tryanothercpu; + } + + imbalance = move_this_load; + + /* For physical_balance case, we accumlated both load + * values in the one of the siblings cpu_irq[], + * to use the same code for physical and logical processors + * as much as possible. + * + * NOTE: the cpu_irq[] array holds the sum of the load for + * sibling A and sibling B in the slot for the lowest numbered + * sibling (A), _AND_ the load for sibling B in the slot for + * the higher numbered sibling. + * + * We seek the least loaded sibling by making the comparison + * (A+B)/2 vs B + */ + load = CPU_IRQ(min_loaded) >> 1; + for_each_cpu_mask(j, cpu_sibling_map[min_loaded]) { + if (load > CPU_IRQ(j)) { + /* This won't change cpu_sibling_map[min_loaded] */ + load = CPU_IRQ(j); + min_loaded = j; + } + } + + cpus_and(allowed_mask, cpu_online_map, irq_affinity[selected_irq]); + target_cpu_mask = cpumask_of_cpu(min_loaded); + cpus_and(tmp, target_cpu_mask, allowed_mask); + + if (!cpus_empty(tmp)) { + irq_desc_t *desc = irq_desc + selected_irq; + unsigned long flags; + + Dprintk("irq = %d moved to cpu = %d\n", + selected_irq, min_loaded); + /* mark for change destination */ + spin_lock_irqsave(&desc->lock, flags); + pending_irq_balance_cpumask[selected_irq] = + cpumask_of_cpu(min_loaded); + spin_unlock_irqrestore(&desc->lock, flags); + /* Since we made a change, come back sooner to + * check for more variation. + */ + balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL, + balanced_irq_interval - BALANCED_IRQ_LESS_DELTA); + return; + } + goto tryanotherirq; + +not_worth_the_effort: + /* + * if we did not find an IRQ to move, then adjust the time interval + * upward + */ + balanced_irq_interval = min((long)MAX_BALANCED_IRQ_INTERVAL, + balanced_irq_interval + BALANCED_IRQ_MORE_DELTA); + Dprintk("IRQ worth rotating not found\n"); + return; +} + +static int balanced_irq(void *unused) +{ + int i; + unsigned long prev_balance_time = jiffies; + long time_remaining = balanced_irq_interval; + + daemonize("kirqd"); + + /* push everything to CPU 0 to give us a starting point. */ + for (i = 0 ; i < NR_IRQS ; i++) { + pending_irq_balance_cpumask[i] = cpumask_of_cpu(0); + } + + for ( ; ; ) { + set_current_state(TASK_INTERRUPTIBLE); + time_remaining = schedule_timeout(time_remaining); + try_to_freeze(PF_FREEZE); + if (time_after(jiffies, + prev_balance_time+balanced_irq_interval)) { + do_irq_balance(); + prev_balance_time = jiffies; + time_remaining = balanced_irq_interval; + } + } + return 0; +} + +static int __init balanced_irq_init(void) +{ + int i; + struct cpuinfo_x86 *c; + cpumask_t tmp; + + cpus_shift_right(tmp, cpu_online_map, 2); + c = &boot_cpu_data; + /* When not overwritten by the command line ask subarchitecture. */ + if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH) + irqbalance_disabled = NO_BALANCE_IRQ; + if (irqbalance_disabled) + return 0; + + /* disable irqbalance completely if there is only one processor online */ + if (num_online_cpus() < 2) { + irqbalance_disabled = 1; + return 0; + } + /* + * Enable physical balance only if more than 1 physical processor + * is present + */ + if (smp_num_siblings > 1 && !cpus_empty(tmp)) + physical_balance = 1; + + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; + irq_cpu_data[i].irq_delta = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL); + irq_cpu_data[i].last_irq = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL); + if (irq_cpu_data[i].irq_delta == NULL || irq_cpu_data[i].last_irq == NULL) { + printk(KERN_ERR "balanced_irq_init: out of memory"); + goto failed; + } + memset(irq_cpu_data[i].irq_delta,0,sizeof(unsigned long) * NR_IRQS); + memset(irq_cpu_data[i].last_irq,0,sizeof(unsigned long) * NR_IRQS); + } + + printk(KERN_INFO "Starting balanced_irq\n"); + if (kernel_thread(balanced_irq, NULL, CLONE_KERNEL) >= 0) + return 0; + else + printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq"); +failed: + for (i = 0; i < NR_CPUS; i++) { + if(irq_cpu_data[i].irq_delta) + kfree(irq_cpu_data[i].irq_delta); + if(irq_cpu_data[i].last_irq) + kfree(irq_cpu_data[i].last_irq); + } + return 0; +} + +int __init irqbalance_disable(char *str) +{ + irqbalance_disabled = 1; + return 0; +} + +__setup("noirqbalance", irqbalance_disable); + +static inline void move_irq(int irq) +{ + /* note - we hold the desc->lock */ + if (unlikely(!cpus_empty(pending_irq_balance_cpumask[irq]))) { + set_ioapic_affinity_irq(irq, pending_irq_balance_cpumask[irq]); + cpus_clear(pending_irq_balance_cpumask[irq]); + } +} + +late_initcall(balanced_irq_init); + +#else /* !CONFIG_IRQBALANCE */ +static inline void move_irq(int irq) { } +#endif /* CONFIG_IRQBALANCE */ + +#ifndef CONFIG_SMP +void fastcall send_IPI_self(int vector) +{ + unsigned int cfg; + + /* + * Wait for idle. + */ + apic_wait_icr_idle(); + cfg = APIC_DM_FIXED | APIC_DEST_SELF | vector | APIC_DEST_LOGICAL; + /* + * Send the IPI. The write to APIC_ICR fires this off. + */ + apic_write_around(APIC_ICR, cfg); +} +#endif /* !CONFIG_SMP */ /* * Find the IRQ entry number of a certain pin. */ -static int __init find_irq_entry(int apic, int pin, int type) +static int find_irq_entry(int apic, int pin, int type) { int i; @@ -289,7 +685,7 @@ static int __init find_irq_entry(int apic, int pin, int type) /* * Find the pin to which IRQ[irq] (ISA) is connected */ -static int __init find_isa_irq_pin(int irq, int type) +static int find_isa_irq_pin(int irq, int type) { int i; @@ -298,7 +694,9 @@ static int __init find_isa_irq_pin(int irq, int type) if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA || mp_bus_id_to_type[lbus] == MP_BUS_EISA || - mp_bus_id_to_type[lbus] == MP_BUS_MCA) && + mp_bus_id_to_type[lbus] == MP_BUS_MCA || + mp_bus_id_to_type[lbus] == MP_BUS_NEC98 + ) && (mp_irqs[i].mpc_irqtype == type) && (mp_irqs[i].mpc_srcbusirq == irq)) @@ -313,16 +711,81 @@ static int __init find_isa_irq_pin(int irq, int type) */ static int pin_2_irq(int idx, int apic, int pin); +int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) +{ + int apic, i, best_guess = -1; + + apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, " + "slot:%d, pin:%d.\n", bus, slot, pin); + if (mp_bus_id_to_pci_bus[bus] == -1) { + printk(KERN_WARNING "PCI BIOS passed nonexistent PCI bus %d!\n", bus); + return -1; + } + for (i = 0; i < mp_irq_entries; i++) { + int lbus = mp_irqs[i].mpc_srcbus; + + for (apic = 0; apic < nr_ioapics; apic++) + if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic || + mp_irqs[i].mpc_dstapic == MP_APIC_ALL) + break; + + if ((mp_bus_id_to_type[lbus] == MP_BUS_PCI) && + !mp_irqs[i].mpc_irqtype && + (bus == lbus) && + (slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f))) { + int irq = pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq); + + if (!(apic || IO_APIC_IRQ(irq))) + continue; + + if (pin == (mp_irqs[i].mpc_srcbusirq & 3)) + return irq; + /* + * Use the first all-but-pin matching entry as a + * best-guess fuzzy result for broken mptables. + */ + if (best_guess < 0) + best_guess = irq; + } + } + return best_guess; +} + +/* + * This function currently is only a helper for the i386 smp boot process where + * we need to reprogram the ioredtbls to cater for the cpus which have come online + * so mask in all cases should simply be TARGET_CPUS + */ +void __init setup_ioapic_dest(void) +{ + int pin, ioapic, irq, irq_entry; + + if (skip_ioapic_setup == 1) + return; + + for (ioapic = 0; ioapic < nr_ioapics; ioapic++) { + for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) { + irq_entry = find_irq_entry(ioapic, pin, mp_INT); + if (irq_entry == -1) + continue; + irq = pin_2_irq(irq_entry, ioapic, pin); + set_ioapic_affinity_irq(irq, TARGET_CPUS); + } + + } +} + /* * EISA Edge/Level control register, ELCR */ -static int __init EISA_ELCR(unsigned int irq) +static int EISA_ELCR(unsigned int irq) { if (irq < 16) { unsigned int port = 0x4d0 + (irq >> 3); return (inb(port) >> (irq & 7)) & 1; } - printk(KERN_INFO "Broken MPtable reports ISA irq %d\n", irq); + apic_printk(APIC_VERBOSE, KERN_INFO + "Broken MPtable reports ISA irq %d\n", irq); return 0; } @@ -352,6 +815,12 @@ static int __init EISA_ELCR(unsigned int irq) #define default_MCA_trigger(idx) (1) #define default_MCA_polarity(idx) (0) +/* NEC98 interrupts are always polarity zero edge triggered, + * when listed as conforming in the MP table. */ + +#define default_NEC98_trigger(idx) (0) +#define default_NEC98_polarity(idx) (0) + static int __init MPBIOS_polarity(int idx) { int bus = mp_irqs[idx].mpc_srcbus; @@ -386,6 +855,11 @@ static int __init MPBIOS_polarity(int idx) polarity = default_MCA_polarity(idx); break; } + case MP_BUS_NEC98: /* NEC 98 pin */ + { + polarity = default_NEC98_polarity(idx); + break; + } default: { printk(KERN_WARNING "broken BIOS!!\n"); @@ -421,7 +895,7 @@ static int __init MPBIOS_polarity(int idx) return polarity; } -static int __init MPBIOS_trigger(int idx) +static int MPBIOS_trigger(int idx) { int bus = mp_irqs[idx].mpc_srcbus; int trigger; @@ -455,6 +929,11 @@ static int __init MPBIOS_trigger(int idx) trigger = default_MCA_trigger(idx); break; } + case MP_BUS_NEC98: /* NEC 98 pin */ + { + trigger = default_NEC98_trigger(idx); + break; + } default: { printk(KERN_WARNING "broken BIOS!!\n"); @@ -516,6 +995,7 @@ static int pin_2_irq(int idx, int apic, int pin) case MP_BUS_ISA: /* ISA pin */ case MP_BUS_EISA: case MP_BUS_MCA: + case MP_BUS_NEC98: { irq = mp_irqs[idx].mpc_srcbusirq; break; @@ -529,6 +1009,13 @@ static int pin_2_irq(int idx, int apic, int pin) while (i < apic) irq += nr_ioapic_registers[i++]; irq += pin; + + /* + * For MPS mode, so far only needed by ES7000 platform + */ + if (ioapic_renumber_irq) + irq = ioapic_renumber_irq(apic, irq); + break; } default: @@ -539,20 +1026,6 @@ static int pin_2_irq(int idx, int apic, int pin) } } - /* - * PCI IRQ command line redirection. Yes, limits are hardcoded. - */ - if ((pin >= 16) && (pin <= 23)) { - if (pirq_entries[pin-16] != -1) { - if (!pirq_entries[pin-16]) { - printk(KERN_DEBUG "disabling PIRQ%d\n", pin-16); - } else { - irq = pirq_entries[pin-16]; - printk(KERN_DEBUG "using PIRQ%d -> IRQ %d\n", - pin-16, irq); - } - } - } return irq; } @@ -573,90 +1046,74 @@ static inline int IO_APIC_irq_trigger(int irq) return 0; } -int irq_vector[NR_IRQS] = { FIRST_DEVICE_VECTOR , 0 }; - -int vector_irq[256]; +/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ +u8 irq_vector[NR_IRQ_VECTORS] = { FIRST_DEVICE_VECTOR , 0 }; int assign_irq_vector(int irq) { static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; - if (IO_APIC_VECTOR(irq) > 0) + + BUG_ON(irq >= NR_IRQ_VECTORS); + if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) return IO_APIC_VECTOR(irq); next: current_vector += 8; - /* Skip the hypercall vector. */ - if (current_vector == HYPERCALL_VECTOR) goto next; - /* Skip the Linux/BSD fast-trap vector. */ - if (current_vector == 0x80) goto next; + /* Skip the hypercall vector. */ + if (current_vector == HYPERCALL_VECTOR) + goto next; - if (current_vector > FIRST_SYSTEM_VECTOR) { + /* Skip the Linux/BSD fast-trap vector. */ + if (current_vector == 0x80) + goto next; + + if (current_vector >= FIRST_SYSTEM_VECTOR) { offset++; + if (!(offset%8)) + return -ENOSPC; current_vector = FIRST_DEVICE_VECTOR + offset; } - if (current_vector == FIRST_SYSTEM_VECTOR) - panic("ran out of interrupt sources!"); - - IO_APIC_VECTOR(irq) = current_vector; - - vector_irq[current_vector] = irq; + vector_irq[current_vector] = irq; + if (irq != AUTO_ASSIGN) + IO_APIC_VECTOR(irq) = current_vector; return current_vector; } -extern void (*interrupt[NR_IRQS])(void); +static struct hw_interrupt_type ioapic_level_type; +static struct hw_interrupt_type ioapic_edge_type; -/* - * Level and edge triggered IO-APIC interrupts need different handling, - * so we use two separate IRQ descriptors. Edge triggered IRQs can be - * handled with the level-triggered descriptor, but that one has slightly - * more overhead. Level-triggered interrupts cannot be handled with the - * edge-triggered handler, without risking IRQ storms and other ugly - * races. - */ +#define IOAPIC_AUTO -1 +#define IOAPIC_EDGE 0 +#define IOAPIC_LEVEL 1 -static unsigned int startup_edge_ioapic_irq(unsigned int irq); -#define shutdown_edge_ioapic_irq disable_edge_ioapic_irq -#define enable_edge_ioapic_irq unmask_IO_APIC_irq -static void disable_edge_ioapic_irq (unsigned int irq); -static void ack_edge_ioapic_irq(unsigned int irq); -static void end_edge_ioapic_irq (unsigned int i); -static struct hw_interrupt_type ioapic_edge_irq_type = { - "IO-APIC-edge", - startup_edge_ioapic_irq, - shutdown_edge_ioapic_irq, - enable_edge_ioapic_irq, - disable_edge_ioapic_irq, - ack_edge_ioapic_irq, - end_edge_ioapic_irq, - set_ioapic_affinity, -}; - -static unsigned int startup_level_ioapic_irq (unsigned int irq); -#define shutdown_level_ioapic_irq mask_IO_APIC_irq -#define enable_level_ioapic_irq unmask_IO_APIC_irq -#define disable_level_ioapic_irq mask_IO_APIC_irq -static void mask_and_ack_level_ioapic_irq (unsigned int irq); -static void end_level_ioapic_irq (unsigned int irq); -static struct hw_interrupt_type ioapic_level_irq_type = { - "IO-APIC-level", - startup_level_ioapic_irq, - shutdown_level_ioapic_irq, - enable_level_ioapic_irq, - disable_level_ioapic_irq, - mask_and_ack_level_ioapic_irq, - end_level_ioapic_irq, - set_ioapic_affinity, -}; +static inline void ioapic_register_intr(int irq, int vector, unsigned long trigger) +{ + if (use_pci_vector() && !platform_legacy_irq(irq)) { + if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || + trigger == IOAPIC_LEVEL) + irq_desc[vector].handler = &ioapic_level_type; + else + irq_desc[vector].handler = &ioapic_edge_type; + set_intr_gate(vector, interrupt[vector]); + } else { + if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || + trigger == IOAPIC_LEVEL) + irq_desc[irq].handler = &ioapic_level_type; + else + irq_desc[irq].handler = &ioapic_edge_type; + set_intr_gate(vector, interrupt[irq]); + } +} void __init setup_IO_APIC_irqs(void) { struct IO_APIC_route_entry entry; - int apic, pin, idx, irq, vector; + int apic, pin, idx, irq, first_notcon = 1, vector; unsigned long flags; - printk(KERN_DEBUG "init IO_APIC IRQs\n"); + apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n"); for (apic = 0; apic < nr_ioapics; apic++) { for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { @@ -667,13 +1124,24 @@ void __init setup_IO_APIC_irqs(void) memset(&entry,0,sizeof(entry)); entry.delivery_mode = INT_DELIVERY_MODE; - entry.dest_mode = (INT_DEST_ADDR_MODE != 0); + entry.dest_mode = INT_DEST_MODE; entry.mask = 0; /* enable IRQ */ - entry.dest.logical.logical_dest = target_cpus(); + entry.dest.logical.logical_dest = + cpu_mask_to_apicid(TARGET_CPUS); idx = find_irq_entry(apic,pin,mp_INT); - if (idx == -1) + if (idx == -1) { + if (first_notcon) { + apic_printk(APIC_VERBOSE, KERN_DEBUG + " IO-APIC (apicid-pin) %d-%d", + mp_ioapics[apic].mpc_apicid, + pin); + first_notcon = 0; + } else + apic_printk(APIC_VERBOSE, ", %d-%d", + mp_ioapics[apic].mpc_apicid, pin); continue; + } entry.trigger = irq_trigger(idx); entry.polarity = irq_polarity(idx); @@ -688,8 +1156,7 @@ void __init setup_IO_APIC_irqs(void) * skip adding the timer int on secondary nodes, which causes * a small but painful rift in the time-space continuum */ - if ((clustered_apic_mode == CLUSTERED_APIC_NUMAQ) - && (apic != 0) && (irq == 0)) + if (multi_timer_check(apic, irq)) continue; else add_pin_to_irq(irq, apic, pin); @@ -700,13 +1167,7 @@ void __init setup_IO_APIC_irqs(void) if (IO_APIC_IRQ(irq)) { vector = assign_irq_vector(irq); entry.vector = vector; - - if (IO_APIC_irq_trigger(irq)) - irq_desc[irq].handler = &ioapic_level_irq_type; - else - irq_desc[irq].handler = &ioapic_edge_irq_type; - - set_intr_gate(vector, interrupt[irq]); + ioapic_register_intr(irq, vector, IOAPIC_AUTO); if (!apic && (irq < 16)) disable_8259A_irq(irq); @@ -717,11 +1178,13 @@ void __init setup_IO_APIC_irqs(void) spin_unlock_irqrestore(&ioapic_lock, flags); } } + + if (!first_notcon) + apic_printk(APIC_VERBOSE, " not connected.\n"); } /* - * Set up the 8259A-master output pin as broadcast to all - * CPUs. + * Set up the 8259A-master output pin: */ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) { @@ -739,9 +1202,9 @@ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) * We use logical delivery to get the timer IRQ * to the first CPU. */ - entry.dest_mode = (INT_DEST_ADDR_MODE != 0); + entry.dest_mode = INT_DEST_MODE; entry.mask = 0; /* unmask IRQ now */ - entry.dest.logical.logical_dest = target_cpus(); + entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); entry.delivery_mode = INT_DELIVERY_MODE; entry.polarity = 0; entry.trigger = 0; @@ -751,7 +1214,7 @@ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) * The timer IRQ doesn't have to know that behind the * scene we have a 8259A-master in AEOI mode ... */ - irq_desc[0].handler = &ioapic_edge_irq_type; + irq_desc[0].handler = &ioapic_edge_type; /* * Add it to the IO-APIC irq-routing table: @@ -764,23 +1227,23 @@ void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector) enable_8259A_irq(0); } -void __init UNEXPECTED_IO_APIC(void) +static inline void UNEXPECTED_IO_APIC(void) { - printk(KERN_WARNING - "An unexpected IO-APIC was found. If this kernel release is less than\n" - "three months old please report this to linux-smp@vger.kernel.org\n"); } void __init print_IO_APIC(void) { -#ifdef VERBOSE +#ifndef NDEBUG int apic, i; - struct IO_APIC_reg_00 reg_00; - struct IO_APIC_reg_01 reg_01; - struct IO_APIC_reg_02 reg_02; - struct IO_APIC_reg_03 reg_03; + union IO_APIC_reg_00 reg_00; + union IO_APIC_reg_01 reg_01; + union IO_APIC_reg_02 reg_02; + union IO_APIC_reg_03 reg_03; unsigned long flags; + if (apic_verbosity == APIC_QUIET) + return; + printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); for (i = 0; i < nr_ioapics; i++) printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n", @@ -795,47 +1258,46 @@ void __init print_IO_APIC(void) for (apic = 0; apic < nr_ioapics; apic++) { spin_lock_irqsave(&ioapic_lock, flags); - *(int *)®_00 = io_apic_read(apic, 0); - *(int *)®_01 = io_apic_read(apic, 1); - if (reg_01.version >= 0x10) - *(int *)®_02 = io_apic_read(apic, 2); - if (reg_01.version >= 0x20) - *(int *)®_03 = io_apic_read(apic, 3); + reg_00.raw = io_apic_read(apic, 0); + reg_01.raw = io_apic_read(apic, 1); + if (reg_01.bits.version >= 0x10) + reg_02.raw = io_apic_read(apic, 2); + if (reg_01.bits.version >= 0x20) + reg_03.raw = io_apic_read(apic, 3); spin_unlock_irqrestore(&ioapic_lock, flags); - printk("\n"); printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].mpc_apicid); - printk(KERN_DEBUG ".... register #00: %08X\n", *(int *)®_00); - printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.ID); - printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.delivery_type); - printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.LTS); - if (reg_00.__reserved_0 || reg_00.__reserved_1 || reg_00.__reserved_2) + printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw); + printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID); + printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.bits.delivery_type); + printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.bits.LTS); + if (reg_00.bits.ID >= get_physical_broadcast()) + UNEXPECTED_IO_APIC(); + if (reg_00.bits.__reserved_1 || reg_00.bits.__reserved_2) UNEXPECTED_IO_APIC(); - printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)®_01); - printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.entries); - if ( (reg_01.entries != 0x0f) && /* older (Neptune) boards */ - (reg_01.entries != 0x17) && /* typical ISA+PCI boards */ - (reg_01.entries != 0x1b) && /* Compaq Proliant boards */ - (reg_01.entries != 0x1f) && /* dual Xeon boards */ - (reg_01.entries != 0x22) && /* bigger Xeon boards */ - (reg_01.entries != 0x2E) && - (reg_01.entries != 0x3F) + printk(KERN_DEBUG ".... register #01: %08X\n", reg_01.raw); + printk(KERN_DEBUG "....... : max redirection entries: %04X\n", reg_01.bits.entries); + if ( (reg_01.bits.entries != 0x0f) && /* older (Neptune) boards */ + (reg_01.bits.entries != 0x17) && /* typical ISA+PCI boards */ + (reg_01.bits.entries != 0x1b) && /* Compaq Proliant boards */ + (reg_01.bits.entries != 0x1f) && /* dual Xeon boards */ + (reg_01.bits.entries != 0x22) && /* bigger Xeon boards */ + (reg_01.bits.entries != 0x2E) && + (reg_01.bits.entries != 0x3F) ) UNEXPECTED_IO_APIC(); - printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.PRQ); - printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.version); - if ( (reg_01.version != 0x01) && /* 82489DX IO-APICs */ - (reg_01.version != 0x02) && /* VIA */ - (reg_01.version != 0x03) && /* later VIA */ - (reg_01.version != 0x10) && /* oldest IO-APICs */ - (reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */ - (reg_01.version != 0x13) && /* Xeon IO-APICs */ - (reg_01.version != 0x20) /* Intel P64H (82806 AA) */ + printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ); + printk(KERN_DEBUG "....... : IO APIC version: %04X\n", reg_01.bits.version); + if ( (reg_01.bits.version != 0x01) && /* 82489DX IO-APICs */ + (reg_01.bits.version != 0x10) && /* oldest IO-APICs */ + (reg_01.bits.version != 0x11) && /* Pentium/Pro IO-APICs */ + (reg_01.bits.version != 0x13) && /* Xeon IO-APICs */ + (reg_01.bits.version != 0x20) /* Intel P64H (82806 AA) */ ) UNEXPECTED_IO_APIC(); - if (reg_01.__reserved_1 || reg_01.__reserved_2) + if (reg_01.bits.__reserved_1 || reg_01.bits.__reserved_2) UNEXPECTED_IO_APIC(); /* @@ -843,10 +1305,10 @@ void __init print_IO_APIC(void) * but the value of reg_02 is read as the previous read register * value, so ignore it if reg_02 == reg_01. */ - if (reg_01.version >= 0x10 && *(int *)®_02 != *(int *)®_01) { - printk(KERN_DEBUG ".... register #02: %08X\n", *(int *)®_02); - printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.arbitration); - if (reg_02.__reserved_1 || reg_02.__reserved_2) + if (reg_01.bits.version >= 0x10 && reg_02.raw != reg_01.raw) { + printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw); + printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration); + if (reg_02.bits.__reserved_1 || reg_02.bits.__reserved_2) UNEXPECTED_IO_APIC(); } @@ -855,11 +1317,11 @@ void __init print_IO_APIC(void) * or reg_03, but the value of reg_0[23] is read as the previous read * register value, so ignore it if reg_03 == reg_0[12]. */ - if (reg_01.version >= 0x20 && *(int *)®_03 != *(int *)®_02 && - *(int *)®_03 != *(int *)®_01) { - printk(KERN_DEBUG ".... register #03: %08X\n", *(int *)®_03); - printk(KERN_DEBUG "....... : Boot DT : %X\n", reg_03.boot_DT); - if (reg_03.__reserved_1) + if (reg_01.bits.version >= 0x20 && reg_03.raw != reg_02.raw && + reg_03.raw != reg_01.raw) { + printk(KERN_DEBUG ".... register #03: %08X\n", reg_03.raw); + printk(KERN_DEBUG "....... : Boot DT : %X\n", reg_03.bits.boot_DT); + if (reg_03.bits.__reserved_1) UNEXPECTED_IO_APIC(); } @@ -868,7 +1330,7 @@ void __init print_IO_APIC(void) printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol" " Stat Dest Deli Vect: \n"); - for (i = 0; i <= reg_01.entries; i++) { + for (i = 0; i <= reg_01.bits.entries; i++) { struct IO_APIC_route_entry entry; spin_lock_irqsave(&ioapic_lock, flags); @@ -894,12 +1356,17 @@ void __init print_IO_APIC(void) ); } } + if (use_pci_vector()) + printk(KERN_INFO "Using vector-based indexing\n"); printk(KERN_DEBUG "IRQ to pin mappings:\n"); for (i = 0; i < NR_IRQS; i++) { struct irq_pin_list *entry = irq_2_pin + i; if (entry->pin < 0) continue; - printk(KERN_DEBUG "IRQ%d ", i); + if (use_pci_vector() && !platform_legacy_irq(i)) + printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i)); + else + printk(KERN_DEBUG "IRQ%d ", i); for (;;) { printk("-> %d:%d", entry->apic, entry->pin); if (!entry->next) @@ -910,152 +1377,13 @@ void __init print_IO_APIC(void) } printk(KERN_INFO ".................................... done.\n"); -#endif +#endif /* !NDEBUG */ + return; } - -#if 0 /* Maybe useful for debugging, but not currently used anywhere. */ - -static void print_APIC_bitfield (int base) -{ - unsigned int v; - int i, j; - - printk(KERN_DEBUG "0123456789abcdef0123456789abcdef\n" KERN_DEBUG); - for (i = 0; i < 8; i++) { - v = apic_read(base + i*0x10); - for (j = 0; j < 32; j++) { - if (v & (1< 3) /* Due to the Pentium erratum 3AP. */ - apic_write(APIC_ESR, 0); - v = apic_read(APIC_ESR); - printk(KERN_DEBUG "... APIC ESR: %08x\n", v); - } - - v = apic_read(APIC_ICR); - printk(KERN_DEBUG "... APIC ICR: %08x\n", v); - v = apic_read(APIC_ICR2); - printk(KERN_DEBUG "... APIC ICR2: %08x\n", v); - - v = apic_read(APIC_LVTT); - printk(KERN_DEBUG "... APIC LVTT: %08x\n", v); - - if (maxlvt > 3) { /* PC is LVT#4. */ - v = apic_read(APIC_LVTPC); - printk(KERN_DEBUG "... APIC LVTPC: %08x\n", v); - } - v = apic_read(APIC_LVT0); - printk(KERN_DEBUG "... APIC LVT0: %08x\n", v); - v = apic_read(APIC_LVT1); - printk(KERN_DEBUG "... APIC LVT1: %08x\n", v); - - if (maxlvt > 2) { /* ERR is LVT#3. */ - v = apic_read(APIC_LVTERR); - printk(KERN_DEBUG "... APIC LVTERR: %08x\n", v); - } - - v = apic_read(APIC_TMICT); - printk(KERN_DEBUG "... APIC TMICT: %08x\n", v); - v = apic_read(APIC_TMCCT); - printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v); - v = apic_read(APIC_TDCR); - printk(KERN_DEBUG "... APIC TDCR: %08x\n", v); - printk("\n"); -} - -void print_all_local_APICs (void) -{ - smp_call_function(print_local_APIC, NULL, 1, 1); - print_local_APIC(NULL); -} - -void /*__init*/ print_PIC(void) -{ - extern spinlock_t i8259A_lock; - unsigned int v, flags; - - printk(KERN_DEBUG "\nprinting PIC contents\n"); - - spin_lock_irqsave(&i8259A_lock, flags); - - v = inb(0xa1) << 8 | inb(0x21); - printk(KERN_DEBUG "... PIC IMR: %04x\n", v); - - v = inb(0xa0) << 8 | inb(0x20); - printk(KERN_DEBUG "... PIC IRR: %04x\n", v); - - outb(0x0b,0xa0); - outb(0x0b,0x20); - v = inb(0xa0) << 8 | inb(0x20); - outb(0x0a,0xa0); - outb(0x0a,0x20); - - spin_unlock_irqrestore(&i8259A_lock, flags); - - printk(KERN_DEBUG "... PIC ISR: %04x\n", v); - - v = inb(0x4d1) << 8 | inb(0x4d0); - printk(KERN_DEBUG "... PIC ELCR: %04x\n", v); -} - -#endif /* 0 */ - - static void __init enable_IO_APIC(void) { - struct IO_APIC_reg_01 reg_01; + union IO_APIC_reg_01 reg_01; int i; unsigned long flags; @@ -1063,18 +1391,15 @@ static void __init enable_IO_APIC(void) irq_2_pin[i].pin = -1; irq_2_pin[i].next = 0; } - if (!pirqs_enabled) - for (i = 0; i < MAX_PIRQS; i++) - pirq_entries[i] = -1; /* * The number of IO-APIC IRQ registers (== #pins): */ for (i = 0; i < nr_ioapics; i++) { spin_lock_irqsave(&ioapic_lock, flags); - *(int *)®_01 = io_apic_read(i, 1); + reg_01.raw = io_apic_read(i, 1); spin_unlock_irqrestore(&ioapic_lock, flags); - nr_ioapic_registers[i] = reg_01.entries+1; + nr_ioapic_registers[i] = reg_01.bits.entries+1; } /* @@ -1103,18 +1428,22 @@ void disable_IO_APIC(void) * by Matt Domsch Tue Dec 21 12:25:05 CST 1999 */ -static void __init setup_ioapic_ids_from_mpc (void) +#ifndef CONFIG_X86_NUMAQ +static void __init setup_ioapic_ids_from_mpc(void) { - struct IO_APIC_reg_00 reg_00; - unsigned long phys_id_present_map = phys_cpu_present_map; + union IO_APIC_reg_00 reg_00; + physid_mask_t phys_id_present_map; int apic; int i; unsigned char old_id; unsigned long flags; - if (clustered_apic_mode) - /* We don't have a good way to do this yet - hack */ - phys_id_present_map = (u_long) 0xf; + /* + * This is broken; anything with a real cpu count has to + * circumvent this idiocy regardless. + */ + phys_id_present_map = ioapic_phys_id_map(phys_cpu_present_map); + /* * Set the IOAPIC ID to the value stored in the MPC table. */ @@ -1122,41 +1451,48 @@ static void __init setup_ioapic_ids_from_mpc (void) /* Read the register 0 value */ spin_lock_irqsave(&ioapic_lock, flags); - *(int *)®_00 = io_apic_read(apic, 0); + reg_00.raw = io_apic_read(apic, 0); spin_unlock_irqrestore(&ioapic_lock, flags); old_id = mp_ioapics[apic].mpc_apicid; - if (mp_ioapics[apic].mpc_apicid >= apic_broadcast_id) { + if (mp_ioapics[apic].mpc_apicid >= get_physical_broadcast()) { printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n", apic, mp_ioapics[apic].mpc_apicid); printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", - reg_00.ID); - mp_ioapics[apic].mpc_apicid = reg_00.ID; + reg_00.bits.ID); + mp_ioapics[apic].mpc_apicid = reg_00.bits.ID; } + /* Don't check I/O APIC IDs for some xAPIC systems. They have + * no meaning without the serial APIC bus. */ + if (NO_IOAPIC_CHECK) + continue; /* * Sanity check, is the ID really free? Every APIC in a * system must have a unique ID or we get lots of nice * 'stuck on smp_invalidate_needed IPI wait' messages. - * I/O APIC IDs no longer have any meaning for xAPICs and SAPICs. */ - if ((clustered_apic_mode != CLUSTERED_APIC_XAPIC) && - (phys_id_present_map & (1 << mp_ioapics[apic].mpc_apicid))) { + if (check_apicid_used(phys_id_present_map, + mp_ioapics[apic].mpc_apicid)) { printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n", apic, mp_ioapics[apic].mpc_apicid); - for (i = 0; i < 0xf; i++) - if (!(phys_id_present_map & (1 << i))) + for (i = 0; i < get_physical_broadcast(); i++) + if (!physid_isset(i, phys_id_present_map)) break; - if (i >= apic_broadcast_id) + if (i >= get_physical_broadcast()) panic("Max APIC ID exceeded!\n"); printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n", i); - phys_id_present_map |= 1 << i; + physid_set(i, phys_id_present_map); mp_ioapics[apic].mpc_apicid = i; } else { - printk("Setting %d in the phys_id_present_map\n", mp_ioapics[apic].mpc_apicid); - phys_id_present_map |= 1 << mp_ioapics[apic].mpc_apicid; + physid_mask_t tmp; + tmp = apicid_to_cpu_present(mp_ioapics[apic].mpc_apicid); + apic_printk(APIC_VERBOSE, "Setting %d in the " + "phys_id_present_map\n", + mp_ioapics[apic].mpc_apicid); + physids_or(phys_id_present_map, phys_id_present_map, tmp); } @@ -1174,26 +1510,30 @@ static void __init setup_ioapic_ids_from_mpc (void) * Read the right value from the MPC table and * write it into the ID register. */ - printk(KERN_INFO "...changing IO-APIC physical APIC ID to %d ...", - mp_ioapics[apic].mpc_apicid); + apic_printk(APIC_VERBOSE, KERN_INFO + "...changing IO-APIC physical APIC ID to %d ...", + mp_ioapics[apic].mpc_apicid); - reg_00.ID = mp_ioapics[apic].mpc_apicid; + reg_00.bits.ID = mp_ioapics[apic].mpc_apicid; spin_lock_irqsave(&ioapic_lock, flags); - io_apic_write(apic, 0, *(int *)®_00); + io_apic_write(apic, 0, reg_00.raw); spin_unlock_irqrestore(&ioapic_lock, flags); /* * Sanity check */ spin_lock_irqsave(&ioapic_lock, flags); - *(int *)®_00 = io_apic_read(apic, 0); + reg_00.raw = io_apic_read(apic, 0); spin_unlock_irqrestore(&ioapic_lock, flags); - if (reg_00.ID != mp_ioapics[apic].mpc_apicid) - panic("could not set ID!\n"); + if (reg_00.bits.ID != mp_ioapics[apic].mpc_apicid) + printk("could not set ID!\n"); else - printk(" ok.\n"); + apic_printk(APIC_VERBOSE, " ok.\n"); } } +#else +static void __init setup_ioapic_ids_from_mpc(void) { } +#endif /* * There is a nasty bug in some older SMP boards, their mptable lies @@ -1205,9 +1545,9 @@ static void __init setup_ioapic_ids_from_mpc (void) */ static int __init timer_irq_works(void) { - unsigned int t1 = jiffies; + unsigned long t1 = jiffies; - __sti(); + local_irq_enable(); /* Let ten ticks pass... */ mdelay((10 * 1000) / HZ); @@ -1224,7 +1564,18 @@ static int __init timer_irq_works(void) return 0; } -static void disable_edge_ioapic_irq (unsigned int irq) { /* nothing */ } +/* + * In the SMP+IOAPIC case it might happen that there are an unspecified + * number of pending IRQ events unhandled. These cases are very rare, + * so we 'resend' these IRQs via IPIs, to the same CPU. It's much + * better to do it this way as thus we do not have to be aware of + * 'pending' interrupts in the IRQ path, except at this point. + */ +/* + * Edge triggered needs to resend any interrupt + * that was delayed but this is now handled in the device + * independent code. + */ /* * Starting up a edge-triggered IO-APIC interrupt is @@ -1235,7 +1586,6 @@ static void disable_edge_ioapic_irq (unsigned int irq) { /* nothing */ } * This is not complete - we should be able to fake * an edge even if it isn't on the 8259A... */ - static unsigned int startup_edge_ioapic_irq(unsigned int irq) { int was_pending = 0; @@ -1260,16 +1610,13 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq) */ static void ack_edge_ioapic_irq(unsigned int irq) { - balance_irq(irq); + move_irq(irq); if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_DISABLED)) mask_IO_APIC_irq(irq); ack_APIC_irq(); } -static void end_edge_ioapic_irq (unsigned int i) { /* nothing */ } - - /* * Level triggered interrupts can just be masked, * and shutting down and starting up the interrupt @@ -1291,15 +1638,12 @@ static unsigned int startup_level_ioapic_irq (unsigned int irq) return 0; /* don't check for pending */ } -static void mask_and_ack_level_ioapic_irq(unsigned int irq) +static void end_level_ioapic_irq (unsigned int irq) { unsigned long v; int i; - balance_irq(irq); - - mask_IO_APIC_irq(irq); - + move_irq(irq); /* * It appears there is an erratum which affects at least version 0x11 * of I/O APIC (that's the 82093AA and cores integrated into various @@ -1320,45 +1664,102 @@ static void mask_and_ack_level_ioapic_irq(unsigned int irq) * The idea is from Manfred Spraul. --macro */ i = IO_APIC_VECTOR(irq); + v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); ack_APIC_irq(); if (!(v & (1 << (i & 0x1f)))) { -#ifdef APIC_LOCKUP_DEBUG - struct irq_pin_list *entry; -#endif - -#ifdef APIC_MISMATCH_DEBUG atomic_inc(&irq_mis_count); -#endif spin_lock(&ioapic_lock); - __edge_IO_APIC_irq(irq); -#ifdef APIC_LOCKUP_DEBUG - for (entry = irq_2_pin + irq;;) { - unsigned int reg; - - if (entry->pin == -1) - break; - reg = io_apic_read(entry->apic, 0x10 + entry->pin * 2); - if (reg & 0x00004000) - printk(KERN_CRIT "Aieee!!! Remote IRR" - " still set after unlock!\n"); - if (!entry->next) - break; - entry = irq_2_pin + entry->next; - } -#endif - __level_IO_APIC_irq(irq); + __mask_and_edge_IO_APIC_irq(irq); + __unmask_and_level_IO_APIC_irq(irq); spin_unlock(&ioapic_lock); } } -static void end_level_ioapic_irq(unsigned int irq) +#ifdef CONFIG_PCI_MSI +static unsigned int startup_edge_ioapic_vector(unsigned int vector) { + int irq = vector_to_irq(vector); + + return startup_edge_ioapic_irq(irq); +} + +static void ack_edge_ioapic_vector(unsigned int vector) +{ + int irq = vector_to_irq(vector); + + ack_edge_ioapic_irq(irq); +} + +static unsigned int startup_level_ioapic_vector (unsigned int vector) +{ + int irq = vector_to_irq(vector); + + return startup_level_ioapic_irq (irq); +} + +static void end_level_ioapic_vector (unsigned int vector) +{ + int irq = vector_to_irq(vector); + + end_level_ioapic_irq(irq); +} + +static void mask_IO_APIC_vector (unsigned int vector) +{ + int irq = vector_to_irq(vector); + + mask_IO_APIC_irq(irq); +} + +static void unmask_IO_APIC_vector (unsigned int vector) +{ + int irq = vector_to_irq(vector); + unmask_IO_APIC_irq(irq); } +static void set_ioapic_affinity_vector (unsigned int vector, + cpumask_t cpu_mask) +{ + int irq = vector_to_irq(vector); + + set_ioapic_affinity_irq(irq, cpu_mask); +} +#endif + +/* + * Level and edge triggered IO-APIC interrupts need different handling, + * so we use two separate IRQ descriptors. Edge triggered IRQs can be + * handled with the level-triggered descriptor, but that one has slightly + * more overhead. Level-triggered interrupts cannot be handled with the + * edge-triggered handler, without risking IRQ storms and other ugly + * races. + */ +static struct hw_interrupt_type ioapic_edge_type = { + .typename = "IO-APIC-edge", + .startup = startup_edge_ioapic, + .shutdown = shutdown_edge_ioapic, + .enable = enable_edge_ioapic, + .disable = disable_edge_ioapic, + .ack = ack_edge_ioapic, + .end = end_edge_ioapic, + .set_affinity = set_ioapic_affinity, +}; + +static struct hw_interrupt_type ioapic_level_type = { + .typename = "IO-APIC-level", + .startup = startup_level_ioapic, + .shutdown = shutdown_level_ioapic, + .enable = enable_level_ioapic, + .disable = disable_level_ioapic, + .ack = mask_and_ack_level_ioapic, + .end = end_level_ioapic, + .set_affinity = set_ioapic_affinity, +}; + static inline void init_IO_APIC_traps(void) { int irq; @@ -1375,7 +1776,13 @@ static inline void init_IO_APIC_traps(void) * 0x80, because int 0x80 is hm, kind of importantish. ;) */ for (irq = 0; irq < NR_IRQS ; irq++) { - if (IO_APIC_IRQ(irq) && !IO_APIC_VECTOR(irq)) { + int tmp = irq; + if (use_pci_vector()) { + if (!platform_legacy_irq(tmp)) + if ((tmp = vector_to_irq(tmp)) == -1) + continue; + } + if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) { /* * Hmm.. We don't have an entry for this, * so default to an old-fashioned 8259 @@ -1414,15 +1821,35 @@ static void ack_lapic_irq (unsigned int irq) static void end_lapic_irq (unsigned int i) { /* nothing */ } static struct hw_interrupt_type lapic_irq_type = { - "local-APIC-edge", - NULL, /* startup_irq() not used for IRQ0 */ - NULL, /* shutdown_irq() not used for IRQ0 */ - enable_lapic_irq, - disable_lapic_irq, - ack_lapic_irq, - end_lapic_irq + .typename = "local-APIC-edge", + .startup = NULL, /* startup_irq() not used for IRQ0 */ + .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */ + .enable = enable_lapic_irq, + .disable = disable_lapic_irq, + .ack = ack_lapic_irq, + .end = end_lapic_irq }; +#if 0 +static void setup_nmi (void) +{ + /* + * Dirty trick to enable the NMI watchdog ... + * We put the 8259A master into AEOI mode and + * unmask on all local APICs LVT0 as NMI. + * + * The idea to use the 8259A in AEOI mode ('8259A Virtual Wire') + * is from Maciej W. Rozycki - so we do not have to EOI from + * the NMI handler or the timer interrupt. + */ + apic_printk(APIC_VERBOSE, KERN_INFO "activating NMI Watchdog ..."); + + on_each_cpu(enable_NMI_through_LVT0, NULL, 1, 1); + + apic_printk(APIC_VERBOSE, " done.\n"); +} +#endif + /* * This looks a bit hackish but it's about the only one way of sending * a few INTA cycles to 8259As and any associated glue logic. ICR does @@ -1493,7 +1920,6 @@ static inline void unlock_ExtINT_logic(void) */ static inline void check_timer(void) { - extern int timer_ack; int pin1, pin2; int vector; @@ -1526,8 +1952,17 @@ static inline void check_timer(void) * Ok, does IRQ0 through the IOAPIC work? */ unmask_IO_APIC_irq(0); - if (timer_irq_works()) + if (timer_irq_works()) { +#if 0 + if (nmi_watchdog == NMI_IO_APIC) { + disable_8259A_irq(0); + setup_nmi(); + enable_8259A_irq(0); + check_nmi_watchdog(); + } +#endif return; + } clear_IO_APIC_pin(0, pin1); printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n"); } @@ -1545,6 +1980,12 @@ static inline void check_timer(void) replace_pin_at_irq(0, 0, pin1, 0, pin2); else add_pin_to_irq(0, 0, pin2); +#if 0 + if (nmi_watchdog == NMI_IO_APIC) { + setup_nmi(); + check_nmi_watchdog(); + } +#endif return; } /* @@ -1554,6 +1995,11 @@ static inline void check_timer(void) } printk(" failed.\n"); + if (nmi_watchdog == NMI_IO_APIC) { + printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n"); + nmi_watchdog = 0; + } + printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); disable_8259A_irq(0); @@ -1570,6 +2016,7 @@ static inline void check_timer(void) printk(KERN_INFO "...trying to set up timer as ExtINT IRQ..."); + timer_ack = 0; init_8259A(0); make_8259A_irq(0); apic_write_around(APIC_LVT0, APIC_DM_EXTINT); @@ -1581,7 +2028,8 @@ static inline void check_timer(void) return; } printk(" failed :(.\n"); - panic("IO-APIC + timer doesn't work! pester mingo@redhat.com"); + panic("IO-APIC + timer doesn't work! Boot with apic=debug and send a " + "report. Then try booting with the 'noapic' option"); } #define NR_IOAPIC_BIOSIDS 256 @@ -1596,20 +2044,12 @@ static void store_ioapic_biosid_mapping(void) /* * - * IRQ's that are handled by the old PIC in all cases: + * IRQ's that are handled by the PIC in the MPS IOAPIC case. * - IRQ2 is the cascade IRQ, and cannot be a io-apic IRQ. * Linux doesn't really care, as it's not actually used * for any interrupt handling anyway. - * - There used to be IRQ13 here as well, but all - * MPS-compliant must not use it for FPU coupling and we - * want to use exception 16 anyway. And there are - * systems who connect it to an I/O APIC for other uses. - * Thus we don't mark it special any longer. - * - * Additionally, something is definitely wrong with irq9 - * on PIIX4 boards. */ -#define PIC_IRQS (1<<2) +#define PIC_IRQS (1 << PIC_CASCADE_IR) void __init setup_IO_APIC(void) { @@ -1617,7 +2057,11 @@ void __init setup_IO_APIC(void) enable_IO_APIC(); - io_apic_irqs = ~PIC_IRQS; + if (acpi_ioapic) + io_apic_irqs = ~0; /* all IRQs go through IOAPIC */ + else + io_apic_irqs = ~PIC_IRQS; + printk("ENABLING IO-APIC IRQs\n"); /* @@ -1632,22 +2076,17 @@ void __init setup_IO_APIC(void) print_IO_APIC(); } -#endif /* CONFIG_X86_IO_APIC */ - - - /* -------------------------------------------------------------------------- ACPI-based IOAPIC Configuration -------------------------------------------------------------------------- */ #ifdef CONFIG_ACPI_BOOT -#define IO_APIC_MAX_ID 15 - int __init io_apic_get_unique_id (int ioapic, int apic_id) { - struct IO_APIC_reg_00 reg_00; - static unsigned long apic_id_map = 0; + union IO_APIC_reg_00 reg_00; + static physid_mask_t apic_id_map = PHYSID_MASK_NONE; + physid_mask_t tmp; unsigned long flags; int i = 0; @@ -1660,38 +2099,31 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id) * advantage of new APIC bus architecture. */ - if (!apic_id_map) - apic_id_map = phys_cpu_present_map; + if (physids_empty(apic_id_map)) + apic_id_map = ioapic_phys_id_map(phys_cpu_present_map); spin_lock_irqsave(&ioapic_lock, flags); - *(int *)®_00 = io_apic_read(ioapic, 0); + reg_00.raw = io_apic_read(ioapic, 0); spin_unlock_irqrestore(&ioapic_lock, flags); - if (apic_id >= IO_APIC_MAX_ID) { + if (apic_id >= get_physical_broadcast()) { printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying " - "%d\n", ioapic, apic_id, reg_00.ID); - apic_id = reg_00.ID; - } - - /* XAPICs do not need unique IDs */ - if (clustered_apic_mode == CLUSTERED_APIC_XAPIC){ - printk(KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", - ioapic, apic_id); - return apic_id; + "%d\n", ioapic, apic_id, reg_00.bits.ID); + apic_id = reg_00.bits.ID; } /* * Every APIC in a system must have a unique ID or we get lots of nice * 'stuck on smp_invalidate_needed IPI wait' messages. */ - if (apic_id_map & (1 << apic_id)) { + if (check_apicid_used(apic_id_map, apic_id)) { - for (i = 0; i < IO_APIC_MAX_ID; i++) { - if (!(apic_id_map & (1 << i))) + for (i = 0; i < get_physical_broadcast(); i++) { + if (!check_apicid_used(apic_id_map, i)) break; } - if (i == IO_APIC_MAX_ID) + if (i == get_physical_broadcast()) panic("Max apic_id exceeded!\n"); printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, " @@ -1700,22 +2132,24 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id) apic_id = i; } - apic_id_map |= (1 << apic_id); + tmp = apicid_to_cpu_present(apic_id); + physids_or(apic_id_map, apic_id_map, tmp); - if (reg_00.ID != apic_id) { - reg_00.ID = apic_id; + if (reg_00.bits.ID != apic_id) { + reg_00.bits.ID = apic_id; spin_lock_irqsave(&ioapic_lock, flags); - io_apic_write(ioapic, 0, *(int *)®_00); - *(int *)®_00 = io_apic_read(ioapic, 0); + io_apic_write(ioapic, 0, reg_00.raw); + reg_00.raw = io_apic_read(ioapic, 0); spin_unlock_irqrestore(&ioapic_lock, flags); /* Sanity check */ - if (reg_00.ID != apic_id) + if (reg_00.bits.ID != apic_id) panic("IOAPIC[%d]: Unable change apic_id!\n", ioapic); } - printk(KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); + apic_printk(APIC_VERBOSE, KERN_INFO + "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id); return apic_id; } @@ -1723,27 +2157,27 @@ int __init io_apic_get_unique_id (int ioapic, int apic_id) int __init io_apic_get_version (int ioapic) { - struct IO_APIC_reg_01 reg_01; + union IO_APIC_reg_01 reg_01; unsigned long flags; spin_lock_irqsave(&ioapic_lock, flags); - *(int *)®_01 = io_apic_read(ioapic, 1); + reg_01.raw = io_apic_read(ioapic, 1); spin_unlock_irqrestore(&ioapic_lock, flags); - return reg_01.version; + return reg_01.bits.version; } int __init io_apic_get_redir_entries (int ioapic) { - struct IO_APIC_reg_01 reg_01; + union IO_APIC_reg_01 reg_01; unsigned long flags; spin_lock_irqsave(&ioapic_lock, flags); - *(int *)®_01 = io_apic_read(ioapic, 1); + reg_01.raw = io_apic_read(ioapic, 1); spin_unlock_irqrestore(&ioapic_lock, flags); - return reg_01.entries; + return reg_01.bits.entries; } @@ -1753,7 +2187,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a unsigned long flags; if (!IO_APIC_IRQ(irq)) { - printk(KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0/n", + printk(KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", ioapic); return -EINVAL; } @@ -1766,12 +2200,12 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a memset(&entry,0,sizeof(entry)); - entry.delivery_mode = dest_LowestPrio; - entry.dest_mode = INT_DELIVERY_MODE; - entry.dest.logical.logical_dest = target_cpus(); - entry.mask = 1; /* Disabled (masked) */ + entry.delivery_mode = INT_DELIVERY_MODE; + entry.dest_mode = INT_DEST_MODE; + entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); entry.trigger = edge_level; entry.polarity = active_high_low; + entry.mask = 1; /* * IRQs < 16 are already in the irq_2_pin[] map @@ -1781,17 +2215,12 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a entry.vector = assign_irq_vector(irq); - printk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " - "IRQ %d Mode:%i Active:%i)\n", ioapic, - mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low); + apic_printk(APIC_DEBUG, KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry " + "(%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i)\n", ioapic, + mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, + edge_level, active_high_low); - if (edge_level) { - irq_desc[irq].handler = &ioapic_level_irq_type; - } else { - irq_desc[irq].handler = &ioapic_edge_irq_type; - } - - set_intr_gate(entry.vector, interrupt[irq]); + ioapic_register_intr(irq, entry.vector, edge_level); if (!ioapic && (irq < 16)) disable_8259A_irq(irq); @@ -1806,123 +2235,12 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a #endif /*CONFIG_ACPI_BOOT*/ -/* opt_leveltrigger, opt_edgetrigger: Force an IO-APIC-routed IRQ to be */ -/* level- or edge-triggered. */ -/* Example: 'leveltrigger=4,5,6,20 edgetrigger=21'. */ -static char opt_leveltrigger[30] = "", opt_edgetrigger[30] = ""; -string_param("leveltrigger", opt_leveltrigger); -string_param("edgetrigger", opt_edgetrigger); - -static int __init ioapic_trigger_setup(void) -{ - char *p; - irq_desc_t *desc; - long irq; - - p = opt_leveltrigger; - while ( *p != '\0' ) - { - irq = simple_strtol(p, &p, 10); - if ( (irq <= 0) || (irq >= NR_IRQS) ) - { - printk("IRQ '%ld' out of range in level-trigger list '%s'\n", - irq, opt_leveltrigger); - break; - } - - printk("Forcing IRQ %ld to level-trigger: ", irq); - - desc = &irq_desc[irq]; - spin_lock_irq(&desc->lock); - - if ( desc->handler == &ioapic_level_irq_type ) - { - printk("already level-triggered (no force applied).\n"); - } - else if ( desc->handler != &ioapic_edge_irq_type ) - { - printk("cannot force (can only force IO-APIC-edge IRQs).\n"); - } - else - { - desc->handler = &ioapic_level_irq_type; - __mask_IO_APIC_irq(irq); - __level_IO_APIC_irq(irq); - printk("done.\n"); - } - - spin_unlock_irq(&desc->lock); - - if ( *p == '\0' ) - break; - - if ( *p != ',' ) - { - printk("Unexpected character '%c' in level-trigger list '%s'\n", - *p, opt_leveltrigger); - break; - } - - p++; - } - - p = opt_edgetrigger; - while ( *p != '\0' ) - { - irq = simple_strtol(p, &p, 10); - if ( (irq <= 0) || (irq >= NR_IRQS) ) - { - printk("IRQ '%ld' out of range in edge-trigger list '%s'\n", - irq, opt_edgetrigger); - break; - } - - printk("Forcing IRQ %ld to edge-trigger: ", irq); - - desc = &irq_desc[irq]; - spin_lock_irq(&desc->lock); - - if ( desc->handler == &ioapic_edge_irq_type ) - { - printk("already edge-triggered (no force applied).\n"); - } - else if ( desc->handler != &ioapic_level_irq_type ) - { - printk("cannot force (can only force IO-APIC-level IRQs).\n"); - } - else - { - desc->handler = &ioapic_edge_irq_type; - __edge_IO_APIC_irq(irq); - desc->status |= IRQ_PENDING; /* may have lost a masked edge */ - printk("done.\n"); - } - - spin_unlock_irq(&desc->lock); - - if ( *p == '\0' ) - break; - - if ( *p != ',' ) - { - printk("Unexpected character '%c' in edge-trigger list '%s'\n", - *p, opt_edgetrigger); - break; - } - - p++; - } - - return 0; -} - -__initcall(ioapic_trigger_setup); int ioapic_guest_read(int apicid, int address, u32 *pval) { u32 val; int apicenum; - struct IO_APIC_reg_00 reg_00; + union IO_APIC_reg_00 reg_00; unsigned long flags; if ( (apicid >= NR_IOAPIC_BIOSIDS) || @@ -1936,9 +2254,9 @@ int ioapic_guest_read(int apicid, int address, u32 *pval) /* Rewrite APIC ID to what the BIOS originally specified. */ if ( address == 0 ) { - *(int *)®_00 = val; - reg_00.ID = apicid; - val = *(u32 *)®_00; + reg_00.raw = val; + reg_00.bits.ID = apicid; + val = reg_00.raw; } *pval = val; @@ -1974,7 +2292,7 @@ int ioapic_guest_write(int apicid, int address, u32 val) /* Set the correct irq-handling type. */ irq_desc[irq].handler = rte.trigger ? - &ioapic_level_irq_type: &ioapic_edge_irq_type; + &ioapic_level_type: &ioapic_edge_type; /* Record the pin<->irq mapping. */ for ( entry = &irq_2_pin[irq]; ; entry = &irq_2_pin[entry->next] ) diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index 86b3d7da99..aaaff647ce 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -42,7 +42,6 @@ struct hw_interrupt_type no_irq_type = { }; atomic_t irq_err_count; -atomic_t irq_mis_count; inline void disable_irq_nosync(unsigned int irq) { diff --git a/xen/arch/x86/microcode.c b/xen/arch/x86/microcode.c index d811e7ed70..4cbafae1e6 100644 --- a/xen/arch/x86/microcode.c +++ b/xen/arch/x86/microcode.c @@ -87,13 +87,6 @@ #define vmalloc(_s) xmalloc_bytes(_s) #define vfree(_p) xfree(_p) #define num_online_cpus() smp_num_cpus -static inline int on_each_cpu( - void (*func) (void *info), void *info, int retry, int wait) -{ - int ret = smp_call_function(func, info, retry, wait); - func(info); - return ret; -} #if 0 MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver"); diff --git a/xen/arch/x86/mpparse.c b/xen/arch/x86/mpparse.c index 6b4599fdf4..39a7619edc 100644 --- a/xen/arch/x86/mpparse.c +++ b/xen/arch/x86/mpparse.c @@ -1,5 +1,5 @@ /* - * Intel Multiprocessor Specificiation 1.1 and 1.4 + * Intel Multiprocessor Specification 1.1 and 1.4 * compliant MP-table parsing routines. * * (c) 1995 Alan Cox, Building #3 @@ -14,44 +14,48 @@ */ #include -#include -#include -#include +#include #include -#include -#include +#include #include -#include -#include -#include -#include -#include -#include +#include +#include -int numnodes = 1; /* XXX Xen */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define es7000_plat 0 /* XXX XEN */ /* Have we found an MP table */ int smp_found_config; +unsigned int __initdata maxcpus = NR_CPUS; /* * Various Linux-internal data structures created from the * MP-table. */ int apic_version [MAX_APICS]; +int mp_bus_id_to_type [MAX_MP_BUSSES]; +int mp_bus_id_to_node [MAX_MP_BUSSES]; +int mp_bus_id_to_local [MAX_MP_BUSSES]; int quad_local_to_mp_bus_id [NR_CPUS/4][4]; +int mp_bus_id_to_pci_bus [MAX_MP_BUSSES] = { [0 ... MAX_MP_BUSSES-1] = -1 }; int mp_current_pci_id; -int *mp_bus_id_to_type; -int *mp_bus_id_to_node; -int *mp_bus_id_to_local; -int *mp_bus_id_to_pci_bus; -int max_mp_busses; -int max_irq_sources; /* I/O APIC entries */ struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; /* # of MP IRQ source entries */ -struct mpc_config_intsrc *mp_irqs; +struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; /* MP IRQ source entries */ int mp_irq_entries; @@ -65,24 +69,18 @@ unsigned long mp_lapic_addr; unsigned int boot_cpu_physical_apicid = -1U; unsigned int boot_cpu_logical_apicid = -1U; /* Internal processor count */ -static unsigned int num_processors; +static unsigned int __initdata num_processors; /* Bitmask of physically existing CPUs */ -unsigned long phys_cpu_present_map; -unsigned long logical_cpu_present_map; +physid_mask_t phys_cpu_present_map; -#ifdef CONFIG_X86_CLUSTERED_APIC -unsigned char esr_disable = 0; -unsigned char clustered_apic_mode = CLUSTERED_APIC_NONE; -unsigned int apic_broadcast_id = APIC_BROADCAST_ID_APIC; -#endif -unsigned char raw_phys_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; +u8 bios_cpu_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; /* * Intel MP BIOS table parsing routines: */ -#ifndef CONFIG_X86_VISWS_APIC + /* * Checksum an MP configuration block. */ @@ -98,48 +96,6 @@ static int __init mpf_checksum(unsigned char *mp, int len) } /* - * Processor encoding in an MP configuration block - */ - -static char __init *mpc_family(int family,int model) -{ - static char n[32]; - static char *model_defs[]= - { - "80486DX","80486DX", - "80486SX","80486DX/2 or 80487", - "80486SL","80486SX/2", - "Unknown","80486DX/2-WB", - "80486DX/4","80486DX/4-WB" - }; - - switch (family) { - case 0x04: - if (model < 10) - return model_defs[model]; - break; - - case 0x05: - return("Pentium(tm)"); - - case 0x06: - return("Pentium(tm) Pro"); - - case 0x0F: - if (model == 0x00) - return("Pentium 4(tm)"); - if (model == 0x01) - return("Pentium 4(tm)"); - if (model == 0x02) - return("Pentium 4(tm) XEON(tm)"); - if (model == 0x0F) - return("Special controller"); - } - sprintf(n,"Unknown CPU [%d:%d]",family, model); - return n; -} - -/* * Have to match translation table entries to main table entries by counter * hence the mpc_record variable .... can't see a less disgusting way of * doing this .... @@ -148,30 +104,30 @@ static char __init *mpc_family(int family,int model) static int mpc_record; static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY] __initdata; +#ifdef CONFIG_X86_NUMAQ +static int MP_valid_apicid(int apicid, int version) +{ + return hweight_long(apicid & 0xf) == 1 && (apicid >> 4) != 0xf; +} +#else +static int MP_valid_apicid(int apicid, int version) +{ + if (version >= 0x14) + return apicid < 0xff; + else + return apicid < 0xf; +} +#endif + void __init MP_processor_info (struct mpc_config_processor *m) { - int ver, quad, logical_apicid; + int ver, apicid; + physid_mask_t tmp; if (!(m->mpc_cpuflag & CPU_ENABLED)) return; - logical_apicid = m->mpc_apicid; - if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) { - quad = translation_table[mpc_record]->trans_quad; - logical_apicid = (quad << 4) + - (m->mpc_apicid ? m->mpc_apicid << 1 : 1); - printk("Processor #%d %s APIC version %d (quad %d, apic %d)\n", - m->mpc_apicid, - mpc_family((m->mpc_cpufeature & CPU_FAMILY_MASK)>>8 , - (m->mpc_cpufeature & CPU_MODEL_MASK)>>4), - m->mpc_apicver, quad, logical_apicid); - } else { - printk("Processor #%d %s APIC version %d\n", - m->mpc_apicid, - mpc_family((m->mpc_cpufeature & CPU_FAMILY_MASK)>>8 , - (m->mpc_cpufeature & CPU_MODEL_MASK)>>4), - m->mpc_apicver); - } + apicid = mpc_apic_id(m, translation_table[mpc_record]); if (m->mpc_featureflag&(1<<0)) Dprintk(" Floating point unit present.\n"); @@ -224,68 +180,68 @@ void __init MP_processor_info (struct mpc_config_processor *m) if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) { Dprintk(" Bootup CPU\n"); boot_cpu_physical_apicid = m->mpc_apicid; - boot_cpu_logical_apicid = logical_apicid; + boot_cpu_logical_apicid = apicid; } - if (num_processors >= NR_CPUS){ - printk(KERN_WARNING "NR_CPUS limit of %i reached. Cannot " - "boot CPU(apicid 0x%x).\n", NR_CPUS, m->mpc_apicid); + if (num_processors >= NR_CPUS) { + printk(KERN_WARNING "WARNING: NR_CPUS limit of %i reached." + " Processor ignored.\n", NR_CPUS); + return; + } + + if (num_processors >= maxcpus) { + printk(KERN_WARNING "WARNING: maxcpus limit of %i reached." + " Processor ignored.\n", maxcpus); return; } num_processors++; + ver = m->mpc_apicver; - if (m->mpc_apicid > MAX_APICS) { - printk("Processor #%d INVALID. (Max ID: %d).\n", + if (!MP_valid_apicid(apicid, ver)) { + printk(KERN_WARNING "Processor #%d INVALID. (Max ID: %d).\n", m->mpc_apicid, MAX_APICS); --num_processors; return; } - ver = m->mpc_apicver; - logical_cpu_present_map |= 1 << (num_processors-1); - phys_cpu_present_map |= apicid_to_phys_cpu_present(m->mpc_apicid); - + tmp = apicid_to_cpu_present(apicid); + physids_or(phys_cpu_present_map, phys_cpu_present_map, tmp); + /* * Validate version */ if (ver == 0x0) { - printk("BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid); + printk(KERN_WARNING "BIOS bug, APIC version is 0 for CPU#%d! fixing up to 0x10. (tell your hw vendor)\n", m->mpc_apicid); ver = 0x10; } apic_version[m->mpc_apicid] = ver; - raw_phys_apicid[num_processors - 1] = m->mpc_apicid; + bios_cpu_apicid[num_processors - 1] = m->mpc_apicid; } static void __init MP_bus_info (struct mpc_config_bus *m) { char str[7]; - int quad; memcpy(str, m->mpc_bustype, 6); str[6] = 0; - - if (clustered_apic_mode == CLUSTERED_APIC_NUMAQ) { - quad = translation_table[mpc_record]->trans_quad; - mp_bus_id_to_node[m->mpc_busid] = quad; - mp_bus_id_to_local[m->mpc_busid] = translation_table[mpc_record]->trans_local; - quad_local_to_mp_bus_id[quad][translation_table[mpc_record]->trans_local] = m->mpc_busid; - printk("Bus #%d is %s (node %d)\n", m->mpc_busid, str, quad); - } else { - Dprintk("Bus #%d is %s\n", m->mpc_busid, str); - } + + mpc_oem_bus_info(m, str, translation_table[mpc_record]); if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA)-1) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_ISA; } else if (strncmp(str, BUSTYPE_EISA, sizeof(BUSTYPE_EISA)-1) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_EISA; } else if (strncmp(str, BUSTYPE_PCI, sizeof(BUSTYPE_PCI)-1) == 0) { + mpc_oem_pci_bus(m, translation_table[mpc_record]); mp_bus_id_to_type[m->mpc_busid] = MP_BUS_PCI; mp_bus_id_to_pci_bus[m->mpc_busid] = mp_current_pci_id; mp_current_pci_id++; } else if (strncmp(str, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA; + } else if (strncmp(str, BUSTYPE_NEC98, sizeof(BUSTYPE_NEC98)-1) == 0) { + mp_bus_id_to_type[m->mpc_busid] = MP_BUS_NEC98; } else { - printk("Unknown bustype %s - ignoring\n", str); + printk(KERN_WARNING "Unknown bustype %s - ignoring\n", str); } } @@ -294,10 +250,10 @@ static void __init MP_ioapic_info (struct mpc_config_ioapic *m) if (!(m->mpc_flags & MPC_APIC_USABLE)) return; - printk("I/O APIC #%d Version %d at 0x%X.\n", + printk(KERN_INFO "I/O APIC #%d Version %d at 0x%X.\n", m->mpc_apicid, m->mpc_apicver, m->mpc_apicaddr); if (nr_ioapics >= MAX_IO_APICS) { - printk("Max # of I/O APICs (%d) exceeded (found %d).\n", + printk(KERN_CRIT "Max # of I/O APICs (%d) exceeded (found %d).\n", MAX_IO_APICS, nr_ioapics); panic("Recompile kernel with bigger MAX_IO_APICS!.\n"); } @@ -318,7 +274,7 @@ static void __init MP_intsrc_info (struct mpc_config_intsrc *m) m->mpc_irqtype, m->mpc_irqflag & 3, (m->mpc_irqflag >> 2) & 3, m->mpc_srcbus, m->mpc_srcbusirq, m->mpc_dstapic, m->mpc_dstirq); - if (++mp_irq_entries == max_irq_sources) + if (++mp_irq_entries == MAX_IRQ_SOURCES) panic("Max # of irq sources exceeded!!\n"); } @@ -344,16 +300,17 @@ static void __init MP_lintsrc_info (struct mpc_config_lintsrc *m) BUG(); } +#ifdef CONFIG_X86_NUMAQ static void __init MP_translation_info (struct mpc_config_translation *m) { - printk("Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, m->trans_quad, m->trans_global, m->trans_local); + printk(KERN_INFO "Translation: record %d, type %d, quad %d, global %d, local %d\n", mpc_record, m->trans_type, m->trans_quad, m->trans_global, m->trans_local); if (mpc_record >= MAX_MPC_ENTRY) - printk("MAX_MPC_ENTRY exceeded!\n"); + printk(KERN_ERR "MAX_MPC_ENTRY exceeded!\n"); else translation_table[mpc_record] = m; /* stash this for later */ - if (m->trans_quad+1 > numnodes) - numnodes = m->trans_quad+1; + if (m->trans_quad < MAX_NUMNODES && !node_online(m->trans_quad)) + node_set_online(m->trans_quad); } /* @@ -366,10 +323,11 @@ static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable, \ int count = sizeof (*oemtable); /* the header size */ unsigned char *oemptr = ((unsigned char *)oemtable)+count; - printk("Found an OEM MPC table at %8p - parsing it ... \n", oemtable); + mpc_record = 0; + printk(KERN_INFO "Found an OEM MPC table at %8p - parsing it ... \n", oemtable); if (memcmp(oemtable->oem_signature,MPC_OEM_SIGNATURE,4)) { - printk("SMP mpc oemtable: bad signature [%c%c%c%c]!\n", + printk(KERN_WARNING "SMP mpc oemtable: bad signature [%c%c%c%c]!\n", oemtable->oem_signature[0], oemtable->oem_signature[1], oemtable->oem_signature[2], @@ -378,7 +336,7 @@ static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable, \ } if (mpf_checksum((unsigned char *)oemtable,oemtable->oem_length)) { - printk("SMP oem mptable: checksum error!\n"); + printk(KERN_WARNING "SMP oem mptable: checksum error!\n"); return; } while (count < oemtable->oem_length) { @@ -395,36 +353,42 @@ static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable, \ } default: { - printk("Unrecognised OEM table entry type! - %d\n", (int) *oemptr); + printk(KERN_WARNING "Unrecognised OEM table entry type! - %d\n", (int) *oemptr); return; } } } } +static inline void mps_oem_check(struct mp_config_table *mpc, char *oem, + char *productid) +{ + if (strncmp(oem, "IBM NUMA", 8)) + printk("Warning! May not be a NUMA-Q system!\n"); + if (mpc->mpc_oemptr) + smp_read_mpc_oem((struct mp_config_oemtable *) mpc->mpc_oemptr, + mpc->mpc_oemsize); +} +#endif /* CONFIG_X86_NUMAQ */ + /* * Read/parse the MPC */ static int __init smp_read_mpc(struct mp_config_table *mpc) { - char oem[16], prod[14]; + char str[16]; + char oem[10]; int count=sizeof(*mpc); unsigned char *mpt=((unsigned char *)mpc)+count; - int num_bus = 0; - int num_irq = 0; - unsigned char *bus_data; if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) { - panic("SMP mptable: bad signature [%c%c%c%c]!\n", - mpc->mpc_signature[0], - mpc->mpc_signature[1], - mpc->mpc_signature[2], - mpc->mpc_signature[3]); + printk(KERN_ERR "SMP mptable: bad signature [0x%x]!\n", + *(u32 *)mpc->mpc_signature); return 0; } if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) { - panic("SMP mptable: checksum error!\n"); + printk(KERN_ERR "SMP mptable: checksum error!\n"); return 0; } if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) { @@ -438,14 +402,14 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) } memcpy(oem,mpc->mpc_oem,8); oem[8]=0; - printk("OEM ID: %s ",oem); + printk(KERN_INFO "OEM ID: %s ",oem); - memcpy(prod,mpc->mpc_productid,12); - prod[12]=0; - printk("Product ID: %s ",prod); + memcpy(str,mpc->mpc_productid,12); + str[12]=0; + printk("Product ID: %s ",str); + + mps_oem_check(mpc, oem, str); - detect_clustered_apic(oem, prod); - printk("APIC at: 0x%X\n",mpc->mpc_lapic); /* @@ -455,77 +419,10 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) if (!acpi_lapic) mp_lapic_addr = mpc->mpc_lapic; - if ((clustered_apic_mode == CLUSTERED_APIC_NUMAQ) && mpc->mpc_oemptr) { - /* We need to process the oem mpc tables to tell us which quad things are in ... */ - mpc_record = 0; - smp_read_mpc_oem((struct mp_config_oemtable *)(unsigned long)mpc->mpc_oemptr, mpc->mpc_oemsize); - mpc_record = 0; - } - - /* Pre-scan to determine the number of bus and - * interrupts records we have - */ - while (count < mpc->mpc_length) { - switch (*mpt) { - case MP_PROCESSOR: - mpt += sizeof(struct mpc_config_processor); - count += sizeof(struct mpc_config_processor); - break; - case MP_BUS: - ++num_bus; - mpt += sizeof(struct mpc_config_bus); - count += sizeof(struct mpc_config_bus); - break; - case MP_INTSRC: - ++num_irq; - mpt += sizeof(struct mpc_config_intsrc); - count += sizeof(struct mpc_config_intsrc); - break; - case MP_IOAPIC: - mpt += sizeof(struct mpc_config_ioapic); - count += sizeof(struct mpc_config_ioapic); - break; - case MP_LINTSRC: - mpt += sizeof(struct mpc_config_lintsrc); - count += sizeof(struct mpc_config_lintsrc); - break; - default: - count = mpc->mpc_length; - break; - } - } - /* - * Paranoia: Allocate one extra of both the number of busses and number - * of irqs, and make sure that we have at least 4 interrupts per PCI - * slot. But some machines do not report very many busses, so we need - * to fall back on the older defaults. - */ - ++num_bus; - max_mp_busses = max(num_bus, MAX_MP_BUSSES); - if (num_irq < (4 * max_mp_busses)) - num_irq = 4 * num_bus; /* 4 intr/PCI slot */ - ++num_irq; - max_irq_sources = max(num_irq, MAX_IRQ_SOURCES); - - count = (max_mp_busses * sizeof(int)) * 4; - count += (max_irq_sources * sizeof(struct mpc_config_intsrc)); - bus_data = (void *)alloc_xenheap_pages(get_order(count)); - if (!bus_data) { - printk(KERN_ERR "SMP mptable: out of memory!\n"); - return 0; - } - mp_bus_id_to_type = (int *)&bus_data[0]; - mp_bus_id_to_node = (int *)&bus_data[(max_mp_busses * sizeof(int))]; - mp_bus_id_to_local = (int *)&bus_data[(max_mp_busses * sizeof(int)) * 2]; - mp_bus_id_to_pci_bus = (int *)&bus_data[(max_mp_busses * sizeof(int)) * 3]; - mp_irqs = (struct mpc_config_intsrc *)&bus_data[(max_mp_busses * sizeof(int)) * 4]; - memset(mp_bus_id_to_pci_bus, -1, max_mp_busses * sizeof(int)); - /* * Now process the configuration blocks. */ - count = sizeof(*mpc); - mpt = ((unsigned char *)mpc)+count; + mpc_record = 0; while (count < mpc->mpc_length) { switch(*mpt) { case MP_PROCESSOR: @@ -584,21 +481,7 @@ static int __init smp_read_mpc(struct mp_config_table *mpc) } ++mpc_record; } - - if (clustered_apic_mode){ - phys_cpu_present_map = logical_cpu_present_map; - } - - - printk("Enabling APIC mode: "); - if(clustered_apic_mode == CLUSTERED_APIC_NUMAQ) - printk("Clustered Logical. "); - else if(clustered_apic_mode == CLUSTERED_APIC_XAPIC) - printk("Physical. "); - else - printk("Flat. "); - printk("Using %d I/O APICs\n",nr_ioapics); - + clustered_apic_check(); if (!num_processors) printk(KERN_ERR "SMP mptable: no processors registered!\n"); return num_processors; @@ -634,12 +517,12 @@ static void __init construct_default_ioirq_mptable(int mpc_default_type) * If it does, we assume it's valid. */ if (mpc_default_type == 5) { - printk("ISA/PCI bus type with no IRQ information... falling back to ELCR\n"); + printk(KERN_INFO "ISA/PCI bus type with no IRQ information... falling back to ELCR\n"); if (ELCR_trigger(0) || ELCR_trigger(1) || ELCR_trigger(2) || ELCR_trigger(13)) - printk("ELCR contains invalid data... not using ELCR\n"); + printk(KERN_WARNING "ELCR contains invalid data... not using ELCR\n"); else { - printk("Using ELCR to identify PCI interrupts\n"); + printk(KERN_INFO "Using ELCR to identify PCI interrupts\n"); ELCR_fallback = 1; } } @@ -686,24 +569,6 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type) struct mpc_config_lintsrc lintsrc; int linttypes[2] = { mp_ExtINT, mp_NMI }; int i; - struct { - int mp_bus_id_to_type[MAX_MP_BUSSES]; - int mp_bus_id_to_node[MAX_MP_BUSSES]; - int mp_bus_id_to_local[MAX_MP_BUSSES]; - int mp_bus_id_to_pci_bus[MAX_MP_BUSSES]; - struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; - } *bus_data; - - bus_data = (void *)alloc_xenheap_pages(get_order(sizeof(*bus_data))); - if (!bus_data) - panic("SMP mptable: out of memory!\n"); - mp_bus_id_to_type = bus_data->mp_bus_id_to_type; - mp_bus_id_to_node = bus_data->mp_bus_id_to_node; - mp_bus_id_to_local = bus_data->mp_bus_id_to_local; - mp_bus_id_to_pci_bus = bus_data->mp_bus_id_to_pci_bus; - mp_irqs = bus_data->mp_irqs; - for (i = 0; i < MAX_MP_BUSSES; ++i) - mp_bus_id_to_pci_bus[i] = -1; /* * local APIC has default address @@ -732,7 +597,8 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type) bus.mpc_busid = 0; switch (mpc_default_type) { default: - printk("???\nUnknown standard configuration %d\n", + printk("???\n"); + printk(KERN_ERR "Unknown standard configuration %d\n", mpc_default_type); /* fall through */ case 1: @@ -790,7 +656,7 @@ void __init get_smp_config (void) /* * ACPI may be used to obtain the entire SMP configuration or just to - * enumerate/configure processors (CONFIG_ACPI_HT_ONLY). Note that + * enumerate/configure processors (CONFIG_ACPI_BOOT). Note that * ACPI supports both logical (e.g. Hyper-Threading) and physical * processors, where MPS only supports physical. */ @@ -801,12 +667,12 @@ void __init get_smp_config (void) else if (acpi_lapic) printk(KERN_INFO "Using ACPI for processor (LAPIC) configuration information\n"); - printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); + printk(KERN_INFO "Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification); if (mpf->mpf_feature2 & (1<<7)) { - printk(" IMCR and PIC compatibility mode.\n"); + printk(KERN_INFO " IMCR and PIC compatibility mode.\n"); pic_mode = 1; } else { - printk(" Virtual Wire compatibility mode.\n"); + printk(KERN_INFO " Virtual Wire compatibility mode.\n"); pic_mode = 0; } @@ -815,7 +681,7 @@ void __init get_smp_config (void) */ if (mpf->mpf_feature1 != 0) { - printk("Default MP configuration #%d\n", mpf->mpf_feature1); + printk(KERN_INFO "Default MP configuration #%d\n", mpf->mpf_feature1); construct_default_ISA_mptable(mpf->mpf_feature1); } else if (mpf->mpf_physptr) { @@ -824,7 +690,7 @@ void __init get_smp_config (void) * Read the physical hardware table. Anything here will * override the defaults. */ - if (!smp_read_mpc((void *)(unsigned long)mpf->mpf_physptr)) { + if (!smp_read_mpc((void *)mpf->mpf_physptr)) { smp_found_config = 0; printk(KERN_ERR "BIOS bug, MP table errors detected!...\n"); printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n"); @@ -838,7 +704,7 @@ void __init get_smp_config (void) if (!mp_irq_entries) { struct mpc_config_bus bus; - printk("BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n"); + printk(KERN_ERR "BIOS bug, no explicit IRQ entries, using default mptable. (tell your hw vendor)\n"); bus.mpc_type = MP_BUS; bus.mpc_busid = 0; @@ -851,7 +717,7 @@ void __init get_smp_config (void) } else BUG(); - printk("Processors: %d\n", num_processors); + printk(KERN_INFO "Processors: %d\n", num_processors); /* * Only use the first configuration found. */ @@ -859,7 +725,7 @@ void __init get_smp_config (void) static int __init smp_scan_config (unsigned long base, unsigned long length) { - unsigned int *bp = phys_to_virt(base); + unsigned long *bp = phys_to_virt(base); struct intel_mp_floating *mpf; Dprintk("Scan SMP from %p for %ld bytes.\n", bp,length); @@ -875,11 +741,27 @@ static int __init smp_scan_config (unsigned long base, unsigned long length) || (mpf->mpf_specification == 4)) ) { smp_found_config = 1; - printk("found SMP MP-table at %08lx\n", + printk(KERN_INFO "found SMP MP-table at %08lx\n", virt_to_phys(mpf)); +#if 0 reserve_bootmem(virt_to_phys(mpf), PAGE_SIZE); - if (mpf->mpf_physptr) - reserve_bootmem((unsigned long)mpf->mpf_physptr, PAGE_SIZE); + if (mpf->mpf_physptr) { + /* + * We cannot access to MPC table to compute + * table size yet, as only few megabytes from + * the bottom is mapped now. + * PC-9800's MPC table places on the very last + * of physical memory; so that simply reserving + * PAGE_SIZE from mpg->mpf_physptr yields BUG() + * in reserve_bootmem. + */ + unsigned long size = PAGE_SIZE; + unsigned long end = max_low_pfn * PAGE_SIZE; + if (mpf->mpf_physptr + size > end) + size = end - mpf->mpf_physptr; + reserve_bootmem(mpf->mpf_physptr, size); + } +#endif mpf_found = mpf; return 1; } @@ -889,7 +771,7 @@ static int __init smp_scan_config (unsigned long base, unsigned long length) return 0; } -void __init find_intel_smp (void) +void __init find_smp_config (void) { unsigned int address; @@ -913,53 +795,20 @@ void __init find_intel_smp (void) * there is a real-mode segmented pointer pointing to the * 4K EBDA area at 0x40E, calculate and scan it here. * - * NOTE! There were Linux loaders that will corrupt the EBDA + * NOTE! There are Linux loaders that will corrupt the EBDA * area, and as such this kind of SMP config may be less * trustworthy, simply because the SMP table may have been - * stomped on during early boot. Thankfully the bootloaders - * now honour the EBDA. + * stomped on during early boot. These loaders are buggy and + * should be fixed. + * + * MP1.4 SPEC states to only scan first 1K of 4K EBDA. */ - address = *(unsigned short *)phys_to_virt(0x40E); - address <<= 4; - smp_scan_config(address, 0x1000); + address = get_bios_ebda(); + if (address) + smp_scan_config(address, 0x400); } -#else - -/* - * The Visual Workstation is Intel MP compliant in the hardware - * sense, but it doesn't have a BIOS(-configuration table). - * No problem for Linux. - */ -void __init find_visws_smp(void) -{ - smp_found_config = 1; - - phys_cpu_present_map |= 2; /* or in id 1 */ - apic_version[1] |= 0x10; /* integrated APIC */ - apic_version[0] |= 0x10; - - mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; -} - -#endif - -/* - * - Intel MP Configuration Table - * - or SGI Visual Workstation configuration - */ -void __init find_smp_config (void) -{ -#ifdef CONFIG_X86_LOCAL_APIC - find_intel_smp(); -#endif -#ifdef CONFIG_VISWS - find_visws_smp(); -#endif -} - - /* -------------------------------------------------------------------------- ACPI-based MP Configuration -------------------------------------------------------------------------- */ @@ -987,7 +836,7 @@ void __init mp_register_lapic ( struct mpc_config_processor processor; int boot_cpu = 0; - if (id >= MAX_APICS) { + if (MAX_APICS - id <= 0) { printk(KERN_WARNING "Processor #%d invalid (max %d)\n", id, MAX_APICS); return; @@ -998,14 +847,7 @@ void __init mp_register_lapic ( processor.mpc_type = MP_PROCESSOR; processor.mpc_apicid = id; - - /* - * mp_register_lapic_address() which is called before the - * current function does the fixmap of FIX_APIC_BASE. - * Read in the correct APIC version from there - */ - processor.mpc_apicver = apic_read(APIC_LVR); - + processor.mpc_apicver = GET_APIC_VERSION(apic_read(APIC_LVR)); processor.mpc_cpuflag = (enabled ? CPU_ENABLED : 0); processor.mpc_cpuflag |= (boot_cpu ? CPU_BOOTPROCESSOR : 0); processor.mpc_cpufeature = (boot_cpu_data.x86 << 8) | @@ -1017,32 +859,32 @@ void __init mp_register_lapic ( MP_processor_info(&processor); } -#if defined(CONFIG_X86_IO_APIC) /*&& defined(CONFIG_ACPI_INTERPRETER)*/ +#if defined(CONFIG_X86_IO_APIC) && (defined(CONFIG_ACPI_INTERPRETER) || defined(CONFIG_ACPI_BOOT)) #define MP_ISA_BUS 0 #define MP_MAX_IOAPIC_PIN 127 struct mp_ioapic_routing { int apic_id; - int irq_start; - int irq_end; + int gsi_base; + int gsi_end; u32 pin_programmed[4]; } mp_ioapic_routing[MAX_IO_APICS]; -static int __init mp_find_ioapic ( - int irq) +static int mp_find_ioapic ( + int gsi) { int i = 0; - /* Find the IOAPIC that manages this IRQ. */ + /* Find the IOAPIC that manages this GSI. */ for (i = 0; i < nr_ioapics; i++) { - if ((irq >= mp_ioapic_routing[i].irq_start) - && (irq <= mp_ioapic_routing[i].irq_end)) + if ((gsi >= mp_ioapic_routing[i].gsi_base) + && (gsi <= mp_ioapic_routing[i].gsi_end)) return i; } - printk(KERN_ERR "ERROR: Unable to locate IOAPIC for IRQ %d\n", irq); + printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi); return -1; } @@ -1051,7 +893,7 @@ static int __init mp_find_ioapic ( void __init mp_register_ioapic ( u8 id, u32 address, - u32 irq_base) + u32 gsi_base) { int idx = 0; @@ -1077,19 +919,19 @@ void __init mp_register_ioapic ( mp_ioapics[idx].mpc_apicver = io_apic_get_version(idx); /* - * Build basic IRQ lookup table to facilitate irq->io_apic lookups - * and to prevent reprogramming of IOAPIC pins (PCI IRQs). + * Build basic GSI lookup table to facilitate gsi->io_apic lookups + * and to prevent reprogramming of IOAPIC pins (PCI GSIs). */ mp_ioapic_routing[idx].apic_id = mp_ioapics[idx].mpc_apicid; - mp_ioapic_routing[idx].irq_start = irq_base; - mp_ioapic_routing[idx].irq_end = irq_base + + mp_ioapic_routing[idx].gsi_base = gsi_base; + mp_ioapic_routing[idx].gsi_end = gsi_base + io_apic_get_redir_entries(idx); printk("IOAPIC[%d]: apic_id %d, version %d, address 0x%x, " - "IRQ %d-%d\n", idx, mp_ioapics[idx].mpc_apicid, + "GSI %d-%d\n", idx, mp_ioapics[idx].mpc_apicid, mp_ioapics[idx].mpc_apicver, mp_ioapics[idx].mpc_apicaddr, - mp_ioapic_routing[idx].irq_start, - mp_ioapic_routing[idx].irq_end); + mp_ioapic_routing[idx].gsi_base, + mp_ioapic_routing[idx].gsi_end); return; } @@ -1099,21 +941,19 @@ void __init mp_override_legacy_irq ( u8 bus_irq, u8 polarity, u8 trigger, - u32 global_irq) + u32 gsi) { struct mpc_config_intsrc intsrc; - int i = 0; - int found = 0; int ioapic = -1; int pin = -1; /* - * Convert 'global_irq' to 'ioapic.pin'. + * Convert 'gsi' to 'ioapic.pin'. */ - ioapic = mp_find_ioapic(global_irq); + ioapic = mp_find_ioapic(gsi); if (ioapic < 0) return; - pin = global_irq - mp_ioapic_routing[ioapic].irq_start; + pin = gsi - mp_ioapic_routing[ioapic].gsi_base; /* * TBD: This check is for faulty timer entries, where the override @@ -1136,23 +976,9 @@ void __init mp_override_legacy_irq ( (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus, intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, intsrc.mpc_dstirq); - /* - * If an existing [IOAPIC.PIN -> IRQ] routing entry exists we override it. - * Otherwise create a new entry (e.g. global_irq == 2). - */ - for (i = 0; i < mp_irq_entries; i++) { - if ((mp_irqs[i].mpc_srcbus == intsrc.mpc_srcbus) - && (mp_irqs[i].mpc_srcbusirq == intsrc.mpc_srcbusirq)) { - mp_irqs[i] = intsrc; - found = 1; - break; - } - } - if (!found) { - mp_irqs[mp_irq_entries] = intsrc; - if (++mp_irq_entries == MAX_IRQ_SOURCES) - panic("Max # of irq sources exceeded!\n"); - } + mp_irqs[mp_irq_entries] = intsrc; + if (++mp_irq_entries == MAX_IRQ_SOURCES) + panic("Max # of irq sources exceeded!\n"); return; } @@ -1160,35 +986,22 @@ void __init mp_override_legacy_irq ( void __init mp_config_acpi_legacy_irqs (void) { + struct mpc_config_intsrc intsrc; int i = 0; int ioapic = -1; - /* - * Initialize mp_irqs for IRQ configuration. - */ - unsigned char *bus_data; - int count; - - count = (MAX_MP_BUSSES * sizeof(int)) * 4; - count += (MAX_IRQ_SOURCES * sizeof(int)) * 4; - bus_data = (void *)alloc_xenheap_pages(get_order(count)); - if (!bus_data) { - panic("Fatal: can't allocate bus memory for ACPI legacy IRQ!"); - } - mp_bus_id_to_type = (int *)&bus_data[0]; - mp_bus_id_to_node = (int *)&bus_data[(MAX_MP_BUSSES * sizeof(int))]; - mp_bus_id_to_local = (int *)&bus_data[(MAX_MP_BUSSES * sizeof(int)) * 2]; - mp_bus_id_to_pci_bus = (int *)&bus_data[(MAX_MP_BUSSES * sizeof(int)) * 3]; - mp_irqs = (struct mpc_config_intsrc *)&bus_data[(MAX_MP_BUSSES * sizeof(int)) * 4]; - for (i = 0; i < MAX_MP_BUSSES; ++i) - mp_bus_id_to_pci_bus[i] = -1; - /* * Fabricate the legacy ISA bus (bus #31). */ mp_bus_id_to_type[MP_ISA_BUS] = MP_BUS_ISA; Dprintk("Bus #%d is ISA\n", MP_ISA_BUS); + /* + * ES7000 has no legacy identity mappings + */ + if (es7000_plat) + return; + /* * Locate the IOAPIC that manages the ISA IRQs (0-15). */ @@ -1196,118 +1009,101 @@ void __init mp_config_acpi_legacy_irqs (void) if (ioapic < 0) return; + intsrc.mpc_type = MP_INTSRC; + intsrc.mpc_irqflag = 0; /* Conforming */ + intsrc.mpc_srcbus = MP_ISA_BUS; + intsrc.mpc_dstapic = mp_ioapics[ioapic].mpc_apicid; + /* - * Use the default configuration for the IRQs 0-15. These may be + * Use the default configuration for the IRQs 0-15. Unless * overriden by (MADT) interrupt source override entries. */ for (i = 0; i < 16; i++) { + int idx; - if (i == 2) - continue; /* Don't connect IRQ2 */ + for (idx = 0; idx < mp_irq_entries; idx++) { + struct mpc_config_intsrc *irq = mp_irqs + idx; - mp_irqs[mp_irq_entries].mpc_type = MP_INTSRC; - mp_irqs[mp_irq_entries].mpc_irqflag = 0; /* Conforming */ - mp_irqs[mp_irq_entries].mpc_srcbus = MP_ISA_BUS; - mp_irqs[mp_irq_entries].mpc_dstapic = mp_ioapics[ioapic].mpc_apicid; - mp_irqs[mp_irq_entries].mpc_irqtype = mp_INT; - mp_irqs[mp_irq_entries].mpc_srcbusirq = i; /* Identity mapped */ - mp_irqs[mp_irq_entries].mpc_dstirq = i; + /* Do we already have a mapping for this ISA IRQ? */ + if (irq->mpc_srcbus == MP_ISA_BUS && irq->mpc_srcbusirq == i) + break; + + /* Do we already have a mapping for this IOAPIC pin */ + if ((irq->mpc_dstapic == intsrc.mpc_dstapic) && + (irq->mpc_dstirq == i)) + break; + } + + if (idx != mp_irq_entries) { + printk(KERN_DEBUG "ACPI: IRQ%d used by override.\n", i); + continue; /* IRQ already used */ + } + + intsrc.mpc_irqtype = mp_INT; + intsrc.mpc_srcbusirq = i; /* Identity mapped */ + intsrc.mpc_dstirq = i; Dprintk("Int: type %d, pol %d, trig %d, bus %d, irq %d, " - "%d-%d\n", - mp_irqs[mp_irq_entries].mpc_irqtype, - mp_irqs[mp_irq_entries].mpc_irqflag & 3, - (mp_irqs[mp_irq_entries].mpc_irqflag >> 2) & 3, - mp_irqs[mp_irq_entries].mpc_srcbus, - mp_irqs[mp_irq_entries].mpc_srcbusirq, - mp_irqs[mp_irq_entries].mpc_dstapic, - mp_irqs[mp_irq_entries].mpc_dstirq); + "%d-%d\n", intsrc.mpc_irqtype, intsrc.mpc_irqflag & 3, + (intsrc.mpc_irqflag >> 2) & 3, intsrc.mpc_srcbus, + intsrc.mpc_srcbusirq, intsrc.mpc_dstapic, + intsrc.mpc_dstirq); + mp_irqs[mp_irq_entries] = intsrc; if (++mp_irq_entries == MAX_IRQ_SOURCES) panic("Max # of irq sources exceeded!\n"); } } -#ifdef CONFIG_ACPI_PCI - -void __init mp_parse_prt (void) +int mp_register_gsi (u32 gsi, int edge_level, int active_high_low) { - struct acpi_prt_entry *entry = NULL; int ioapic = -1; int ioapic_pin = 0; - int irq = 0; int idx, bit = 0; - int edge_level = 0; - int active_high_low = 0; - /* - * Parsing through the PCI Interrupt Routing Table (PRT) and program - * routing for all entries. - */ - list_for_each_entry(entry, &acpi_prt.entries, node) { - /* Need to get irq for dynamic entry */ - if (entry->link.handle) { - irq = acpi_pci_link_get_irq(entry->link.handle, entry->link.index, &edge_level, &active_high_low); - if (!irq) - continue; - } - else { - /* Hardwired IRQ. Assume PCI standard settings */ - irq = entry->link.index; - edge_level = 1; - active_high_low = 1; - } +#ifdef CONFIG_ACPI_BUS + /* Don't set up the ACPI SCI because it's already set up */ + if (acpi_fadt.sci_int == gsi) + return gsi; +#endif - /* Don't set up the ACPI SCI because it's already set up */ - if (acpi_fadt.sci_int == irq) { - entry->irq = irq; /*we still need to set entry's irq*/ - continue; - } - - ioapic = mp_find_ioapic(irq); - if (ioapic < 0) - continue; - ioapic_pin = irq - mp_ioapic_routing[ioapic].irq_start; - - /* - * Avoid pin reprogramming. PRTs typically include entries - * with redundant pin->irq mappings (but unique PCI devices); - * we only only program the IOAPIC on the first. - */ - bit = ioapic_pin % 32; - idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32); - if (idx > 3) { - printk(KERN_ERR "Invalid reference to IOAPIC pin " - "%d-%d\n", mp_ioapic_routing[ioapic].apic_id, - ioapic_pin); - continue; - } - if ((1<irq = irq; - continue; - } - - mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<irq = irq; - - printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d -> IRQ %d\n", - entry->id.segment, entry->id.bus, - entry->id.device, ('A' + entry->pin), - mp_ioapic_routing[ioapic].apic_id, ioapic_pin, - entry->irq); + ioapic = mp_find_ioapic(gsi); + if (ioapic < 0) { + printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi); + return gsi; } - - print_IO_APIC(); - return; + ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base; + + if (ioapic_renumber_irq) + gsi = ioapic_renumber_irq(ioapic, gsi); + + /* + * Avoid pin reprogramming. PRTs typically include entries + * with redundant pin->gsi mappings (but unique PCI devices); + * we only program the IOAPIC on the first. + */ + bit = ioapic_pin % 32; + idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32); + if (idx > 3) { + printk(KERN_ERR "Invalid reference to IOAPIC pin " + "%d-%d\n", mp_ioapic_routing[ioapic].apic_id, + ioapic_pin); + return gsi; + } + if ((1< #include #include +#include #include #include #include diff --git a/xen/arch/x86/nmi.c b/xen/arch/x86/nmi.c index ee798f9a36..afdf8051bb 100644 --- a/xen/arch/x86/nmi.c +++ b/xen/arch/x86/nmi.c @@ -86,24 +86,20 @@ extern int logical_proc_id[]; int __init check_nmi_watchdog (void) { unsigned int prev_nmi_count[NR_CPUS]; - int j, cpu; + int cpu; if ( !nmi_watchdog ) return 0; printk("Testing NMI watchdog --- "); - for ( j = 0; j < smp_num_cpus; j++ ) - { - cpu = cpu_logical_map(j); + for ( cpu = 0; cpu < smp_num_cpus; cpu++ ) prev_nmi_count[cpu] = nmi_count(cpu); - } __sti(); mdelay((10*1000)/nmi_hz); /* wait 10 ticks */ - for ( j = 0; j < smp_num_cpus; j++ ) + for ( cpu = 0; cpu < smp_num_cpus; cpu++ ) { - cpu = cpu_logical_map(j); if ( nmi_count(cpu) - prev_nmi_count[cpu] <= 5 ) printk("CPU#%d stuck. ", cpu); else diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c index 66e0ed1251..5de96ec96d 100644 --- a/xen/arch/x86/physdev.c +++ b/xen/arch/x86/physdev.c @@ -10,8 +10,6 @@ #include #include -extern void (*interrupt[])(void); - extern int ioapic_guest_read(int apicid, int address, u32 *pval); extern int ioapic_guest_write(int apicid, int address, u32 pval); diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index 981a36d97d..7a3abe9913 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -48,8 +48,8 @@ #include #include #include - -#ifdef CONFIG_SMP +#include +#include /* Cconfigured maximum number of CPUs to activate. We name the parameter "maxcpus" rather than max_cpus to be compatible with Linux */ @@ -63,10 +63,10 @@ int smp_num_cpus = 1; int ht_per_core = 1; /* Bitmask of currently online CPUs */ -unsigned long cpu_online_map; +cpumask_t cpu_online_map; -static volatile unsigned long cpu_callin_map; -static volatile unsigned long cpu_callout_map; +cpumask_t cpu_callin_map; +cpumask_t cpu_callout_map; /* Per CPU bogomips and other parameters */ struct cpuinfo_x86 cpu_data[NR_CPUS]; @@ -800,7 +800,8 @@ void __init smp_boot_cpus(void) if (!smp_found_config) { printk("SMP motherboard not detected.\n"); io_apic_irqs = 0; - cpu_online_map = phys_cpu_present_map = 1; + phys_cpu_present_map = physid_mask_of_physid(0); + cpu_online_map = 1; smp_num_cpus = 1; if (APIC_init_uniprocessor()) printk("Local APIC not detected." @@ -815,7 +816,7 @@ void __init smp_boot_cpus(void) if (!test_bit(boot_cpu_physical_apicid, &phys_cpu_present_map)) { printk("weird, boot CPU (#%d) not listed by the BIOS.\n", boot_cpu_physical_apicid); - phys_cpu_present_map |= (1 << hard_smp_processor_id()); + physid_set(hard_smp_processor_id(), phys_cpu_present_map); } /* @@ -827,7 +828,8 @@ void __init smp_boot_cpus(void) boot_cpu_physical_apicid); printk("... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); io_apic_irqs = 0; - cpu_online_map = phys_cpu_present_map = 1; + phys_cpu_present_map = physid_mask_of_physid(0); + cpu_online_map = 1; smp_num_cpus = 1; goto smp_done; } @@ -841,7 +843,8 @@ void __init smp_boot_cpus(void) smp_found_config = 0; printk("SMP mode deactivated, forcing use of dummy APIC emulation.\n"); io_apic_irqs = 0; - cpu_online_map = phys_cpu_present_map = 1; + phys_cpu_present_map = physid_mask_of_physid(0); + cpu_online_map = 1; smp_num_cpus = 1; goto smp_done; } @@ -875,7 +878,7 @@ void __init smp_boot_cpus(void) if (opt_noht && (apicid & (ht_per_core - 1))) continue; - if (!(phys_cpu_present_map & (1 << bit))) + if (!check_apicid_present(bit)) continue; if ((max_cpus >= 0) && (max_cpus <= cpucount+1)) continue; @@ -886,7 +889,7 @@ void __init smp_boot_cpus(void) * Make sure we unmap all failed CPUs */ if ((boot_apicid_to_cpu(apicid) == -1) && - (phys_cpu_present_map & (1 << bit))) + (!check_apicid_present(bit))) printk("CPU #%d not responding - cannot use it.\n", apicid); } @@ -923,7 +926,10 @@ void __init smp_boot_cpus(void) if ( nr_ioapics ) setup_IO_APIC(); /* Set up all local APIC timers in the system. */ - setup_APIC_clocks(); + { + extern void setup_APIC_clocks(void); + setup_APIC_clocks(); + } /* Synchronize the TSC with the AP(s). */ if ( cpucount ) synchronize_tsc_bp(); @@ -932,8 +938,6 @@ void __init smp_boot_cpus(void) ; } -#endif /* CONFIG_SMP */ - /* * Local variables: * mode: C diff --git a/xen/arch/x86/x86_32/asm-offsets.c b/xen/arch/x86/x86_32/asm-offsets.c index 7015b2a861..b440b0501e 100644 --- a/xen/arch/x86/x86_32/asm-offsets.c +++ b/xen/arch/x86/x86_32/asm-offsets.c @@ -90,7 +90,7 @@ void __dummy__(void) OFFSET(MULTICALL_result, multicall_entry_t, args[5]); BLANK(); - DEFINE(FIXMAP_apic_base, fix_to_virt(FIX_APIC_BASE)); + DEFINE(FIXMAP_apic_base, __fix_to_virt(FIX_APIC_BASE)); BLANK(); DEFINE(IRQSTAT_shift, LOG_2(sizeof(irq_cpustat_t))); diff --git a/xen/arch/x86/x86_32/mm.c b/xen/arch/x86/x86_32/mm.c index 045d904c21..e88195a8e1 100644 --- a/xen/arch/x86/x86_32/mm.c +++ b/xen/arch/x86/x86_32/mm.c @@ -83,7 +83,7 @@ void __set_fixmap( { if ( unlikely(idx >= __end_of_fixed_addresses) ) BUG(); - map_pages(idle_pg_table, fix_to_virt(idx), p, PAGE_SIZE, flags); + map_pages(idle_pg_table, __fix_to_virt(idx), p, PAGE_SIZE, flags); } diff --git a/xen/arch/x86/x86_32/traps.c b/xen/arch/x86/x86_32/traps.c index bd14acde01..d3453802b9 100644 --- a/xen/arch/x86/x86_32/traps.c +++ b/xen/arch/x86/x86_32/traps.c @@ -273,12 +273,8 @@ long set_fast_trap(struct exec_domain *p, int idx) return 0; } - /* - * We only fast-trap vectors 0x20-0x2f, and vector 0x80. - * The former range is used by Windows and MS-DOS. - * Vector 0x80 is used by Linux and the BSD variants. - */ - if ( (idx != 0x80) && ((idx < 0x20) || (idx > 0x2f)) ) + /* We only fast-trap vector 0x80 (used by Linux and the BSD variants). */ + if ( idx != 0x80 ) return -1; ti = &p->arch.guest_context.trap_ctxt[idx]; diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c index a1db5acd05..3becac2024 100644 --- a/xen/arch/x86/x86_64/mm.c +++ b/xen/arch/x86/x86_64/mm.c @@ -125,7 +125,7 @@ void __set_fixmap( { if ( unlikely(idx >= __end_of_fixed_addresses) ) BUG(); - map_pages(idle_pg_table, fix_to_virt(idx), p, PAGE_SIZE, flags); + map_pages(idle_pg_table, __fix_to_virt(idx), p, PAGE_SIZE, flags); } diff --git a/xen/common/bitmap.c b/xen/common/bitmap.c new file mode 100644 index 0000000000..d931eca83c --- /dev/null +++ b/xen/common/bitmap.c @@ -0,0 +1,365 @@ +/* + * lib/bitmap.c + * Helper functions for bitmap.h. + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ +#include +#include +#include +#include +#include +#include + +/* + * bitmaps provide an array of bits, implemented using an an + * array of unsigned longs. The number of valid bits in a + * given bitmap does _not_ need to be an exact multiple of + * BITS_PER_LONG. + * + * The possible unused bits in the last, partially used word + * of a bitmap are 'don't care'. The implementation makes + * no particular effort to keep them zero. It ensures that + * their value will not affect the results of any operation. + * The bitmap operations that return Boolean (bitmap_empty, + * for example) or scalar (bitmap_weight, for example) results + * carefully filter out these unused bits from impacting their + * results. + * + * These operations actually hold to a slightly stronger rule: + * if you don't input any bitmaps to these ops that have some + * unused bits set, then they won't output any set unused bits + * in output bitmaps. + * + * The byte ordering of bitmaps is more natural on little + * endian architectures. See the big-endian headers + * include/asm-ppc64/bitops.h and include/asm-s390/bitops.h + * for the best explanations of this ordering. + */ + +int __bitmap_empty(const unsigned long *bitmap, int bits) +{ + int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (bitmap[k]) + return 0; + + if (bits % BITS_PER_LONG) + if (bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) + return 0; + + return 1; +} +EXPORT_SYMBOL(__bitmap_empty); + +int __bitmap_full(const unsigned long *bitmap, int bits) +{ + int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (~bitmap[k]) + return 0; + + if (bits % BITS_PER_LONG) + if (~bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) + return 0; + + return 1; +} +EXPORT_SYMBOL(__bitmap_full); + +int __bitmap_equal(const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits) +{ + int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (bitmap1[k] != bitmap2[k]) + return 0; + + if (bits % BITS_PER_LONG) + if ((bitmap1[k] ^ bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) + return 0; + + return 1; +} +EXPORT_SYMBOL(__bitmap_equal); + +void __bitmap_complement(unsigned long *dst, const unsigned long *src, int bits) +{ + int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + dst[k] = ~src[k]; + + if (bits % BITS_PER_LONG) + dst[k] = ~src[k] & BITMAP_LAST_WORD_MASK(bits); +} +EXPORT_SYMBOL(__bitmap_complement); + +/* + * __bitmap_shift_right - logical right shift of the bits in a bitmap + * @dst - destination bitmap + * @src - source bitmap + * @nbits - shift by this many bits + * @bits - bitmap size, in bits + * + * Shifting right (dividing) means moving bits in the MS -> LS bit + * direction. Zeros are fed into the vacated MS positions and the + * LS bits shifted off the bottom are lost. + */ +void __bitmap_shift_right(unsigned long *dst, + const unsigned long *src, int shift, int bits) +{ + int k, lim = BITS_TO_LONGS(bits), left = bits % BITS_PER_LONG; + int off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG; + unsigned long mask = (1UL << left) - 1; + for (k = 0; off + k < lim; ++k) { + unsigned long upper, lower; + + /* + * If shift is not word aligned, take lower rem bits of + * word above and make them the top rem bits of result. + */ + if (!rem || off + k + 1 >= lim) + upper = 0; + else { + upper = src[off + k + 1]; + if (off + k + 1 == lim - 1 && left) + upper &= mask; + } + lower = src[off + k]; + if (left && off + k == lim - 1) + lower &= mask; + dst[k] = upper << (BITS_PER_LONG - rem) | lower >> rem; + if (left && k == lim - 1) + dst[k] &= mask; + } + if (off) + memset(&dst[lim - off], 0, off*sizeof(unsigned long)); +} +EXPORT_SYMBOL(__bitmap_shift_right); + + +/* + * __bitmap_shift_left - logical left shift of the bits in a bitmap + * @dst - destination bitmap + * @src - source bitmap + * @nbits - shift by this many bits + * @bits - bitmap size, in bits + * + * Shifting left (multiplying) means moving bits in the LS -> MS + * direction. Zeros are fed into the vacated LS bit positions + * and those MS bits shifted off the top are lost. + */ + +void __bitmap_shift_left(unsigned long *dst, + const unsigned long *src, int shift, int bits) +{ + int k, lim = BITS_TO_LONGS(bits), left = bits % BITS_PER_LONG; + int off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG; + for (k = lim - off - 1; k >= 0; --k) { + unsigned long upper, lower; + + /* + * If shift is not word aligned, take upper rem bits of + * word below and make them the bottom rem bits of result. + */ + if (rem && k > 0) + lower = src[k - 1]; + else + lower = 0; + upper = src[k]; + if (left && k == lim - 1) + upper &= (1UL << left) - 1; + dst[k + off] = lower >> (BITS_PER_LONG - rem) | upper << rem; + if (left && k + off == lim - 1) + dst[k + off] &= (1UL << left) - 1; + } + if (off) + memset(dst, 0, off*sizeof(unsigned long)); +} +EXPORT_SYMBOL(__bitmap_shift_left); + +void __bitmap_and(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits) +{ + int k; + int nr = BITS_TO_LONGS(bits); + + for (k = 0; k < nr; k++) + dst[k] = bitmap1[k] & bitmap2[k]; +} +EXPORT_SYMBOL(__bitmap_and); + +void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits) +{ + int k; + int nr = BITS_TO_LONGS(bits); + + for (k = 0; k < nr; k++) + dst[k] = bitmap1[k] | bitmap2[k]; +} +EXPORT_SYMBOL(__bitmap_or); + +void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits) +{ + int k; + int nr = BITS_TO_LONGS(bits); + + for (k = 0; k < nr; k++) + dst[k] = bitmap1[k] ^ bitmap2[k]; +} +EXPORT_SYMBOL(__bitmap_xor); + +void __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits) +{ + int k; + int nr = BITS_TO_LONGS(bits); + + for (k = 0; k < nr; k++) + dst[k] = bitmap1[k] & ~bitmap2[k]; +} +EXPORT_SYMBOL(__bitmap_andnot); + +int __bitmap_intersects(const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits) +{ + int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (bitmap1[k] & bitmap2[k]) + return 1; + + if (bits % BITS_PER_LONG) + if ((bitmap1[k] & bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) + return 1; + return 0; +} +EXPORT_SYMBOL(__bitmap_intersects); + +int __bitmap_subset(const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits) +{ + int k, lim = bits/BITS_PER_LONG; + for (k = 0; k < lim; ++k) + if (bitmap1[k] & ~bitmap2[k]) + return 0; + + if (bits % BITS_PER_LONG) + if ((bitmap1[k] & ~bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) + return 0; + return 1; +} +EXPORT_SYMBOL(__bitmap_subset); + +#if BITS_PER_LONG == 32 +int __bitmap_weight(const unsigned long *bitmap, int bits) +{ + int k, w = 0, lim = bits/BITS_PER_LONG; + + for (k = 0; k < lim; k++) + w += hweight32(bitmap[k]); + + if (bits % BITS_PER_LONG) + w += hweight32(bitmap[k] & BITMAP_LAST_WORD_MASK(bits)); + + return w; +} +#else +int __bitmap_weight(const unsigned long *bitmap, int bits) +{ + int k, w = 0, lim = bits/BITS_PER_LONG; + + for (k = 0; k < lim; k++) + w += hweight64(bitmap[k]); + + if (bits % BITS_PER_LONG) + w += hweight64(bitmap[k] & BITMAP_LAST_WORD_MASK(bits)); + + return w; +} +#endif +EXPORT_SYMBOL(__bitmap_weight); + +/** + * bitmap_find_free_region - find a contiguous aligned mem region + * @bitmap: an array of unsigned longs corresponding to the bitmap + * @bits: number of bits in the bitmap + * @order: region size to find (size is actually 1< BITS_PER_LONG) + return -EINVAL; + + /* make a mask of the order */ + mask = (1ul << (pages - 1)); + mask += mask - 1; + + /* run up the bitmap pages bits at a time */ + for (i = 0; i < bits; i += pages) { + int index = i/BITS_PER_LONG; + int offset = i - (index * BITS_PER_LONG); + if((bitmap[index] & (mask << offset)) == 0) { + /* set region in bimap */ + bitmap[index] |= (mask << offset); + return i; + } + } + return -ENOMEM; +} +EXPORT_SYMBOL(bitmap_find_free_region); + +/** + * bitmap_release_region - release allocated bitmap region + * @bitmap: a pointer to the bitmap + * @pos: the beginning of the region + * @order: the order of the bits to release (number is 1< BITS_PER_LONG. The + * algorithm would be a simple look for multiple zeros in the + * array, but there's no driver today that needs this. If you + * trip this BUG(), you get to code it... */ + BUG_ON(pages > BITS_PER_LONG); + mask += mask - 1; + if (bitmap[index] & (mask << offset)) + return -EBUSY; + bitmap[index] |= (mask << offset); + return 0; +} +EXPORT_SYMBOL(bitmap_allocate_region); diff --git a/xen/common/xmalloc.c b/xen/common/xmalloc.c index bb90cc392d..de4831e18c 100644 --- a/xen/common/xmalloc.c +++ b/xen/common/xmalloc.c @@ -42,7 +42,7 @@ struct xmalloc_hdr /* Total including this hdr. */ size_t size; struct list_head freelist; -} __attribute__((__aligned__(SMP_CACHE_BYTES))); +} __cacheline_aligned; static void maybe_split(struct xmalloc_hdr *hdr, size_t size, size_t block) { diff --git a/xen/drivers/acpi/tables.c b/xen/drivers/acpi/tables.c index 64a05061a6..1c718efc88 100644 --- a/xen/drivers/acpi/tables.c +++ b/xen/drivers/acpi/tables.c @@ -58,6 +58,7 @@ static char *acpi_table_signatures[ACPI_TABLE_COUNT] = { [ACPI_SSDT] = "SSDT", [ACPI_SPMI] = "SPMI", [ACPI_HPET] = "HPET", + [ACPI_MCFG] = "MCFG", }; static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" }; @@ -100,7 +101,7 @@ acpi_table_print ( else name = header->signature; - printk(KERN_INFO PREFIX "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n", + printk(KERN_DEBUG PREFIX "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n", name, header->revision, header->oem_id, header->oem_table_id, header->oem_revision, header->asl_compiler_id, header->asl_compiler_revision, @@ -130,7 +131,7 @@ acpi_table_print_madt_entry ( { struct acpi_table_ioapic *p = (struct acpi_table_ioapic*) header; - printk(KERN_INFO PREFIX "IOAPIC (id[0x%02x] address[0x%08x] global_irq_base[0x%x])\n", + printk(KERN_INFO PREFIX "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n", p->id, p->address, p->global_irq_base); } break; @@ -184,8 +185,8 @@ acpi_table_print_madt_entry ( { struct acpi_table_iosapic *p = (struct acpi_table_iosapic*) header; - printk(KERN_INFO PREFIX "IOSAPIC (id[0x%x] global_irq_base[0x%x] address[%p])\n", - p->id, p->global_irq_base, (void *) (unsigned long) p->address); + printk(KERN_INFO PREFIX "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n", + p->id, (void *) (unsigned long) p->address, p->global_irq_base); } break; @@ -285,7 +286,7 @@ acpi_get_table_header_early ( *header = (void *) __acpi_map_table(fadt->V1_dsdt, sizeof(struct acpi_table_header)); } else - *header = 0; + *header = NULL; if (!*header) { printk(KERN_WARNING PREFIX "Unable to map DSDT\n"); @@ -302,13 +303,14 @@ acpi_table_parse_madt_family ( enum acpi_table_id id, unsigned long madt_size, int entry_id, - acpi_madt_entry_handler handler) + acpi_madt_entry_handler handler, + unsigned int max_entries) { void *madt = NULL; - acpi_table_entry_header *entry = NULL; - unsigned long count = 0; - unsigned long madt_end = 0; - unsigned int i = 0; + acpi_table_entry_header *entry; + unsigned int count = 0; + unsigned long madt_end; + unsigned int i; if (!handler) return -EINVAL; @@ -341,14 +343,20 @@ acpi_table_parse_madt_family ( entry = (acpi_table_entry_header *) ((unsigned long) madt + madt_size); - while (((unsigned long) entry) < madt_end) { - if (entry->type == entry_id) { - count++; - handler(entry); - } + while (((unsigned long) entry) + sizeof(acpi_table_entry_header) < madt_end) { + if (entry->type == entry_id && + (!max_entries || count++ < max_entries)) + if (handler(entry, madt_end)) + return -EINVAL; + entry = (acpi_table_entry_header *) ((unsigned long) entry + entry->length); } + if (max_entries && count > max_entries) { + printk(KERN_WARNING PREFIX "[%s:0x%02x] ignored %i entries of " + "%i found\n", acpi_table_signatures[id], entry_id, + count - max_entries, count); + } return count; } @@ -357,10 +365,11 @@ acpi_table_parse_madt_family ( int __init acpi_table_parse_madt ( enum acpi_madt_entry_id id, - acpi_madt_entry_handler handler) + acpi_madt_entry_handler handler, + unsigned int max_entries) { return acpi_table_parse_madt_family(ACPI_APIC, sizeof(struct acpi_table_madt), - id, handler); + id, handler, max_entries); } @@ -378,8 +387,13 @@ acpi_table_parse ( for (i = 0; i < sdt_count; i++) { if (sdt_entry[i].id != id) continue; - handler(sdt_entry[i].pa, sdt_entry[i].size); count++; + if (count == 1) + handler(sdt_entry[i].pa, sdt_entry[i].size); + + else + printk(KERN_WARNING PREFIX "%d duplicate %s table ignored.\n", + count, acpi_table_signatures[id]); } return count; @@ -543,6 +557,14 @@ acpi_table_get_sdt ( return 0; } +/* + * acpi_table_init() + * + * find RSDP, find and checksum SDT/XSDT. + * checksum all tables, print SDT/XSDT + * + * result: sdt_entry[] is initialized + */ int __init acpi_table_init (void) @@ -565,7 +587,7 @@ acpi_table_init (void) return -ENODEV; } - printk(KERN_INFO PREFIX "RSDP (v%3.3d %6.6s ) @ 0x%p\n", + printk(KERN_DEBUG PREFIX "RSDP (v%3.3d %6.6s ) @ 0x%p\n", rsdp->revision, rsdp->oem_id, (void *) rsdp_phys); if (rsdp->revision < 2) @@ -585,4 +607,3 @@ acpi_table_init (void) return 0; } - diff --git a/xen/include/acpi/acconfig.h b/xen/include/acpi/acconfig.h index 8879c2c830..6701c11b40 100644 --- a/xen/include/acpi/acconfig.h +++ b/xen/include/acpi/acconfig.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,11 +64,21 @@ /* Version string */ -#define ACPI_CA_VERSION 0x20040116 +#define ACPI_CA_VERSION 0x20050211 + +/* + * OS name, used for the _OS object. The _OS object is essentially obsolete, + * but there is a large base of ASL/AML code in existing machines that check + * for the string below. The use of this string usually guarantees that + * the ASL will execute down the most tested code path. Also, there is some + * code that will not execute the _OSI method unless _OS matches the string + * below. Therefore, change this string at your own risk. + */ +#define ACPI_OS_NAME "Microsoft Windows NT" /* Maximum objects in the various object caches */ -#define ACPI_MAX_STATE_CACHE_DEPTH 64 /* State objects for stacks */ +#define ACPI_MAX_STATE_CACHE_DEPTH 64 /* State objects */ #define ACPI_MAX_PARSE_CACHE_DEPTH 96 /* Parse tree objects */ #define ACPI_MAX_EXTPARSE_CACHE_DEPTH 64 /* Parse tree objects */ #define ACPI_MAX_OBJECT_CACHE_DEPTH 64 /* Interpreter operand objects */ @@ -89,7 +99,7 @@ /* Version of ACPI supported */ -#define ACPI_CA_SUPPORT_LEVEL 2 +#define ACPI_CA_SUPPORT_LEVEL 3 /* String size constants */ @@ -152,10 +162,11 @@ /* Constants used in searching for the RSDP in low memory */ -#define ACPI_LO_RSDP_WINDOW_BASE 0 /* Physical Address */ -#define ACPI_HI_RSDP_WINDOW_BASE 0xE0000 /* Physical Address */ -#define ACPI_LO_RSDP_WINDOW_SIZE 0x400 -#define ACPI_HI_RSDP_WINDOW_SIZE 0x20000 +#define ACPI_EBDA_PTR_LOCATION 0x0000040E /* Physical Address */ +#define ACPI_EBDA_PTR_LENGTH 2 +#define ACPI_EBDA_WINDOW_SIZE 1024 +#define ACPI_HI_RSDP_WINDOW_BASE 0x000E0000 /* Physical Address */ +#define ACPI_HI_RSDP_WINDOW_SIZE 0x00020000 #define ACPI_RSDP_SCAN_STEP 16 /* Operation regions */ @@ -185,6 +196,10 @@ #define ACPI_SMBUS_BUFFER_SIZE 34 +/* Number of strings associated with the _OSI reserved method */ + +#define ACPI_NUM_OSI_STRINGS 9 + /****************************************************************************** * diff --git a/xen/include/acpi/acexcep.h b/xen/include/acpi/acexcep.h index 9441f5c1a7..53f8b50fac 100644 --- a/xen/include/acpi/acexcep.h +++ b/xen/include/acpi/acexcep.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -95,8 +95,9 @@ #define AE_LOGICAL_ADDRESS (acpi_status) (0x001B | AE_CODE_ENVIRONMENTAL) #define AE_ABORT_METHOD (acpi_status) (0x001C | AE_CODE_ENVIRONMENTAL) #define AE_SAME_HANDLER (acpi_status) (0x001D | AE_CODE_ENVIRONMENTAL) +#define AE_WAKE_ONLY_GPE (acpi_status) (0x001E | AE_CODE_ENVIRONMENTAL) -#define AE_CODE_ENV_MAX 0x001D +#define AE_CODE_ENV_MAX 0x001E /* * Programmer exceptions @@ -165,7 +166,7 @@ #define AE_AML_CIRCULAR_REFERENCE (acpi_status) (0x0020 | AE_CODE_AML) #define AE_AML_BAD_RESOURCE_LENGTH (acpi_status) (0x0021 | AE_CODE_AML) -#define AE_CODE_AML_MAX 0x0020 +#define AE_CODE_AML_MAX 0x0021 /* * Internal exceptions used for control @@ -222,7 +223,8 @@ char const *acpi_gbl_exception_names_env[] = "AE_NO_GLOBAL_LOCK", "AE_LOGICAL_ADDRESS", "AE_ABORT_METHOD", - "AE_SAME_HANDLER" + "AE_SAME_HANDLER", + "AE_WAKE_ONLY_GPE" }; char const *acpi_gbl_exception_names_pgm[] = diff --git a/xen/include/acpi/acglobal.h b/xen/include/acpi/acglobal.h index 9cf587e950..c7f387a972 100644 --- a/xen/include/acpi/acglobal.h +++ b/xen/include/acpi/acglobal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,17 +46,26 @@ /* - * Ensure that the globals are actually defined only once. + * Ensure that the globals are actually defined and initialized only once. * - * The use of these defines allows a single list of globals (here) in order + * The use of these macros allows a single list of globals (here) in order * to simplify maintenance of the code. */ #ifdef DEFINE_ACPI_GLOBALS #define ACPI_EXTERN +#define ACPI_INIT_GLOBAL(a,b) a=b #else #define ACPI_EXTERN extern +#define ACPI_INIT_GLOBAL(a,b) a #endif +/* + * Keep local copies of these FADT-based registers. NOTE: These globals + * are first in this file for alignment reasons on 64-bit systems. + */ +ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; +ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; + /***************************************************************************** * @@ -74,6 +83,46 @@ extern u32 acpi_dbg_layer; extern u32 acpi_gbl_nesting_level; +/***************************************************************************** + * + * Runtime configuration (static defaults that can be overriden at runtime) + * + ****************************************************************************/ + +/* + * Enable "slack" in the AML interpreter? Default is FALSE, and the + * interpreter strictly follows the ACPI specification. Setting to TRUE + * allows the interpreter to forgive certain bad AML constructs. Currently: + * 1) Allow "implicit return" of last value in a control method + * 2) Allow access beyond end of operation region + * 3) Allow access to uninitialized locals/args (auto-init to integer 0) + * 4) Allow ANY object type to be a source operand for the Store() operator + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL (acpi_gbl_enable_interpreter_slack, FALSE); + +/* + * Automatically serialize ALL control methods? Default is FALSE, meaning + * to use the Serialized/not_serialized method flags on a per method basis. + * Only change this if the ASL code is poorly written and cannot handle + * reentrancy even though methods are marked "not_serialized". + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL (acpi_gbl_all_methods_serialized, FALSE); + +/* + * Create the predefined _OSI method in the namespace? Default is TRUE + * because ACPI CA is fully compatible with other ACPI implementations. + * Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior. + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL (acpi_gbl_create_osi_method, TRUE); + +/* + * Disable wakeup GPEs during runtime? Default is TRUE because WAKE and + * RUNTIME GPEs should never be shared, and WAKE GPEs should typically only + * be enabled just before going to sleep. + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL (acpi_gbl_leave_wake_gpes_disabled, TRUE); + + /***************************************************************************** * * ACPI Table globals @@ -87,7 +136,6 @@ extern u32 acpi_gbl_nesting_level; * * These tables are single-table only; meaning that there can be at most one * of each in the system. Each global points to the actual table. - * */ ACPI_EXTERN u32 acpi_gbl_table_flags; ACPI_EXTERN u32 acpi_gbl_rsdt_table_count; @@ -97,6 +145,11 @@ ACPI_EXTERN FADT_DESCRIPTOR *acpi_gbl_FADT; ACPI_EXTERN struct acpi_table_header *acpi_gbl_DSDT; ACPI_EXTERN FACS_DESCRIPTOR *acpi_gbl_FACS; ACPI_EXTERN struct acpi_common_facs acpi_gbl_common_fACS; +/* + * Since there may be multiple SSDTs and PSDTS, a single pointer is not + * sufficient; Therefore, there isn't one! + */ + /* * Handle both ACPI 1.0 and ACPI 2.0 Integer widths @@ -107,17 +160,6 @@ ACPI_EXTERN u8 acpi_gbl_integer_bit_width; ACPI_EXTERN u8 acpi_gbl_integer_byte_width; ACPI_EXTERN u8 acpi_gbl_integer_nybble_width; -/* Keep local copies of these FADT-based registers */ - -ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; -ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; - -/* - * Since there may be multiple SSDTs and PSDTS, a single pointer is not - * sufficient; Therefore, there isn't one! - */ - - /* * ACPI Table info arrays */ @@ -142,6 +184,7 @@ ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[NUM_MUTEX]; ACPI_EXTERN struct acpi_memory_list acpi_gbl_memory_lists[ACPI_NUM_MEM_LISTS]; ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_device_notify; ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_system_notify; +ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler; ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler; ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk; ACPI_EXTERN acpi_handle acpi_gbl_global_lock_semaphore; @@ -161,13 +204,16 @@ ACPI_EXTERN u8 acpi_gbl_step_to_next_call; ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present; ACPI_EXTERN u8 acpi_gbl_global_lock_present; ACPI_EXTERN u8 acpi_gbl_events_initialized; +ACPI_EXTERN u8 acpi_gbl_system_awake_and_running; extern u8 acpi_gbl_shutdown; extern u32 acpi_gbl_startup_flags; extern const u8 acpi_gbl_decode_to8bit[8]; -extern const char *acpi_gbl_db_sleep_states[ACPI_S_STATE_COUNT]; +extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT]; +extern const char *acpi_gbl_highest_dstate_names[4]; extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES]; extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS]; +extern const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS]; /***************************************************************************** @@ -178,7 +224,7 @@ extern const char *acpi_gbl_region_types[ACPI_NUM_P #define NUM_NS_TYPES ACPI_TYPE_INVALID+1 -#if defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) +#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) #define NUM_PREDEFINED_NAMES 10 #else #define NUM_PREDEFINED_NAMES 9 @@ -186,6 +232,7 @@ extern const char *acpi_gbl_region_types[ACPI_NUM_P ACPI_EXTERN struct acpi_namespace_node acpi_gbl_root_node_struct; ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_root_node; +ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_fadt_gpe_device; extern const u8 acpi_gbl_ns_properties[NUM_NS_TYPES]; extern const struct acpi_predefined_names acpi_gbl_pre_defined_names [NUM_PREDEFINED_NAMES]; diff --git a/xen/include/acpi/achware.h b/xen/include/acpi/achware.h index cfcff91f6d..28ad1398c1 100644 --- a/xen/include/acpi/achware.h +++ b/xen/include/acpi/achware.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -114,15 +114,7 @@ acpi_hw_clear_acpi_status ( /* GPE support */ acpi_status -acpi_hw_enable_gpe ( - struct acpi_gpe_event_info *gpe_event_info); - -void -acpi_hw_enable_gpe_for_wakeup ( - struct acpi_gpe_event_info *gpe_event_info); - -acpi_status -acpi_hw_disable_gpe ( +acpi_hw_write_gpe_enable_reg ( struct acpi_gpe_event_info *gpe_event_info); acpi_status @@ -130,10 +122,6 @@ acpi_hw_disable_gpe_block ( struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block); -void -acpi_hw_disable_gpe_for_wakeup ( - struct acpi_gpe_event_info *gpe_event_info); - acpi_status acpi_hw_clear_gpe ( struct acpi_gpe_event_info *gpe_event_info); @@ -143,22 +131,39 @@ acpi_hw_clear_gpe_block ( struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_hw_get_gpe_status ( struct acpi_gpe_event_info *gpe_event_info, acpi_event_status *event_status); +#endif acpi_status -acpi_hw_disable_non_wakeup_gpes ( - void); +acpi_hw_disable_all_gpes ( + u32 flags); acpi_status -acpi_hw_enable_non_wakeup_gpes ( - void); +acpi_hw_enable_all_runtime_gpes ( + u32 flags); + +acpi_status +acpi_hw_enable_all_wakeup_gpes ( + u32 flags); + +acpi_status +acpi_hw_enable_runtime_gpe_block ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block); + +acpi_status +acpi_hw_enable_wakeup_gpe_block ( + struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block); /* ACPI Timer prototypes */ +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_timer_resolution ( u32 *resolution); @@ -172,6 +177,6 @@ acpi_get_timer_duration ( u32 start_ticks, u32 end_ticks, u32 *time_elapsed); - +#endif /* ACPI_FUTURE_USAGE */ #endif /* __ACHWARE_H__ */ diff --git a/xen/include/acpi/aclocal.h b/xen/include/acpi/aclocal.h index 129422eacc..f2b96f6be4 100644 --- a/xen/include/acpi/aclocal.h +++ b/xen/include/acpi/aclocal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -53,7 +53,7 @@ typedef u32 acpi_mutex_handle; /* Total number of aml opcodes defined */ -#define AML_NUM_OPCODES 0x7E +#define AML_NUM_OPCODES 0x7F /***************************************************************************** @@ -189,8 +189,6 @@ struct acpi_namespace_node u8 type; /* Type associated with this name */ u16 owner_id; union acpi_name_union name; /* ACPI Name, always 4 chars per ACPI spec */ - - union acpi_operand_object *object; /* Pointer to attached ACPI object (optional) */ struct acpi_namespace_node *child; /* First child */ struct acpi_namespace_node *peer; /* Next peer*/ @@ -211,10 +209,8 @@ struct acpi_namespace_node #define ANOBJ_METHOD_LOCAL 0x10 #define ANOBJ_METHOD_NO_RETVAL 0x20 #define ANOBJ_METHOD_SOME_NO_RETVAL 0x40 - #define ANOBJ_IS_BIT_OFFSET 0x80 - /* * ACPI Table Descriptor. One per ACPI table */ @@ -309,16 +305,31 @@ struct acpi_create_field_info * ****************************************************************************/ -/* Information about a GPE, one per each GPE in an array */ +/* Dispatch info for each GPE -- either a method or handler, cannot be both */ -struct acpi_gpe_event_info +struct acpi_handler_info +{ + acpi_event_handler address; /* Address of handler, if any */ + void *context; /* Context to be passed to handler */ + struct acpi_namespace_node *method_node; /* Method node for this GPE level (saved) */ +}; + +union acpi_gpe_dispatch_info { struct acpi_namespace_node *method_node; /* Method node for this GPE level */ - acpi_gpe_handler handler; /* Address of handler, if any */ - void *context; /* Context to be passed to handler */ + struct acpi_handler_info *handler; +}; + +/* + * Information about a GPE, one per each GPE in an array. + * NOTE: Important to keep this struct as small as possible. + */ +struct acpi_gpe_event_info +{ + union acpi_gpe_dispatch_info dispatch; /* Either Method or Handler */ struct acpi_gpe_register_info *register_info; /* Backpointer to register info */ - u8 flags; /* Level or Edge */ - u8 bit_mask; /* This GPE within the register */ + u8 flags; /* Misc info about this GPE */ + u8 register_bit; /* This GPE bit within the register */ }; /* Information about a GPE register pair, one per each status/enable pair in an array */ @@ -327,9 +338,8 @@ struct acpi_gpe_register_info { struct acpi_generic_address status_address; /* Address of status reg */ struct acpi_generic_address enable_address; /* Address of enable reg */ - u8 status; /* Current value of status reg */ - u8 enable; /* Current value of enable reg */ - u8 wake_enable; /* Mask of bits to keep enabled when sleeping */ + u8 enable_for_wake; /* GPEs to keep enabled when sleeping */ + u8 enable_for_run; /* GPEs to keep enabled when running */ u8 base_gpe_number; /* Base GPE number for this register */ }; @@ -339,6 +349,7 @@ struct acpi_gpe_register_info */ struct acpi_gpe_block_info { + struct acpi_namespace_node *node; struct acpi_gpe_block_info *previous; struct acpi_gpe_block_info *next; struct acpi_gpe_xrupt_info *xrupt_block; /* Backpointer to interrupt block */ @@ -360,6 +371,13 @@ struct acpi_gpe_xrupt_info }; +struct acpi_gpe_walk_info +{ + struct acpi_namespace_node *gpe_device; + struct acpi_gpe_block_info *gpe_block; +}; + + typedef acpi_status (*ACPI_GPE_CALLBACK) ( struct acpi_gpe_xrupt_info *gpe_xrupt_info, struct acpi_gpe_block_info *gpe_block); @@ -495,7 +513,7 @@ struct acpi_thread_state struct acpi_walk_state *walk_state_list; /* Head of list of walk_states for this thread */ union acpi_operand_object *acquired_mutex_list; /* List of all currently acquired mutexes */ u32 thread_id; /* Running thread ID */ - u16 current_sync_level; /* Mutex Sync (nested acquire) level */ + u8 current_sync_level; /* Mutex Sync (nested acquire) level */ }; @@ -544,7 +562,7 @@ union acpi_generic_state struct acpi_scope_state scope; struct acpi_pscope_state parse_scope; struct acpi_pkg_state pkg; - struct acpi_thread_state acpi_thread; + struct acpi_thread_state thread; struct acpi_result_values results; struct acpi_notify_info notify; }; @@ -844,7 +862,6 @@ struct acpi_bit_register_info /* * Large resource descriptor types */ - #define ACPI_RDESC_TYPE_MEMORY_24 0x81 #define ACPI_RDESC_TYPE_GENERAL_REGISTER 0x82 #define ACPI_RDESC_TYPE_LARGE_VENDOR 0x84 @@ -854,6 +871,7 @@ struct acpi_bit_register_info #define ACPI_RDESC_TYPE_WORD_ADDRESS_SPACE 0x88 #define ACPI_RDESC_TYPE_EXTENDED_XRUPT 0x89 #define ACPI_RDESC_TYPE_QWORD_ADDRESS_SPACE 0x8A +#define ACPI_RDESC_TYPE_EXTENDED_ADDRESS_SPACE 0x8B /***************************************************************************** diff --git a/xen/include/acpi/acmacros.h b/xen/include/acpi/acmacros.h index e1abf964bf..fcaced16b1 100644 --- a/xen/include/acpi/acmacros.h +++ b/xen/include/acpi/acmacros.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -53,6 +53,10 @@ #define ACPI_LOBYTE(l) ((u8)(u16)(l)) #define ACPI_HIBYTE(l) ((u8)((((u16)(l)) >> 8) & 0xFF)) +#define ACPI_SET_BIT(target,bit) ((target) |= (bit)) +#define ACPI_CLEAR_BIT(target,bit) ((target) &= ~(bit)) +#define ACPI_MIN(a,b) (((a)<(b))?(a):(b)) + #if ACPI_MACHINE_WIDTH == 16 @@ -97,7 +101,7 @@ * printf() format helpers */ -/* Split 64-bit integer into two 32-bit values. use with %8,8_x%8.8X */ +/* Split 64-bit integer into two 32-bit values. Use with %8.8X%8.8X */ #define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i),ACPI_LODWORD(i) @@ -361,24 +365,6 @@ #define ACPI_IS_OCTAL_DIGIT(d) (((char)(d) >= '0') && ((char)(d) <= '7')) -/* Macros for GAS addressing */ - -#if ACPI_MACHINE_WIDTH != 16 - -#define ACPI_PCI_DEVICE(a) (u16) ((ACPI_HIDWORD ((a))) & 0x0000FFFF) -#define ACPI_PCI_FUNCTION(a) (u16) ((ACPI_LODWORD ((a))) >> 16) -#define ACPI_PCI_REGISTER(a) (u16) ((ACPI_LODWORD ((a))) & 0x0000FFFF) - -#else - -/* No support for GAS and PCI IDs in 16-bit mode */ - -#define ACPI_PCI_FUNCTION(a) (u16) ((a) & 0xFFFF0000) -#define ACPI_PCI_DEVICE(a) (u16) ((a) & 0x0000FFFF) -#define ACPI_PCI_REGISTER(a) (u16) ((a) & 0x0000FFFF) - -#endif - /* Bitfields within ACPI registers */ @@ -502,19 +488,19 @@ * The first parameter should be the procedure name as a quoted string. This is declared * as a local string ("_proc_name) so that it can be also used by the function exit macros below. */ -#define ACPI_FUNCTION_NAME(a) struct acpi_debug_print_info _dbg; \ - _dbg.component_id = _COMPONENT; \ - _dbg.proc_name = a; \ - _dbg.module_name = _THIS_MODULE; +#define ACPI_FUNCTION_NAME(a) struct acpi_debug_print_info _debug_info; \ + _debug_info.component_id = _COMPONENT; \ + _debug_info.proc_name = a; \ + _debug_info.module_name = _THIS_MODULE; #define ACPI_FUNCTION_TRACE(a) ACPI_FUNCTION_NAME(a) \ - acpi_ut_trace(__LINE__,&_dbg) + acpi_ut_trace(__LINE__,&_debug_info) #define ACPI_FUNCTION_TRACE_PTR(a,b) ACPI_FUNCTION_NAME(a) \ - acpi_ut_trace_ptr(__LINE__,&_dbg,(void *)b) + acpi_ut_trace_ptr(__LINE__,&_debug_info,(void *)b) #define ACPI_FUNCTION_TRACE_U32(a,b) ACPI_FUNCTION_NAME(a) \ - acpi_ut_trace_u32(__LINE__,&_dbg,(u32)b) + acpi_ut_trace_u32(__LINE__,&_debug_info,(u32)b) #define ACPI_FUNCTION_TRACE_STR(a,b) ACPI_FUNCTION_NAME(a) \ - acpi_ut_trace_str(__LINE__,&_dbg,(char *)b) + acpi_ut_trace_str(__LINE__,&_debug_info,(char *)b) #define ACPI_FUNCTION_ENTRY() acpi_ut_track_stack_ptr() @@ -531,10 +517,10 @@ #define ACPI_DO_WHILE0(a) a #endif -#define return_VOID ACPI_DO_WHILE0 ({acpi_ut_exit(__LINE__,&_dbg);return;}) -#define return_ACPI_STATUS(s) ACPI_DO_WHILE0 ({acpi_ut_status_exit(__LINE__,&_dbg,(s));return((s));}) -#define return_VALUE(s) ACPI_DO_WHILE0 ({acpi_ut_value_exit(__LINE__,&_dbg,(acpi_integer)(s));return((s));}) -#define return_PTR(s) ACPI_DO_WHILE0 ({acpi_ut_ptr_exit(__LINE__,&_dbg,(u8 *)(s));return((s));}) +#define return_VOID ACPI_DO_WHILE0 ({acpi_ut_exit(__LINE__,&_debug_info);return;}) +#define return_ACPI_STATUS(s) ACPI_DO_WHILE0 ({acpi_ut_status_exit(__LINE__,&_debug_info,(s));return((s));}) +#define return_VALUE(s) ACPI_DO_WHILE0 ({acpi_ut_value_exit(__LINE__,&_debug_info,(acpi_integer)(s));return((s));}) +#define return_PTR(s) ACPI_DO_WHILE0 ({acpi_ut_ptr_exit(__LINE__,&_debug_info,(u8 *)(s));return((s));}) /* Conditional execution */ @@ -548,12 +534,16 @@ /* Stack and buffer dumping */ -#define ACPI_DUMP_STACK_ENTRY(a) acpi_ex_dump_operand(a) +#define ACPI_DUMP_STACK_ENTRY(a) acpi_ex_dump_operand((a),0) #define ACPI_DUMP_OPERANDS(a,b,c,d,e) acpi_ex_dump_operands(a,b,c,d,e,_THIS_MODULE,__LINE__) #define ACPI_DUMP_ENTRY(a,b) acpi_ns_dump_entry (a,b) + +#ifdef ACPI_FUTURE_USAGE #define ACPI_DUMP_TABLES(a,b) acpi_ns_dump_tables(a,b) +#endif + #define ACPI_DUMP_PATHNAME(a,b,c,d) acpi_ns_dump_pathname(a,b,c,d) #define ACPI_DUMP_RESOURCE_LIST(a) acpi_rs_dump_resource_list(a) #define ACPI_DUMP_BUFFER(a,b) acpi_ut_dump_buffer((u8 *)a,b,DB_BYTE_DISPLAY,_COMPONENT) @@ -606,7 +596,11 @@ #define ACPI_DUMP_STACK_ENTRY(a) #define ACPI_DUMP_OPERANDS(a,b,c,d,e) #define ACPI_DUMP_ENTRY(a,b) + +#ifdef ACPI_FUTURE_USAGE #define ACPI_DUMP_TABLES(a,b) +#endif + #define ACPI_DUMP_PATHNAME(a,b,c,d) #define ACPI_DUMP_RESOURCE_LIST(a) #define ACPI_DUMP_BUFFER(a,b) @@ -681,7 +675,4 @@ #endif /* ACPI_DBG_TRACK_ALLOCATIONS */ - -#define ACPI_GET_STACK_POINTER _asm {mov eax, ebx} - #endif /* ACMACROS_H */ diff --git a/xen/include/acpi/acobject.h b/xen/include/acpi/acobject.h index 6caaf6ade2..036023a940 100644 --- a/xen/include/acpi/acobject.h +++ b/xen/include/acpi/acobject.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -94,9 +94,7 @@ u32 bit_length; /* Length of field in bits */\ u32 base_byte_offset; /* Byte offset within containing object */\ u8 start_field_bit_offset;/* Bit offset within first field datum (0-63) */\ - u8 datum_valid_bits; /* Valid bit in first "Field datum" */\ - u8 end_field_valid_bits; /* Valid bits in the last "field datum" */\ - u8 end_buffer_valid_bits; /* Valid bits in the last "buffer datum" */\ + u8 access_bit_width; /* Read/Write size in bits (8-64) */\ u32 value; /* Value to store into the Bank or Index register */\ struct acpi_namespace_node *node; /* Link back to parent node */ @@ -135,7 +133,10 @@ struct acpi_object_integer acpi_integer value; }; - +/* + * Note: The String and Buffer object must be identical through the Pointer + * element. There is code that depends on this. + */ struct acpi_object_string /* Null terminated, ASCII characters only */ { ACPI_OBJECT_COMMON_HEADER @@ -180,7 +181,11 @@ struct acpi_object_event }; -#define INFINITE_CONCURRENCY 0xFF +#define ACPI_INFINITE_CONCURRENCY 0xFF + +typedef +acpi_status (*ACPI_INTERNAL_METHOD) ( + struct acpi_walk_state *walk_state); struct acpi_object_method { @@ -190,6 +195,7 @@ struct acpi_object_method u32 aml_length; void *semaphore; u8 *aml_start; + ACPI_INTERNAL_METHOD implementation; u8 concurrency; u8 thread_count; acpi_owner_id owning_id; @@ -199,13 +205,14 @@ struct acpi_object_method struct acpi_object_mutex { ACPI_OBJECT_COMMON_HEADER - u16 sync_level; - u16 acquisition_depth; - struct acpi_thread_state *owner_thread; - void *semaphore; + u8 sync_level; /* 0-15, specified in Mutex() call */ + u16 acquisition_depth; /* Allow multiple Acquires, same thread */ + struct acpi_thread_state *owner_thread; /* Current owner of the mutex */ + void *semaphore; /* Actual OS synchronization object */ union acpi_operand_object *prev; /* Link for list of acquired mutexes */ union acpi_operand_object *next; /* Link for list of acquired mutexes */ - struct acpi_namespace_node *node; /* containing object */ + struct acpi_namespace_node *node; /* Containing namespace node */ + u8 original_sync_level; /* Owner's original sync level (0-15) */ }; @@ -215,7 +222,7 @@ struct acpi_object_region u8 space_id; union acpi_operand_object *handler; /* Handler for region access */ - struct acpi_namespace_node *node; /* containing object */ + struct acpi_namespace_node *node; /* Containing namespace node */ union acpi_operand_object *next; u32 length; acpi_physical_address address; diff --git a/xen/include/acpi/acoutput.h b/xen/include/acpi/acoutput.h index 0ed98ae4d3..2fbe180fee 100644 --- a/xen/include/acpi/acoutput.h +++ b/xen/include/acpi/acoutput.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -136,7 +136,7 @@ /* * Debug level macros that are used in the DEBUG_PRINT macros */ -#define ACPI_DEBUG_LEVEL(dl) (u32) dl,__LINE__,&_dbg +#define ACPI_DEBUG_LEVEL(dl) (u32) dl,__LINE__,&_debug_info /* Exception level -- used in the global "debug_level" */ diff --git a/xen/include/acpi/acpi.h b/xen/include/acpi/acpi.h index bb5bd8f03e..ad53252dd4 100644 --- a/xen/include/acpi/acpi.h +++ b/xen/include/acpi/acpi.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/xen/include/acpi/acpi_bus.h b/xen/include/acpi/acpi_bus.h index 4326bc934b..a4197e9abe 100644 --- a/xen/include/acpi/acpi_bus.h +++ b/xen/include/acpi/acpi_bus.h @@ -26,16 +26,10 @@ #ifndef __ACPI_BUS_H__ #define __ACPI_BUS_H__ -#if 0 -#include -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,4)) -#include -#define CONFIG_LDM -#endif -#endif /* 0 */ - #include +#define PREFIX "ACPI: " + /* TBD: Make dynamic */ #define ACPI_MAX_HANDLES 10 struct acpi_handle_list { @@ -66,10 +60,10 @@ acpi_evaluate_reference ( #ifdef CONFIG_ACPI_BUS -/*#include */ +#include #define ACPI_BUS_FILE_ROOT "acpi" -/*extern struct proc_dir_entry *acpi_root_dir;*/ +extern struct proc_dir_entry *acpi_root_dir; extern FADT_DESCRIPTOR acpi_fadt; enum acpi_bus_removal_type { @@ -108,6 +102,9 @@ typedef int (*acpi_op_suspend) (struct acpi_device *device, int state); typedef int (*acpi_op_resume) (struct acpi_device *device, int state); typedef int (*acpi_op_scan) (struct acpi_device *device); typedef int (*acpi_op_bind) (struct acpi_device *device); +typedef int (*acpi_op_unbind) (struct acpi_device *device); +typedef int (*acpi_op_match) (struct acpi_device *device, + struct acpi_driver *driver); struct acpi_device_ops { acpi_op_add add; @@ -119,13 +116,15 @@ struct acpi_device_ops { acpi_op_resume resume; acpi_op_scan scan; acpi_op_bind bind; + acpi_op_unbind unbind; + acpi_op_match match; }; struct acpi_driver { struct list_head node; char name[80]; char class[80]; - int references; + atomic_t references; char *ids; /* Supported Hardware IDs */ struct acpi_device_ops ops; }; @@ -161,7 +160,8 @@ struct acpi_device_flags { u32 suprise_removal_ok:1; u32 power_manageable:1; u32 performance_manageable:1; - u32 reserved:21; + u32 wake_capable:1; /* Wakeup(_PRW) supported? */ + u32 reserved:20; }; @@ -207,10 +207,8 @@ struct acpi_device_power_flags { u32 explicit_get:1; /* _PSC present? */ u32 power_resources:1; /* Power resources */ u32 inrush_current:1; /* Serialize Dx->D0 */ - u32 wake_capable:1; /* Wakeup supported? */ - u32 wake_enabled:1; /* Enabled for wakeup */ u32 power_removed:1; /* Optimize Dx->D0 */ - u32 reserved:26; + u32 reserved:28; }; struct acpi_device_power_state { @@ -254,6 +252,25 @@ struct acpi_device_perf { struct acpi_device_perf_state *states; }; +/* Wakeup Management */ +struct acpi_device_wakeup_flags { + u8 valid:1; /* Can successfully enable wakeup? */ + u8 run_wake:1; /* Run-Wake GPE devices */ +}; + +struct acpi_device_wakeup_state { + u8 enabled:1; + u8 active:1; +}; + +struct acpi_device_wakeup { + acpi_handle gpe_device; + acpi_integer gpe_number;; + acpi_integer sleep_state; + struct acpi_handle_list resources; + struct acpi_device_wakeup_state state; + struct acpi_device_wakeup_flags flags; +}; /* Device */ @@ -262,18 +279,19 @@ struct acpi_device { struct acpi_device *parent; struct list_head children; struct list_head node; + struct list_head wakeup_list; + struct list_head g_list; struct acpi_device_status status; struct acpi_device_flags flags; struct acpi_device_pnp pnp; struct acpi_device_power power; + struct acpi_device_wakeup wakeup; struct acpi_device_perf performance; struct acpi_device_dir dir; struct acpi_device_ops ops; struct acpi_driver *driver; void *driver_data; -#ifdef CONFIG_LDM - struct device dev; -#endif + struct kobject kobj; }; #define acpi_driver_data(d) ((d)->driver_data) @@ -292,12 +310,14 @@ struct acpi_bus_event { u32 data; }; +extern struct subsystem acpi_subsys; /* * External Functions */ -int acpi_bus_get_device(acpi_handle, struct acpi_device **device); +int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device); +void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context); int acpi_bus_get_status (struct acpi_device *device); int acpi_bus_get_power (acpi_handle handle, int *state); int acpi_bus_set_power (acpi_handle handle, int state); @@ -305,11 +325,16 @@ int acpi_bus_generate_event (struct acpi_device *device, u8 type, int data); int acpi_bus_receive_event (struct acpi_bus_event *event); int acpi_bus_register_driver (struct acpi_driver *driver); int acpi_bus_unregister_driver (struct acpi_driver *driver); -int acpi_bus_scan (struct acpi_device *device); -int acpi_init (void); -void acpi_exit (void); +int acpi_bus_scan (struct acpi_device *start); +int acpi_bus_trim(struct acpi_device *start, int rmdevice); +int acpi_bus_add (struct acpi_device **child, struct acpi_device *parent, + acpi_handle handle, int type); +int acpi_match_ids (struct acpi_device *device, char *ids); +int acpi_create_dir(struct acpi_device *); +void acpi_remove_dir(struct acpi_device *); + #endif /*CONFIG_ACPI_BUS*/ #endif /*__ACPI_BUS_H__*/ diff --git a/xen/include/acpi/acpi_drivers.h b/xen/include/acpi/acpi_drivers.h index 3b5273a230..c26d5ea5b1 100644 --- a/xen/include/acpi/acpi_drivers.h +++ b/xen/include/acpi/acpi_drivers.h @@ -1,5 +1,5 @@ /* - * acpi_drivers.h ($Revision: 32 $) + * acpi_drivers.h ($Revision: 31 $) * * Copyright (C) 2001, 2002 Andy Grover * Copyright (C) 2001, 2002 Paul Diefenbaugh @@ -27,122 +27,22 @@ #define __ACPI_DRIVERS_H__ #include -#include "acpi_bus.h" +#include #define ACPI_MAX_STRING 80 - -/* -------------------------------------------------------------------------- - ACPI Bus - -------------------------------------------------------------------------- */ - #define ACPI_BUS_COMPONENT 0x00010000 -#define ACPI_BUS_CLASS "system_bus" -#define ACPI_BUS_HID "ACPI_BUS" -#define ACPI_BUS_DRIVER_NAME "ACPI Bus Driver" -#define ACPI_BUS_DEVICE_NAME "System Bus" +#define ACPI_SYSTEM_COMPONENT 0x02000000 +/* _HID definitions */ -/* -------------------------------------------------------------------------- - AC Adapter - -------------------------------------------------------------------------- */ - -#define ACPI_AC_COMPONENT 0x00020000 -#define ACPI_AC_CLASS "ac_adapter" -#define ACPI_AC_HID "ACPI0003" -#define ACPI_AC_DRIVER_NAME "ACPI AC Adapter Driver" -#define ACPI_AC_DEVICE_NAME "AC Adapter" -#define ACPI_AC_FILE_STATE "state" -#define ACPI_AC_NOTIFY_STATUS 0x80 -#define ACPI_AC_STATUS_OFFLINE 0x00 -#define ACPI_AC_STATUS_ONLINE 0x01 -#define ACPI_AC_STATUS_UNKNOWN 0xFF - - -/* -------------------------------------------------------------------------- - Battery - -------------------------------------------------------------------------- */ - -#define ACPI_BATTERY_COMPONENT 0x00040000 -#define ACPI_BATTERY_CLASS "battery" -#define ACPI_BATTERY_HID "PNP0C0A" -#define ACPI_BATTERY_DRIVER_NAME "ACPI Battery Driver" -#define ACPI_BATTERY_DEVICE_NAME "Battery" -#define ACPI_BATTERY_FILE_INFO "info" -#define ACPI_BATTERY_FILE_STATUS "state" -#define ACPI_BATTERY_FILE_ALARM "alarm" -#define ACPI_BATTERY_NOTIFY_STATUS 0x80 -#define ACPI_BATTERY_NOTIFY_INFO 0x81 -#define ACPI_BATTERY_UNITS_WATTS "mW" -#define ACPI_BATTERY_UNITS_AMPS "mA" - - -/* -------------------------------------------------------------------------- - Button - -------------------------------------------------------------------------- */ - -#define ACPI_BUTTON_COMPONENT 0x00080000 -#define ACPI_BUTTON_DRIVER_NAME "ACPI Button Driver" -#define ACPI_BUTTON_CLASS "button" -#define ACPI_BUTTON_FILE_INFO "info" -#define ACPI_BUTTON_FILE_STATE "state" -#define ACPI_BUTTON_TYPE_UNKNOWN 0x00 -#define ACPI_BUTTON_NOTIFY_STATUS 0x80 - -#define ACPI_BUTTON_SUBCLASS_POWER "power" -#define ACPI_BUTTON_HID_POWER "PNP0C0C" +#define ACPI_POWER_HID "ACPI_PWR" +#define ACPI_PROCESSOR_HID "ACPI_CPU" +#define ACPI_SYSTEM_HID "ACPI_SYS" +#define ACPI_THERMAL_HID "ACPI_THM" #define ACPI_BUTTON_HID_POWERF "ACPI_FPB" -#define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button (CM)" -#define ACPI_BUTTON_DEVICE_NAME_POWERF "Power Button (FF)" -#define ACPI_BUTTON_TYPE_POWER 0x01 -#define ACPI_BUTTON_TYPE_POWERF 0x02 - -#define ACPI_BUTTON_SUBCLASS_SLEEP "sleep" -#define ACPI_BUTTON_HID_SLEEP "PNP0C0E" #define ACPI_BUTTON_HID_SLEEPF "ACPI_FSB" -#define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button (CM)" -#define ACPI_BUTTON_DEVICE_NAME_SLEEPF "Sleep Button (FF)" -#define ACPI_BUTTON_TYPE_SLEEP 0x03 -#define ACPI_BUTTON_TYPE_SLEEPF 0x04 - -#define ACPI_BUTTON_SUBCLASS_LID "lid" -#define ACPI_BUTTON_HID_LID "PNP0C0D" -#define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch" -#define ACPI_BUTTON_TYPE_LID 0x05 - - -/* -------------------------------------------------------------------------- - Embedded Controller - -------------------------------------------------------------------------- */ - -#define ACPI_EC_COMPONENT 0x00100000 -#define ACPI_EC_CLASS "embedded_controller" -#define ACPI_EC_HID "PNP0C09" -#define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver" -#define ACPI_EC_DEVICE_NAME "Embedded Controller" -#define ACPI_EC_FILE_INFO "info" - -#ifdef CONFIG_ACPI_EC - -int acpi_ec_ecdt_probe (void); -int acpi_ec_init (void); -void acpi_ec_exit (void); - -#endif - - -/* -------------------------------------------------------------------------- - Fan - -------------------------------------------------------------------------- */ - -#define ACPI_FAN_COMPONENT 0x00200000 -#define ACPI_FAN_CLASS "fan" -#define ACPI_FAN_HID "PNP0C0B" -#define ACPI_FAN_DRIVER_NAME "ACPI Fan Driver" -#define ACPI_FAN_DEVICE_NAME "Fan" -#define ACPI_FAN_FILE_STATE "state" -#define ACPI_FAN_NOTIFY_STATUS 0x80 /* -------------------------------------------------------------------------- @@ -153,41 +53,28 @@ void acpi_ec_exit (void); #define ACPI_PCI_COMPONENT 0x00400000 -/* ACPI PCI Root Bridge (pci_root.c) */ - -#define ACPI_PCI_ROOT_CLASS "pci_bridge" -#define ACPI_PCI_ROOT_HID "PNP0A03" -#define ACPI_PCI_ROOT_DRIVER_NAME "ACPI PCI Root Bridge Driver" -#define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" - -int acpi_pci_root_init (void); -void acpi_pci_root_exit (void); - /* ACPI PCI Interrupt Link (pci_link.c) */ -#define ACPI_PCI_LINK_CLASS "pci_irq_routing" -#define ACPI_PCI_LINK_HID "PNP0C0F" -#define ACPI_PCI_LINK_DRIVER_NAME "ACPI PCI Interrupt Link Driver" -#define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link" -#define ACPI_PCI_LINK_FILE_INFO "info" -#define ACPI_PCI_LINK_FILE_STATUS "state" - -int acpi_pci_link_check (void); +int acpi_irq_penalty_init (void); int acpi_pci_link_get_irq (acpi_handle handle, int index, int* edge_level, int* active_high_low); -int acpi_pci_link_init (void); -void acpi_pci_link_exit (void); /* ACPI PCI Interrupt Routing (pci_irq.c) */ int acpi_pci_irq_add_prt (acpi_handle handle, int segment, int bus); +void acpi_pci_irq_del_prt (int segment, int bus); /* ACPI PCI Device Binding (pci_bind.c) */ struct pci_bus; int acpi_pci_bind (struct acpi_device *device); +int acpi_pci_unbind (struct acpi_device *device); int acpi_pci_bind_root (struct acpi_device *device, struct acpi_pci_id *id, struct pci_bus *bus); +/* Arch-defined function to add a bus to the system */ + +struct pci_bus *pci_acpi_scan_root(struct acpi_device *device, int domain, int bus); + #endif /*CONFIG_ACPI_PCI*/ @@ -195,43 +82,25 @@ int acpi_pci_bind_root (struct acpi_device *device, struct acpi_pci_id *id, stru Power Resource -------------------------------------------------------------------------- */ -#define ACPI_POWER_COMPONENT 0x00800000 -#define ACPI_POWER_CLASS "power_resource" -#define ACPI_POWER_HID "ACPI_PWR" -#define ACPI_POWER_DRIVER_NAME "ACPI Power Resource Driver" -#define ACPI_POWER_DEVICE_NAME "Power Resource" -#define ACPI_POWER_FILE_INFO "info" -#define ACPI_POWER_FILE_STATUS "state" -#define ACPI_POWER_RESOURCE_STATE_OFF 0x00 -#define ACPI_POWER_RESOURCE_STATE_ON 0x01 -#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF - #ifdef CONFIG_ACPI_POWER - +int acpi_enable_wakeup_device_power (struct acpi_device *dev); +int acpi_disable_wakeup_device_power (struct acpi_device *dev); int acpi_power_get_inferred_state (struct acpi_device *device); int acpi_power_transition (struct acpi_device *device, int state); -int acpi_power_init (void); -void acpi_power_exit (void); - #endif +/* -------------------------------------------------------------------------- + Embedded Controller + -------------------------------------------------------------------------- */ +#ifdef CONFIG_ACPI_EC +int acpi_ec_ecdt_probe (void); +#endif + /* -------------------------------------------------------------------------- Processor -------------------------------------------------------------------------- */ -#define ACPI_PROCESSOR_COMPONENT 0x01000000 -#define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_HID "ACPI_CPU" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" -#define ACPI_PROCESSOR_DEVICE_NAME "Processor" -#define ACPI_PROCESSOR_FILE_INFO "info" -#define ACPI_PROCESSOR_FILE_POWER "power" -#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" -#define ACPI_PROCESSOR_FILE_THROTTLING "throttling" -#define ACPI_PROCESSOR_FILE_LIMIT "limit" -#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 -#define ACPI_PROCESSOR_NOTIFY_POWER 0x81 #define ACPI_PROCESSOR_LIMIT_NONE 0x00 #define ACPI_PROCESSOR_LIMIT_INCREMENT 0x01 #define ACPI_PROCESSOR_LIMIT_DECREMENT 0x02 @@ -239,109 +108,4 @@ void acpi_power_exit (void); int acpi_processor_set_thermal_limit(acpi_handle handle, int type); -/* -------------------------------------------------------------------------- - System - -------------------------------------------------------------------------- */ - -#define ACPI_SYSTEM_COMPONENT 0x02000000 -#define ACPI_SYSTEM_CLASS "system" -#define ACPI_SYSTEM_HID "ACPI_SYS" -#define ACPI_SYSTEM_DRIVER_NAME "ACPI System Driver" -#define ACPI_SYSTEM_DEVICE_NAME "System" -#define ACPI_SYSTEM_FILE_INFO "info" -#define ACPI_SYSTEM_FILE_EVENT "event" -#define ACPI_SYSTEM_FILE_ALARM "alarm" -#define ACPI_SYSTEM_FILE_DSDT "dsdt" -#define ACPI_SYSTEM_FILE_FADT "fadt" -#define ACPI_SYSTEM_FILE_SLEEP "sleep" -#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer" -#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level" - -#ifdef CONFIG_ACPI_SYSTEM - -int acpi_system_init (void); -void acpi_system_exit (void); - -#endif - - -/* -------------------------------------------------------------------------- - Thermal Zone - -------------------------------------------------------------------------- */ - -#define ACPI_THERMAL_COMPONENT 0x04000000 -#define ACPI_THERMAL_CLASS "thermal_zone" -#define ACPI_THERMAL_HID "ACPI_THM" -#define ACPI_THERMAL_DRIVER_NAME "ACPI Thermal Zone Driver" -#define ACPI_THERMAL_DEVICE_NAME "Thermal Zone" -#define ACPI_THERMAL_FILE_STATE "state" -#define ACPI_THERMAL_FILE_TEMPERATURE "temperature" -#define ACPI_THERMAL_FILE_TRIP_POINTS "trip_points" -#define ACPI_THERMAL_FILE_COOLING_MODE "cooling_mode" -#define ACPI_THERMAL_FILE_POLLING_FREQ "polling_frequency" -#define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80 -#define ACPI_THERMAL_NOTIFY_THRESHOLDS 0x81 -#define ACPI_THERMAL_NOTIFY_DEVICES 0x82 -#define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0 -#define ACPI_THERMAL_NOTIFY_HOT 0xF1 -#define ACPI_THERMAL_MODE_ACTIVE 0x00 -#define ACPI_THERMAL_MODE_PASSIVE 0x01 -#define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff" - - -/* -------------------------------------------------------------------------- - Debug Support - -------------------------------------------------------------------------- */ - -#define ACPI_DEBUG_RESTORE 0 -#define ACPI_DEBUG_LOW 1 -#define ACPI_DEBUG_MEDIUM 2 -#define ACPI_DEBUG_HIGH 3 -#define ACPI_DEBUG_DRIVERS 4 - -/*extern u32 acpi_dbg_level;*/ -/*extern u32 acpi_dbg_layer;*/ - -static inline void -acpi_set_debug ( - u32 flag) -{ - static u32 layer_save; - static u32 level_save; - - switch (flag) { - case ACPI_DEBUG_RESTORE: - acpi_dbg_layer = layer_save; - acpi_dbg_level = level_save; - break; - case ACPI_DEBUG_LOW: - case ACPI_DEBUG_MEDIUM: - case ACPI_DEBUG_HIGH: - case ACPI_DEBUG_DRIVERS: - layer_save = acpi_dbg_layer; - level_save = acpi_dbg_level; - break; - } - - switch (flag) { - case ACPI_DEBUG_LOW: - acpi_dbg_layer = ACPI_COMPONENT_DEFAULT | ACPI_ALL_DRIVERS; - acpi_dbg_level = ACPI_DEBUG_DEFAULT; - break; - case ACPI_DEBUG_MEDIUM: - acpi_dbg_layer = ACPI_COMPONENT_DEFAULT | ACPI_ALL_DRIVERS; - acpi_dbg_level = ACPI_LV_FUNCTIONS | ACPI_LV_ALL_EXCEPTIONS; - break; - case ACPI_DEBUG_HIGH: - acpi_dbg_layer = 0xFFFFFFFF; - acpi_dbg_level = 0xFFFFFFFF; - break; - case ACPI_DEBUG_DRIVERS: - acpi_dbg_layer = ACPI_ALL_DRIVERS; - acpi_dbg_level = 0xFFFFFFFF; - break; - } -} - - #endif /*__ACPI_DRIVERS_H__*/ diff --git a/xen/include/acpi/acpiosxf.h b/xen/include/acpi/acpiosxf.h index 6f485231ac..57779919c1 100644 --- a/xen/include/acpi/acpiosxf.h +++ b/xen/include/acpi/acpiosxf.h @@ -9,7 +9,7 @@ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -169,17 +169,19 @@ acpi_status acpi_os_map_memory ( acpi_physical_address physical_address, acpi_size size, - void **logical_address); + void __iomem **logical_address); void acpi_os_unmap_memory ( - void *logical_address, + void __iomem *logical_address, acpi_size size); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_os_get_physical_address ( void *logical_address, acpi_physical_address *physical_address); +#endif /* @@ -188,14 +190,14 @@ acpi_os_get_physical_address ( acpi_status acpi_os_install_interrupt_handler ( - u32 interrupt_number, - OSD_HANDLER service_routine, + u32 gsi, + acpi_osd_handler service_routine, void *context); acpi_status acpi_os_remove_interrupt_handler ( - u32 interrupt_number, - OSD_HANDLER service_routine); + u32 gsi, + acpi_osd_handler service_routine); /* @@ -209,13 +211,16 @@ acpi_os_get_thread_id ( acpi_status acpi_os_queue_for_execution ( u32 priority, - OSD_EXECUTION_CALLBACK function, + acpi_osd_exec_callback function, + void *context); + +void +acpi_os_wait_events_complete ( void *context); void acpi_os_sleep ( - u32 seconds, - u32 milliseconds); + acpi_integer milliseconds); void acpi_os_stall ( @@ -258,25 +263,28 @@ acpi_os_write_memory ( /* * Platform and hardware-independent PCI configuration space access + * Note: Can't use "Register" as a parameter, changed to "Reg" -- + * certain compilers complain. */ acpi_status acpi_os_read_pci_configuration ( struct acpi_pci_id *pci_id, - u32 register, + u32 reg, void *value, u32 width); acpi_status acpi_os_write_pci_configuration ( struct acpi_pci_id *pci_id, - u32 register, + u32 reg, acpi_integer value, u32 width); /* * Interim function needed for PCI IRQ routing */ + void acpi_os_derive_pci_id( acpi_handle rhandle, @@ -292,12 +300,14 @@ acpi_os_readable ( void *pointer, acpi_size length); +#ifdef ACPI_FUTURE_USAGE u8 acpi_os_writable ( void *pointer, acpi_size length); +#endif -u32 +u64 acpi_os_get_timer ( void); @@ -329,9 +339,11 @@ acpi_os_redirect_output ( * Debug input */ +#ifdef ACPI_FUTURE_USAGE u32 acpi_os_get_line ( char *buffer); +#endif /* diff --git a/xen/include/acpi/acpixf.h b/xen/include/acpi/acpixf.h index fcebceb3e2..00d78b7965 100644 --- a/xen/include/acpi/acpixf.h +++ b/xen/include/acpi/acpixf.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -70,9 +70,11 @@ acpi_status acpi_terminate ( void); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_subsystem_status ( void); +#endif acpi_status acpi_enable ( @@ -82,9 +84,11 @@ acpi_status acpi_disable ( void); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_system_info ( struct acpi_buffer *ret_buffer); +#endif const char * acpi_format_exception ( @@ -94,10 +98,12 @@ acpi_status acpi_purge_cached_objects ( void); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_install_initialization_handler ( acpi_init_handler handler, u32 function); +#endif /* * ACPI Memory manager @@ -129,6 +135,7 @@ acpi_status acpi_load_tables ( void); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_load_table ( struct acpi_table_header *table_ptr); @@ -142,6 +149,7 @@ acpi_get_table_header ( acpi_table_type table_type, u32 instance, struct acpi_table_header *out_table_header); +#endif /* ACPI_FUTURE_USAGE */ acpi_status acpi_get_table ( @@ -218,6 +226,7 @@ acpi_evaluate_object ( struct acpi_object_list *parameter_objects, struct acpi_buffer *return_object_buffer); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_evaluate_object_typed ( acpi_handle object, @@ -225,6 +234,7 @@ acpi_evaluate_object_typed ( struct acpi_object_list *external_params, struct acpi_buffer *return_buffer, acpi_object_type return_type); +#endif acpi_status acpi_get_object_info ( @@ -296,9 +306,20 @@ acpi_install_gpe_handler ( acpi_handle gpe_device, u32 gpe_number, u32 type, - acpi_gpe_handler handler, + acpi_event_handler address, void *context); +#ifdef ACPI_FUTURE_USAGE +acpi_status +acpi_install_exception_handler ( + acpi_exception_handler handler); +#endif + + +/* + * Event interfaces + */ + acpi_status acpi_acquire_global_lock ( u16 timeout, @@ -312,7 +333,7 @@ acpi_status acpi_remove_gpe_handler ( acpi_handle gpe_device, u32 gpe_number, - acpi_gpe_handler handler); + acpi_event_handler address); acpi_status acpi_enable_event ( @@ -328,10 +349,18 @@ acpi_status acpi_clear_event ( u32 event); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_event_status ( u32 event, acpi_event_status *event_status); +#endif /* ACPI_FUTURE_USAGE */ + +acpi_status +acpi_set_gpe_type ( + acpi_handle gpe_device, + u32 gpe_number, + u8 type); acpi_status acpi_enable_gpe ( @@ -351,12 +380,14 @@ acpi_clear_gpe ( u32 gpe_number, u32 flags); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_gpe_status ( acpi_handle gpe_device, u32 gpe_number, u32 flags, acpi_event_status *event_status); +#endif /* ACPI_FUTURE_USAGE */ acpi_status acpi_install_gpe_block ( @@ -385,10 +416,12 @@ acpi_get_current_resources( acpi_handle device_handle, struct acpi_buffer *ret_buffer); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_possible_resources( acpi_handle device_handle, struct acpi_buffer *ret_buffer); +#endif acpi_status acpi_walk_resources ( @@ -432,9 +465,11 @@ acpi_status acpi_set_firmware_waking_vector ( acpi_physical_address physical_address); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_get_firmware_waking_vector ( acpi_physical_address *physical_address); +#endif acpi_status acpi_get_sleep_type_data ( @@ -446,11 +481,11 @@ acpi_status acpi_enter_sleep_state_prep ( u8 sleep_state); -acpi_status +acpi_status asmlinkage acpi_enter_sleep_state ( u8 sleep_state); -acpi_status +acpi_status asmlinkage acpi_enter_sleep_state_s4bios ( void); diff --git a/xen/include/acpi/acstruct.h b/xen/include/acpi/acstruct.h index c746cb9c3b..6b2284c9e8 100644 --- a/xen/include/acpi/acstruct.h +++ b/xen/include/acpi/acstruct.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -69,13 +69,14 @@ struct acpi_walk_state { u8 data_type; /* To differentiate various internal objs MUST BE FIRST!*/\ + u8 walk_type; acpi_owner_id owner_id; /* Owner of objects created during the walk */ u8 last_predicate; /* Result of last predicate */ + u8 reserved; /* For alignment */ u8 current_result; /* */ u8 next_op_info; /* Info about next_op */ u8 num_operands; /* Stack pointer for Operands[] array */ u8 return_used; - u8 walk_type; u16 opcode; /* Current AML opcode */ u8 scope_depth; u8 reserved1; @@ -91,7 +92,8 @@ struct acpi_walk_state struct acpi_namespace_node arguments[ACPI_METHOD_NUM_ARGS]; /* Control method arguments */ union acpi_operand_object **caller_return_desc; union acpi_generic_state *control_state; /* List of control states (nested IFs) */ - struct acpi_namespace_node *deferred_node; /* Used when executing deferred opcodes */ + struct acpi_namespace_node *deferred_node; /* Used when executing deferred opcodes */ + struct acpi_gpe_event_info *gpe_event_info; /* Info for GPE (_Lxx/_Exx methods only */ struct acpi_namespace_node local_variables[ACPI_METHOD_NUM_LOCALS]; /* Control method locals */ struct acpi_namespace_node *method_call_node; /* Called method Node*/ union acpi_parse_object *method_call_op; /* method_call Op if running a method */ @@ -112,7 +114,7 @@ struct acpi_walk_state union acpi_parse_object *next_op; /* next op to be processed */ acpi_parse_downwards descending_callback; acpi_parse_upwards ascending_callback; - struct acpi_thread_state *acpi_thread; + struct acpi_thread_state *thread; struct acpi_walk_state *next; /* Next walk_state in list */ }; @@ -200,4 +202,21 @@ union acpi_aml_operands }; +/* Internal method parameter list */ + +struct acpi_parameter_info +{ + struct acpi_namespace_node *node; + union acpi_operand_object **parameters; + union acpi_operand_object *return_object; + u8 parameter_type; + u8 return_object_type; +}; + +/* Types for parameter_type above */ + +#define ACPI_PARAM_ARGS 0 +#define ACPI_PARAM_GPE 1 + + #endif diff --git a/xen/include/acpi/actbl.h b/xen/include/acpi/actbl.h index 55680ad34b..f39ed91b5b 100644 --- a/xen/include/acpi/actbl.h +++ b/xen/include/acpi/actbl.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -288,19 +288,6 @@ struct smart_battery_table }; -/* - * High performance timer - */ -struct hpet_table -{ - ACPI_TABLE_HEADER_DEF - u32 hardware_id; - u32 base_address [3]; - u8 hpet_number; - u16 clock_tick; - u8 attributes; -}; - #pragma pack() @@ -343,5 +330,23 @@ struct acpi_table_support #include "actbl1.h" /* Acpi 1.0 table definitions */ #include "actbl2.h" /* Acpi 2.0 table definitions */ +extern u8 acpi_fadt_is_v1; /* is set to 1 if FADT is revision 1, + * needed for certain workarounds */ + +#pragma pack(1) +/* + * High performance timer + */ +struct hpet_table +{ + ACPI_TABLE_HEADER_DEF + u32 hardware_id; + struct acpi_generic_address base_address; + u8 hpet_number; + u16 clock_tick; + u8 attributes; +}; + +#pragma pack() #endif /* __ACTBL_H__ */ diff --git a/xen/include/acpi/actbl1.h b/xen/include/acpi/actbl1.h index 0db07c3291..33de5f4d2c 100644 --- a/xen/include/acpi/actbl1.h +++ b/xen/include/acpi/actbl1.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/xen/include/acpi/actbl2.h b/xen/include/acpi/actbl2.h index 188cedb529..ea3ca08d88 100644 --- a/xen/include/acpi/actbl2.h +++ b/xen/include/acpi/actbl2.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -62,6 +62,7 @@ #define BAF_8042_KEYBOARD_CONTROLLER 0x0002 #define FADT2_REVISION_ID 3 +#define FADT2_MINUS_REVISION_ID 2 #pragma pack(1) @@ -114,53 +115,56 @@ struct acpi_generic_address u8 address_space_id; /* Address space where struct or register exists. */ u8 register_bit_width; /* Size in bits of given register */ u8 register_bit_offset; /* Bit offset within the register */ - u8 reserved; /* Must be 0 */ + u8 access_width; /* Minimum Access size (ACPI 3.0) */ u64 address; /* 64-bit address of struct or register */ }; +#define FADT_REV2_COMMON \ + u32 V1_firmware_ctrl; /* 32-bit physical address of FACS */ \ + u32 V1_dsdt; /* 32-bit physical address of DSDT */ \ + u8 reserved1; /* System Interrupt Model isn't used in ACPI 2.0*/ \ + u8 prefer_PM_profile; /* Conveys preferred power management profile to OSPM. */ \ + u16 sci_int; /* System vector of SCI interrupt */ \ + u32 smi_cmd; /* Port address of SMI command port */ \ + u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */ \ + u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */ \ + u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ \ + u8 pstate_cnt; /* Processor performance state control*/ \ + u32 V1_pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ \ + u32 V1_pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ \ + u32 V1_pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ \ + u32 V1_pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ \ + u32 V1_pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ \ + u32 V1_pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ \ + u32 V1_gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ \ + u32 V1_gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ \ + u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ \ + u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ \ + u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ \ + u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ \ + u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ \ + u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ \ + u8 gpe1_base; /* Offset in gpe model where gpe1 events start */ \ + u8 cst_cnt; /* Support for the _CST object and C States change notification.*/ \ + u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ \ + u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ \ + u16 flush_size; /* Number of flush strides that need to be read */ \ + u16 flush_stride; /* Processor's memory cache line width, in bytes */ \ + u8 duty_offset; /* Processor's duty cycle index in processor's P_CNT reg*/ \ + u8 duty_width; /* Processor's duty cycle value bit width in P_CNT register.*/ \ + u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ \ + u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ \ + u8 century; /* Index to century in RTC CMOS RAM */ \ + u16 iapc_boot_arch; /* IA-PC Boot Architecture Flags. See Table 5-10 for description*/ + /* * ACPI 2.0 Fixed ACPI Description Table (FADT) */ struct fadt_descriptor_rev2 { ACPI_TABLE_HEADER_DEF /* ACPI common table header */ - u32 V1_firmware_ctrl; /* 32-bit physical address of FACS */ - u32 V1_dsdt; /* 32-bit physical address of DSDT */ - u8 reserved1; /* System Interrupt Model isn't used in ACPI 2.0*/ - u8 prefer_PM_profile; /* Conveys preferred power management profile to OSPM. */ - u16 sci_int; /* System vector of SCI interrupt */ - u32 smi_cmd; /* Port address of SMI command port */ - u8 acpi_enable; /* Value to write to smi_cmd to enable ACPI */ - u8 acpi_disable; /* Value to write to smi_cmd to disable ACPI */ - u8 S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */ - u8 pstate_cnt; /* Processor performance state control*/ - u32 V1_pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */ - u32 V1_pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */ - u32 V1_pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */ - u32 V1_pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */ - u32 V1_pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */ - u32 V1_pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */ - u32 V1_gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */ - u32 V1_gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */ - u8 pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */ - u8 pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */ - u8 pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */ - u8 pm_tm_len; /* Byte Length of ports at pm_tm_blk */ - u8 gpe0_blk_len; /* Byte Length of ports at gpe0_blk */ - u8 gpe1_blk_len; /* Byte Length of ports at gpe1_blk */ - u8 gpe1_base; /* Offset in gpe model where gpe1 events start */ - u8 cst_cnt; /* Support for the _CST object and C States change notification.*/ - u16 plvl2_lat; /* Worst case HW latency to enter/exit C2 state */ - u16 plvl3_lat; /* Worst case HW latency to enter/exit C3 state */ - u16 flush_size; /* Number of flush strides that need to be read */ - u16 flush_stride; /* Processor's memory cache line width, in bytes */ - u8 duty_offset; /* Processor's duty cycle index in processor's P_CNT reg*/ - u8 duty_width; /* Processor's duty cycle value bit width in P_CNT register.*/ - u8 day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */ - u8 mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */ - u8 century; /* Index to century in RTC CMOS RAM */ - u16 iapc_boot_arch; /* IA-PC Boot Architecture Flags. See Table 5-10 for description*/ + FADT_REV2_COMMON u8 reserved2; /* Reserved */ u32 wb_invd : 1; /* The wbinvd instruction works properly */ u32 wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */ @@ -195,6 +199,20 @@ struct fadt_descriptor_rev2 }; +/* "Downrevved" ACPI 2.0 FADT descriptor */ + +struct fadt_descriptor_rev2_minus +{ + ACPI_TABLE_HEADER_DEF /* ACPI common table header */ + FADT_REV2_COMMON + u8 reserved2; /* Reserved */ + u32 flags; + struct acpi_generic_address reset_register; /* Reset register address in GAS format */ + u8 reset_value; /* Value to write to the reset_register port to reset the system. */ + u8 reserved7[3]; /* These three bytes must be zero */ +}; + + /* Embedded Controller */ struct ec_boot_resources diff --git a/xen/include/acpi/actypes.h b/xen/include/acpi/actypes.h index ae1a73e617..51cb780c24 100644 --- a/xen/include/acpi/actypes.h +++ b/xen/include/acpi/actypes.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -303,7 +303,7 @@ struct uint32_struct typedef u32 acpi_integer; #define ACPI_INTEGER_MAX ACPI_UINT32_MAX #define ACPI_INTEGER_BIT_SIZE 32 -#define ACPI_MAX_DECIMAL_DIGITS 10 +#define ACPI_MAX_DECIMAL_DIGITS 10 /* 2^32 = 4,294,967,296 */ #define ACPI_USE_NATIVE_DIVIDE /* Use compiler native 32-bit divide */ @@ -315,13 +315,18 @@ typedef u32 acpi_integer; typedef u64 acpi_integer; #define ACPI_INTEGER_MAX ACPI_UINT64_MAX #define ACPI_INTEGER_BIT_SIZE 64 -#define ACPI_MAX_DECIMAL_DIGITS 19 +#define ACPI_MAX_DECIMAL_DIGITS 20 /* 2^64 = 18,446,744,073,709,551,616 */ + #if ACPI_MACHINE_WIDTH == 64 #define ACPI_USE_NATIVE_DIVIDE /* Use compiler native 64-bit divide */ #endif #endif +#define ACPI_MAX64_DECIMAL_DIGITS 20 +#define ACPI_MAX32_DECIMAL_DIGITS 10 +#define ACPI_MAX16_DECIMAL_DIGITS 5 +#define ACPI_MAX8_DECIMAL_DIGITS 3 /* * Constants with special meanings @@ -349,7 +354,6 @@ typedef u64 acpi_integer; /* * Power state values */ - #define ACPI_STATE_UNKNOWN (u8) 0xFF #define ACPI_STATE_S0 (u8) 0 @@ -393,7 +397,6 @@ typedef u64 acpi_integer; #define ACPI_NOTIFY_BUS_MODE_MISMATCH (u8) 6 #define ACPI_NOTIFY_POWER_FAULT (u8) 7 - /* * Table types. These values are passed to the table related APIs */ @@ -409,14 +412,13 @@ typedef u32 acpi_table_type; #define ACPI_TABLE_MAX 6 #define NUM_ACPI_TABLE_TYPES (ACPI_TABLE_MAX+1) - /* * Types associated with ACPI names and objects. The first group of * values (up to ACPI_TYPE_EXTERNAL_MAX) correspond to the definition * of the ACPI object_type() operator (See the ACPI Spec). Therefore, * only add to the first group if the spec changes. * - * Types must be kept in sync with the global acpi_ns_properties + * NOTE: Types must be kept in sync with the global acpi_ns_properties * and acpi_ns_type_names arrays. */ typedef u32 acpi_object_type; @@ -453,26 +455,27 @@ typedef u32 acpi_object_type; #define ACPI_TYPE_LOCAL_INDEX_FIELD 0x13 #define ACPI_TYPE_LOCAL_REFERENCE 0x14 /* Arg#, Local#, Name, Debug, ref_of, Index */ #define ACPI_TYPE_LOCAL_ALIAS 0x15 -#define ACPI_TYPE_LOCAL_NOTIFY 0x16 -#define ACPI_TYPE_LOCAL_ADDRESS_HANDLER 0x17 -#define ACPI_TYPE_LOCAL_RESOURCE 0x18 -#define ACPI_TYPE_LOCAL_RESOURCE_FIELD 0x19 -#define ACPI_TYPE_LOCAL_SCOPE 0x1A /* 1 Name, multiple object_list Nodes */ +#define ACPI_TYPE_LOCAL_METHOD_ALIAS 0x16 +#define ACPI_TYPE_LOCAL_NOTIFY 0x17 +#define ACPI_TYPE_LOCAL_ADDRESS_HANDLER 0x18 +#define ACPI_TYPE_LOCAL_RESOURCE 0x19 +#define ACPI_TYPE_LOCAL_RESOURCE_FIELD 0x1A +#define ACPI_TYPE_LOCAL_SCOPE 0x1B /* 1 Name, multiple object_list Nodes */ -#define ACPI_TYPE_NS_NODE_MAX 0x1A /* Last typecode used within a NS Node */ +#define ACPI_TYPE_NS_NODE_MAX 0x1B /* Last typecode used within a NS Node */ /* * These are special object types that never appear in * a Namespace node, only in an union acpi_operand_object */ -#define ACPI_TYPE_LOCAL_EXTRA 0x1B -#define ACPI_TYPE_LOCAL_DATA 0x1C +#define ACPI_TYPE_LOCAL_EXTRA 0x1C +#define ACPI_TYPE_LOCAL_DATA 0x1D -#define ACPI_TYPE_LOCAL_MAX 0x1C +#define ACPI_TYPE_LOCAL_MAX 0x1D /* All types above here are invalid */ -#define ACPI_TYPE_INVALID 0x1D +#define ACPI_TYPE_INVALID 0x1E #define ACPI_TYPE_NOT_FOUND 0xFF @@ -514,9 +517,8 @@ typedef u32 acpi_object_type; #define ACPI_WRITE 1 #define ACPI_IO_MASK 1 - /* - * Acpi Event Types: Fixed & General Purpose + * Event Types: Fixed & General Purpose */ typedef u32 acpi_event_type; @@ -531,25 +533,8 @@ typedef u32 acpi_event_type; #define ACPI_EVENT_MAX 4 #define ACPI_NUM_FIXED_EVENTS ACPI_EVENT_MAX + 1 -#define ACPI_GPE_INVALID 0xFF -#define ACPI_GPE_MAX 0xFF -#define ACPI_NUM_GPE 256 - -#define ACPI_EVENT_LEVEL_TRIGGERED 1 -#define ACPI_EVENT_EDGE_TRIGGERED 2 - /* - * Flags for GPE and Lock interfaces - */ -#define ACPI_EVENT_WAKE_ENABLE 0x2 -#define ACPI_EVENT_WAKE_DISABLE 0x2 - -#define ACPI_NOT_ISR 0x1 -#define ACPI_ISR 0x0 - - -/* - * acpi_event Status: + * Event Status - Per event * ------------- * The encoding of acpi_event_status is illustrated below. * Note that a set bit (1) indicates the property is TRUE @@ -570,12 +555,74 @@ typedef u32 acpi_event_status; #define ACPI_EVENT_FLAG_WAKE_ENABLED (acpi_event_status) 0x02 #define ACPI_EVENT_FLAG_SET (acpi_event_status) 0x04 +/* + * General Purpose Events (GPE) + */ +#define ACPI_GPE_INVALID 0xFF +#define ACPI_GPE_MAX 0xFF +#define ACPI_NUM_GPE 256 + +#define ACPI_GPE_ENABLE 0 +#define ACPI_GPE_DISABLE 1 + + +/* + * GPE info flags - Per GPE + * +-+-+-+---+---+-+ + * |7|6|5|4:3|2:1|0| + * +-+-+-+---+---+-+ + * | | | | | | + * | | | | | +--- Interrupt type: Edge or Level Triggered + * | | | | +--- Type: Wake-only, Runtime-only, or wake/runtime + * | | | +--- Type of dispatch -- to method, handler, or none + * | | +--- Enabled for runtime? + * | +--- Enabled for wake? + * +--- System state when GPE ocurred (running/waking) + */ +#define ACPI_GPE_XRUPT_TYPE_MASK (u8) 0x01 +#define ACPI_GPE_LEVEL_TRIGGERED (u8) 0x01 +#define ACPI_GPE_EDGE_TRIGGERED (u8) 0x00 + +#define ACPI_GPE_TYPE_MASK (u8) 0x06 +#define ACPI_GPE_TYPE_WAKE_RUN (u8) 0x06 +#define ACPI_GPE_TYPE_WAKE (u8) 0x02 +#define ACPI_GPE_TYPE_RUNTIME (u8) 0x04 /* Default */ + +#define ACPI_GPE_DISPATCH_MASK (u8) 0x18 +#define ACPI_GPE_DISPATCH_HANDLER (u8) 0x08 +#define ACPI_GPE_DISPATCH_METHOD (u8) 0x10 +#define ACPI_GPE_DISPATCH_NOT_USED (u8) 0x00 /* Default */ + +#define ACPI_GPE_RUN_ENABLE_MASK (u8) 0x20 +#define ACPI_GPE_RUN_ENABLED (u8) 0x20 +#define ACPI_GPE_RUN_DISABLED (u8) 0x00 /* Default */ + +#define ACPI_GPE_WAKE_ENABLE_MASK (u8) 0x40 +#define ACPI_GPE_WAKE_ENABLED (u8) 0x40 +#define ACPI_GPE_WAKE_DISABLED (u8) 0x00 /* Default */ + +#define ACPI_GPE_ENABLE_MASK (u8) 0x60 /* Both run/wake */ + +#define ACPI_GPE_SYSTEM_MASK (u8) 0x80 +#define ACPI_GPE_SYSTEM_RUNNING (u8) 0x80 +#define ACPI_GPE_SYSTEM_WAKING (u8) 0x00 + +/* + * Flags for GPE and Lock interfaces + */ +#define ACPI_EVENT_WAKE_ENABLE 0x2 /* acpi_gpe_enable */ +#define ACPI_EVENT_WAKE_DISABLE 0x2 /* acpi_gpe_disable */ + +#define ACPI_NOT_ISR 0x1 +#define ACPI_ISR 0x0 + /* Notify types */ -#define ACPI_SYSTEM_NOTIFY 0 -#define ACPI_DEVICE_NOTIFY 1 -#define ACPI_MAX_NOTIFY_HANDLER_TYPE 1 +#define ACPI_SYSTEM_NOTIFY 0x1 +#define ACPI_DEVICE_NOTIFY 0x2 +#define ACPI_ALL_NOTIFY 0x3 +#define ACPI_MAX_NOTIFY_HANDLER_TYPE 0x3 #define ACPI_MAX_SYS_NOTIFY 0x7f @@ -756,11 +803,11 @@ struct acpi_system_info */ typedef u32 -(ACPI_SYSTEM_XFACE *OSD_HANDLER) ( +(ACPI_SYSTEM_XFACE *acpi_osd_handler) ( void *context); typedef void -(ACPI_SYSTEM_XFACE *OSD_EXECUTION_CALLBACK) ( +(ACPI_SYSTEM_XFACE *acpi_osd_exec_callback) ( void *context); /* @@ -770,10 +817,6 @@ typedef u32 (*acpi_event_handler) ( void *context); -typedef -void (*acpi_gpe_handler) ( - void *context); - typedef void (*acpi_notify_handler) ( acpi_handle device, @@ -793,8 +836,16 @@ acpi_status (*acpi_init_handler) ( #define ACPI_INIT_DEVICE_INI 1 +typedef +acpi_status (*acpi_exception_handler) ( + acpi_status aml_status, + acpi_name name, + u16 opcode, + u32 aml_offset, + void *context); -/* Address Spaces (Operation Regions */ + +/* Address Spaces (For Operation Regions) */ typedef acpi_status (*acpi_adr_space_handler) ( @@ -861,6 +912,7 @@ struct acpi_compatible_id_list #define ACPI_VALID_HID 0x0004 #define ACPI_VALID_UID 0x0008 #define ACPI_VALID_CID 0x0010 +#define ACPI_VALID_SXDS 0x0020 #define ACPI_COMMON_OBJ_INFO \ @@ -880,11 +932,12 @@ struct acpi_device_info { ACPI_COMMON_OBJ_INFO; - u32 valid; /* Indicates which fields are valid */ + u32 valid; /* Indicates which fields below are valid */ u32 current_status; /* _STA value */ acpi_integer address; /* _ADR value if any */ struct acpi_device_id hardware_id; /* _HID value if any */ struct acpi_device_id unique_id; /* _UID value if any */ + u8 highest_dstates[4]; /* _sx_d values: 0xFF indicates not valid */ struct acpi_compatible_id_list compatibility_id; /* List of _CIDs if any */ }; diff --git a/xen/include/acpi/acutils.h b/xen/include/acpi/acutils.h index 4927d6beab..0de26b8f10 100644 --- a/xen/include/acpi/acutils.h +++ b/xen/include/acpi/acutils.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,7 +52,6 @@ acpi_status (*acpi_pkg_callback) ( union acpi_generic_state *state, void *context); - acpi_status acpi_ut_walk_package_tree ( union acpi_operand_object *source_object, @@ -60,7 +59,6 @@ acpi_ut_walk_package_tree ( acpi_pkg_callback walk_callback, void *context); - struct acpi_pkg_info { u8 *free_space; @@ -179,6 +177,12 @@ acpi_ut_strncpy ( const char *src_string, acpi_size count); +int +acpi_ut_memcmp ( + const char *buffer1, + const char *buffer2, + acpi_size count); + int acpi_ut_strncmp ( const char *string1, @@ -473,8 +477,13 @@ acpi_ut_delete_internal_object_list ( #define METHOD_NAME__PRT "_PRT" #define METHOD_NAME__CRS "_CRS" #define METHOD_NAME__PRS "_PRS" +#define METHOD_NAME__PRW "_PRW" +acpi_status +acpi_ut_osi_implementation ( + struct acpi_walk_state *walk_state); + acpi_status acpi_ut_evaluate_object ( struct acpi_namespace_node *prefix_node, @@ -508,6 +517,10 @@ acpi_ut_execute_UID ( struct acpi_namespace_node *device_node, struct acpi_device_id *uid); +acpi_status +acpi_ut_execute_sxds ( + struct acpi_namespace_node *device_node, + u8 *highest); /* * ut_mutex - mutual exclusion interfaces @@ -570,6 +583,10 @@ union acpi_operand_object * acpi_ut_create_buffer_object ( acpi_size buffer_size); +union acpi_operand_object * +acpi_ut_create_string_object ( + acpi_size string_size); + /* * ut_ref_cnt - Object reference count management @@ -649,12 +666,14 @@ acpi_ut_create_update_state_and_push ( u16 action, union acpi_generic_state **state_list); +#ifdef ACPI_FUTURE_USAGE acpi_status acpi_ut_create_pkg_state_and_push ( void *internal_object, void *external_object, u16 index, union acpi_generic_state **state_list); +#endif union acpi_generic_state * acpi_ut_create_control_state ( @@ -664,6 +683,7 @@ void acpi_ut_delete_generic_state ( union acpi_generic_state *state); +#ifdef ACPI_ENABLE_OBJECT_CACHE void acpi_ut_delete_generic_state_cache ( void); @@ -671,6 +691,7 @@ acpi_ut_delete_generic_state_cache ( void acpi_ut_delete_object_cache ( void); +#endif /* * utmisc @@ -683,14 +704,14 @@ acpi_ut_print_string ( acpi_status acpi_ut_divide ( - acpi_integer *in_dividend, - acpi_integer *in_divisor, + acpi_integer in_dividend, + acpi_integer in_divisor, acpi_integer *out_quotient, acpi_integer *out_remainder); acpi_status acpi_ut_short_divide ( - acpi_integer *in_dividend, + acpi_integer in_dividend, u32 divisor, acpi_integer *out_quotient, u32 *out_remainder); @@ -709,9 +730,15 @@ acpi_ut_strtoul64 ( u32 base, acpi_integer *ret_integer); +/* Values for Base above (16=Hex, 10=Decimal) */ + +#define ACPI_ANY_BASE 0 + +#ifdef ACPI_FUTURE_USAGE char * acpi_ut_strupr ( char *src_string); +#endif u8 * acpi_ut_get_resource_end_tag ( @@ -753,9 +780,11 @@ acpi_ut_release_to_cache ( u32 list_id, void *object); +#ifdef ACPI_ENABLE_OBJECT_CACHE void acpi_ut_delete_generic_cache ( u32 list_id); +#endif acpi_status acpi_ut_validate_buffer ( @@ -830,9 +859,11 @@ acpi_ut_remove_allocation ( char *module, u32 line); +#ifdef ACPI_FUTURE_USAGE void acpi_ut_dump_allocation_info ( void); +#endif void acpi_ut_dump_allocations ( diff --git a/xen/include/acpi/platform/acenv.h b/xen/include/acpi/platform/acenv.h index 9a0cd41084..5a956b549b 100644 --- a/xen/include/acpi/platform/acenv.h +++ b/xen/include/acpi/platform/acenv.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -57,6 +57,7 @@ #define ACPI_DISASSEMBLER #define ACPI_NO_METHOD_EXECUTION #define ACPI_USE_SYSTEM_CLIBRARY +#define ACPI_ENABLE_OBJECT_CACHE #endif #ifdef _ACPI_EXEC_APP @@ -67,6 +68,7 @@ #define ACPI_DEBUGGER #define ACPI_DISASSEMBLER #define ACPI_USE_SYSTEM_CLIBRARY +#define ACPI_ENABLE_OBJECT_CACHE #endif #ifdef _ACPI_ASL_COMPILER @@ -75,6 +77,7 @@ #define ACPI_DISASSEMBLER #define ACPI_CONSTANT_EVAL_ONLY #define ACPI_USE_SYSTEM_CLIBRARY +#define ACPI_ENABLE_OBJECT_CACHE #endif /* @@ -152,12 +155,8 @@ #define COMPILER_DEPENDENT_INT64 long long #define COMPILER_DEPENDENT_UINT64 unsigned long long - -/* Name of host operating system (returned by the _OS_ namespace object) */ - -#define ACPI_OS_NAME "Intel ACPI/CA Core Subsystem" - -/* This macro is used to tag functions as "printf-like" because +/* + * This macro is used to tag functions as "printf-like" because * some compilers can catch printf format string problems. MSVC * doesn't, so this is proprocessed away. */ @@ -227,7 +226,11 @@ */ #define ACPI_STRSTR(s1,s2) strstr((s1), (s2)) + +#ifdef ACPI_FUTURE_USAGE #define ACPI_STRUPR(s) (void) acpi_ut_strupr ((s)) +#endif + #define ACPI_STRLEN(s) (acpi_size) strlen((s)) #define ACPI_STRCPY(d,s) (void) strcpy((d), (s)) #define ACPI_STRNCPY(d,s,n) (void) strncpy((d), (s), (acpi_size)(n)) @@ -236,6 +239,7 @@ #define ACPI_STRCAT(d,s) (void) strcat((d), (s)) #define ACPI_STRNCAT(d,s,n) strncat((d), (s), (acpi_size)(n)) #define ACPI_STRTOUL(d,s,n) strtoul((d), (s), (acpi_size)(n)) +#define ACPI_MEMCMP(s1,s2,n) memcmp((s1), (s2), (acpi_size)(n)) #define ACPI_MEMCPY(d,s,n) (void) memcpy((d), (s), (acpi_size)(n)) #define ACPI_MEMSET(d,s,n) (void) memset((d), (s), (acpi_size)(n)) @@ -290,7 +294,11 @@ typedef char *va_list; #define ACPI_STRSTR(s1,s2) acpi_ut_strstr ((s1), (s2)) + +#ifdef ACPI_FUTURE_USAGE #define ACPI_STRUPR(s) (void) acpi_ut_strupr ((s)) +#endif + #define ACPI_STRLEN(s) (acpi_size) acpi_ut_strlen ((s)) #define ACPI_STRCPY(d,s) (void) acpi_ut_strcpy ((d), (s)) #define ACPI_STRNCPY(d,s,n) (void) acpi_ut_strncpy ((d), (s), (acpi_size)(n)) @@ -299,6 +307,7 @@ typedef char *va_list; #define ACPI_STRCAT(d,s) (void) acpi_ut_strcat ((d), (s)) #define ACPI_STRNCAT(d,s,n) acpi_ut_strncat ((d), (s), (acpi_size)(n)) #define ACPI_STRTOUL(d,s,n) acpi_ut_strtoul ((d), (s), (acpi_size)(n)) +#define ACPI_MEMCMP(s1,s2,n) acpi_ut_memcmp((s1), (s2), (acpi_size)(n)) #define ACPI_MEMCPY(d,s,n) (void) acpi_ut_memcpy ((d), (s), (acpi_size)(n)) #define ACPI_MEMSET(d,v,n) (void) acpi_ut_memset ((d), (v), (acpi_size)(n)) #define ACPI_TOUPPER acpi_ut_to_upper diff --git a/xen/include/acpi/platform/acgcc.h b/xen/include/acpi/platform/acgcc.h index ac15b08460..91fda36b04 100644 --- a/xen/include/acpi/platform/acgcc.h +++ b/xen/include/acpi/platform/acgcc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,6 +54,6 @@ * to to tell the compiler warning in a per-variable manner that a variable * is unused. */ -#define ACPI_UNUSED_VAR __attribute_used__ +#define ACPI_UNUSED_VAR __attribute__ ((unused)) #endif /* __ACGCC_H__ */ diff --git a/xen/include/acpi/platform/aclinux.h b/xen/include/acpi/platform/aclinux.h index eecd6c888c..4006b0ce01 100644 --- a/xen/include/acpi/platform/aclinux.h +++ b/xen/include/acpi/platform/aclinux.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2004, R. Byron Moore + * Copyright (C) 2000 - 2005, R. Byron Moore * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -44,8 +44,6 @@ #ifndef __ACLINUX_H__ #define __ACLINUX_H__ -#define ACPI_OS_NAME "Linux" - #define ACPI_USE_SYSTEM_CLIBRARY #define ACPI_USE_DO_WHILE_0 @@ -83,6 +81,8 @@ #define ACPI_USE_NATIVE_DIVIDE #endif +#define __cdecl +#define ACPI_FLUSH_CPU_CACHE() #endif /* __KERNEL__ */ /* Linux uses GCC */ diff --git a/xen/include/asm-ia64/config.h b/xen/include/asm-ia64/config.h index 74dbb3a4e5..27f1e43620 100644 --- a/xen/include/asm-ia64/config.h +++ b/xen/include/asm-ia64/config.h @@ -31,10 +31,6 @@ typedef int pid_t; #define touch_nmi_watchdog() // from linux/include/linux/types.h -#define BITS_TO_LONGS(bits) \ - (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) -#define DECLARE_BITMAP(name,bits) \ - unsigned long name[BITS_TO_LONGS(bits)] #define CLEAR_BITMAP(name,bits) \ memset(name, 0, BITS_TO_LONGS(bits)*sizeof(unsigned long)) @@ -57,7 +53,6 @@ extern char _end[]; /* standard ELF symbol */ //#define __kernel //#define __safe #define __force -#define __iomem #define __chk_user_ptr(x) (void)0 //#define __chk_io_ptr(x) (void)0 //#define __builtin_warning(x, y...) (1) @@ -77,9 +72,6 @@ extern char _end[]; /* standard ELF symbol */ //#define CONFIG_NR_CPUS 16 #define barrier() __asm__ __volatile__("": : :"memory") -// linux/include/spinlock.h -#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED - /////////////////////////////////////////////////////////////// // xen/include/asm/config.h // Natural boundary upon TR size to define xenheap space diff --git a/xen/include/asm-x86/apic.h b/xen/include/asm-x86/apic.h index 61d3f8fe47..73112359a5 100644 --- a/xen/include/asm-x86/apic.h +++ b/xen/include/asm-x86/apic.h @@ -2,19 +2,34 @@ #define __ASM_APIC_H #include -#include +#include #include #include -#ifdef CONFIG_X86_LOCAL_APIC - -#define APIC_DEBUG 0 - -#if APIC_DEBUG -#define Dprintk(x...) printk(x) -#else #define Dprintk(x...) -#endif + +/* + * Debugging macros + */ +#define APIC_QUIET 0 +#define APIC_VERBOSE 1 +#define APIC_DEBUG 2 + +extern int apic_verbosity; + +/* + * Define the default level of output to be very little + * This can be turned up by using apic=verbose for more + * information and apic=debug for _lots_ of information. + * apic_verbosity is defined in apic.c + */ +#define apic_printk(v, s, a...) do { \ + if ((v) <= apic_verbosity) \ + printk(s, ##a); \ + } while (0) + + +#ifdef CONFIG_X86_LOCAL_APIC /* * Basic functions accessing APICs. @@ -37,9 +52,12 @@ static __inline u32 apic_read(unsigned long reg) static __inline__ void apic_wait_icr_idle(void) { - do { } while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY ); + while ( apic_read( APIC_ICR ) & APIC_ICR_BUSY ) + cpu_relax(); } +int get_physical_broadcast(void); + #ifdef CONFIG_X86_GOOD_APIC # define FORCE_READ_AROUND_WRITE 0 # define apic_read_around(x) @@ -63,21 +81,29 @@ static inline void ack_APIC_irq(void) apic_write_around(APIC_EOI, 0); } +extern void (*wait_timer_tick)(void); + extern int get_maxlvt(void); extern void clear_local_APIC(void); extern void connect_bsp_APIC (void); extern void disconnect_bsp_APIC (void); extern void disable_local_APIC (void); +extern void lapic_shutdown (void); extern int verify_local_APIC (void); extern void cache_APIC_registers (void); extern void sync_Arb_IDs (void); extern void init_bsp_APIC (void); extern void setup_local_APIC (void); extern void init_apic_mappings (void); -extern void smp_local_timer_interrupt (struct cpu_user_regs * regs); -extern void setup_APIC_clocks (void); +extern void smp_local_timer_interrupt (struct cpu_user_regs *regs); +extern void setup_boot_APIC_clock (void); +extern void setup_secondary_APIC_clock (void); extern void setup_apic_nmi_watchdog (void); -extern void nmi_watchdog_tick (struct cpu_user_regs * regs); +extern int reserve_lapic_nmi(void); +extern void release_lapic_nmi(void); +extern void disable_timer_nmi_watchdog(void); +extern void enable_timer_nmi_watchdog(void); +extern void nmi_watchdog_tick (struct cpu_user_regs *regs); extern void touch_nmi_watchdog(void); extern int APIC_init_uniprocessor (void); extern void disable_APIC_timer(void); @@ -85,6 +111,7 @@ extern void enable_APIC_timer(void); extern unsigned int watchdog_on; extern int check_nmi_watchdog (void); +extern void enable_NMI_through_LVT0 (void * dummy); extern unsigned int nmi_watchdog; #define NMI_NONE 0 @@ -92,6 +119,9 @@ extern unsigned int nmi_watchdog; #define NMI_LOCAL_APIC 2 #define NMI_INVALID 3 -#endif /* CONFIG_X86_LOCAL_APIC */ +#else /* !CONFIG_X86_LOCAL_APIC */ +static inline void lapic_shutdown(void) { } + +#endif /* !CONFIG_X86_LOCAL_APIC */ #endif /* __ASM_APIC_H */ diff --git a/xen/include/asm-x86/apicdef.h b/xen/include/asm-x86/apicdef.h index 8d7f3aa3d7..911a55ef82 100644 --- a/xen/include/asm-x86/apicdef.h +++ b/xen/include/asm-x86/apicdef.h @@ -11,14 +11,11 @@ #define APIC_DEFAULT_PHYS_BASE 0xfee00000 #define APIC_ID 0x20 -#define APIC_ID_MASK (0x0F<<24) -#define GET_APIC_ID(x) (((x)>>24)&0x0F) #define APIC_LVR 0x30 #define APIC_LVR_MASK 0xFF00FF #define GET_APIC_VERSION(x) ((x)&0xFF) #define GET_APIC_MAXLVT(x) (((x)>>16)&0xFF) #define APIC_INTEGRATED(x) ((x)&0xF0) -#define APIC_XAPIC_SUPPORT(x) ((x)>=0x14) #define APIC_TASKPRI 0x80 #define APIC_TPRI_MASK 0xFF #define APIC_ARBPRI 0x90 @@ -33,8 +30,8 @@ #define SET_APIC_LOGICAL_ID(x) (((x)<<24)) #define APIC_ALL_CPUS 0xFF #define APIC_DFR 0xE0 -#define APIC_DFR_CLUSTER 0x0FFFFFFFul /* Clustered */ -#define APIC_DFR_FLAT 0xFFFFFFFFul /* Flat mode */ +#define APIC_DFR_CLUSTER 0x0FFFFFFFul +#define APIC_DFR_FLAT 0xFFFFFFFFul #define APIC_SPIV 0xF0 #define APIC_SPIV_FOCUS_DISABLED (1<<9) #define APIC_SPIV_APIC_ENABLED (1<<8) @@ -60,7 +57,6 @@ #define APIC_INT_LEVELTRIG 0x08000 #define APIC_INT_ASSERT 0x04000 #define APIC_ICR_BUSY 0x01000 -#define APIC_DEST_PHYSICAL 0x00000 #define APIC_DEST_LOGICAL 0x00800 #define APIC_DM_FIXED 0x00000 #define APIC_DM_LOWEST 0x00100 @@ -75,6 +71,7 @@ #define GET_APIC_DEST_FIELD(x) (((x)>>24)&0xFF) #define SET_APIC_DEST_FIELD(x) ((x)<<24) #define APIC_LVTT 0x320 +#define APIC_LVTTHMR 0x330 #define APIC_LVTPC 0x340 #define APIC_LVT0 0x350 #define APIC_LVT_TIMER_BASE_MASK (0x3<<18) @@ -111,18 +108,272 @@ #define APIC_BASE (fix_to_virt(FIX_APIC_BASE)) -#ifdef CONFIG_X86_CLUSTERED_APIC -#define MAX_IO_APICS 32 +#ifdef CONFIG_NUMA + #define MAX_IO_APICS 32 #else -#define MAX_IO_APICS 8 + #define MAX_IO_APICS 8 #endif - /* - * The broadcast ID is 0xF for old APICs and 0xFF for xAPICs. SAPICs - * don't broadcast (yet?), but if they did, they might use 0xFFFF. + * the local APIC register structure, memory mapped. Not terribly well + * tested, but we might eventually use this one in the future - the + * problem why we cannot use it right now is the P5 APIC, it has an + * errata which cannot take 8-bit reads and writes, only 32-bit ones ... */ -#define APIC_BROADCAST_ID_XAPIC (0xFF) -#define APIC_BROADCAST_ID_APIC (0x0F) +#define u32 unsigned int + +#define lapic ((volatile struct local_apic *)APIC_BASE) + +#ifndef __ASSEMBLY__ +struct local_apic { + +/*000*/ struct { u32 __reserved[4]; } __reserved_01; + +/*010*/ struct { u32 __reserved[4]; } __reserved_02; + +/*020*/ struct { /* APIC ID Register */ + u32 __reserved_1 : 24, + phys_apic_id : 4, + __reserved_2 : 4; + u32 __reserved[3]; + } id; + +/*030*/ const + struct { /* APIC Version Register */ + u32 version : 8, + __reserved_1 : 8, + max_lvt : 8, + __reserved_2 : 8; + u32 __reserved[3]; + } version; + +/*040*/ struct { u32 __reserved[4]; } __reserved_03; + +/*050*/ struct { u32 __reserved[4]; } __reserved_04; + +/*060*/ struct { u32 __reserved[4]; } __reserved_05; + +/*070*/ struct { u32 __reserved[4]; } __reserved_06; + +/*080*/ struct { /* Task Priority Register */ + u32 priority : 8, + __reserved_1 : 24; + u32 __reserved_2[3]; + } tpr; + +/*090*/ const + struct { /* Arbitration Priority Register */ + u32 priority : 8, + __reserved_1 : 24; + u32 __reserved_2[3]; + } apr; + +/*0A0*/ const + struct { /* Processor Priority Register */ + u32 priority : 8, + __reserved_1 : 24; + u32 __reserved_2[3]; + } ppr; + +/*0B0*/ struct { /* End Of Interrupt Register */ + u32 eoi; + u32 __reserved[3]; + } eoi; + +/*0C0*/ struct { u32 __reserved[4]; } __reserved_07; + +/*0D0*/ struct { /* Logical Destination Register */ + u32 __reserved_1 : 24, + logical_dest : 8; + u32 __reserved_2[3]; + } ldr; + +/*0E0*/ struct { /* Destination Format Register */ + u32 __reserved_1 : 28, + model : 4; + u32 __reserved_2[3]; + } dfr; + +/*0F0*/ struct { /* Spurious Interrupt Vector Register */ + u32 spurious_vector : 8, + apic_enabled : 1, + focus_cpu : 1, + __reserved_2 : 22; + u32 __reserved_3[3]; + } svr; + +/*100*/ struct { /* In Service Register */ +/*170*/ u32 bitfield; + u32 __reserved[3]; + } isr [8]; + +/*180*/ struct { /* Trigger Mode Register */ +/*1F0*/ u32 bitfield; + u32 __reserved[3]; + } tmr [8]; + +/*200*/ struct { /* Interrupt Request Register */ +/*270*/ u32 bitfield; + u32 __reserved[3]; + } irr [8]; + +/*280*/ union { /* Error Status Register */ + struct { + u32 send_cs_error : 1, + receive_cs_error : 1, + send_accept_error : 1, + receive_accept_error : 1, + __reserved_1 : 1, + send_illegal_vector : 1, + receive_illegal_vector : 1, + illegal_register_address : 1, + __reserved_2 : 24; + u32 __reserved_3[3]; + } error_bits; + struct { + u32 errors; + u32 __reserved_3[3]; + } all_errors; + } esr; + +/*290*/ struct { u32 __reserved[4]; } __reserved_08; + +/*2A0*/ struct { u32 __reserved[4]; } __reserved_09; + +/*2B0*/ struct { u32 __reserved[4]; } __reserved_10; + +/*2C0*/ struct { u32 __reserved[4]; } __reserved_11; + +/*2D0*/ struct { u32 __reserved[4]; } __reserved_12; + +/*2E0*/ struct { u32 __reserved[4]; } __reserved_13; + +/*2F0*/ struct { u32 __reserved[4]; } __reserved_14; + +/*300*/ struct { /* Interrupt Command Register 1 */ + u32 vector : 8, + delivery_mode : 3, + destination_mode : 1, + delivery_status : 1, + __reserved_1 : 1, + level : 1, + trigger : 1, + __reserved_2 : 2, + shorthand : 2, + __reserved_3 : 12; + u32 __reserved_4[3]; + } icr1; + +/*310*/ struct { /* Interrupt Command Register 2 */ + union { + u32 __reserved_1 : 24, + phys_dest : 4, + __reserved_2 : 4; + u32 __reserved_3 : 24, + logical_dest : 8; + } dest; + u32 __reserved_4[3]; + } icr2; + +/*320*/ struct { /* LVT - Timer */ + u32 vector : 8, + __reserved_1 : 4, + delivery_status : 1, + __reserved_2 : 3, + mask : 1, + timer_mode : 1, + __reserved_3 : 14; + u32 __reserved_4[3]; + } lvt_timer; + +/*330*/ struct { /* LVT - Thermal Sensor */ + u32 vector : 8, + delivery_mode : 3, + __reserved_1 : 1, + delivery_status : 1, + __reserved_2 : 3, + mask : 1, + __reserved_3 : 15; + u32 __reserved_4[3]; + } lvt_thermal; + +/*340*/ struct { /* LVT - Performance Counter */ + u32 vector : 8, + delivery_mode : 3, + __reserved_1 : 1, + delivery_status : 1, + __reserved_2 : 3, + mask : 1, + __reserved_3 : 15; + u32 __reserved_4[3]; + } lvt_pc; + +/*350*/ struct { /* LVT - LINT0 */ + u32 vector : 8, + delivery_mode : 3, + __reserved_1 : 1, + delivery_status : 1, + polarity : 1, + remote_irr : 1, + trigger : 1, + mask : 1, + __reserved_2 : 15; + u32 __reserved_3[3]; + } lvt_lint0; + +/*360*/ struct { /* LVT - LINT1 */ + u32 vector : 8, + delivery_mode : 3, + __reserved_1 : 1, + delivery_status : 1, + polarity : 1, + remote_irr : 1, + trigger : 1, + mask : 1, + __reserved_2 : 15; + u32 __reserved_3[3]; + } lvt_lint1; + +/*370*/ struct { /* LVT - Error */ + u32 vector : 8, + __reserved_1 : 4, + delivery_status : 1, + __reserved_2 : 3, + mask : 1, + __reserved_3 : 15; + u32 __reserved_4[3]; + } lvt_error; + +/*380*/ struct { /* Timer Initial Count Register */ + u32 initial_count; + u32 __reserved_2[3]; + } timer_icr; + +/*390*/ const + struct { /* Timer Current Count Register */ + u32 curr_count; + u32 __reserved_2[3]; + } timer_ccr; + +/*3A0*/ struct { u32 __reserved[4]; } __reserved_16; + +/*3B0*/ struct { u32 __reserved[4]; } __reserved_17; + +/*3C0*/ struct { u32 __reserved[4]; } __reserved_18; + +/*3D0*/ struct { u32 __reserved[4]; } __reserved_19; + +/*3E0*/ struct { /* Timer Divide Configuration Register */ + u32 divisor : 4, + __reserved_1 : 28; + u32 __reserved_2[3]; + } timer_dcr; + +/*3F0*/ struct { u32 __reserved[4]; } __reserved_20; + +} __attribute__ ((packed)); +#endif /* !__ASSEMBLY__ */ + +#undef u32 #endif diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h index 7f44c5ae87..1ddc8228db 100644 --- a/xen/include/asm-x86/config.h +++ b/xen/include/asm-x86/config.h @@ -69,6 +69,8 @@ extern unsigned long _end; /* standard ELF symbol */ #if defined(__x86_64__) +#define CONFIG_X86_64 1 + #define asmlinkage #define XENHEAP_DEFAULT_MB (16) @@ -179,6 +181,8 @@ extern unsigned long _end; /* standard ELF symbol */ #elif defined(__i386__) +#define CONFIG_X86_32 1 + #define asmlinkage __attribute__((regparm(0))) /* diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h index 514ccdf0f1..683ba2ac0c 100644 --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -2,7 +2,9 @@ #ifndef __ASM_DOMAIN_H__ #define __ASM_DOMAIN_H__ +#include #include +#include struct trap_bounce { unsigned long error_code; diff --git a/xen/include/asm-x86/fixmap.h b/xen/include/asm-x86/fixmap.h index e123cb791a..d2d8ef183e 100644 --- a/xen/include/asm-x86/fixmap.h +++ b/xen/include/asm-x86/fixmap.h @@ -13,6 +13,7 @@ #define _ASM_FIXMAP_H #include +#include #include #include #include @@ -52,6 +53,36 @@ extern void __set_fixmap( #define set_fixmap_nocache(idx, phys) \ __set_fixmap(idx, phys, PAGE_HYPERVISOR_NOCACHE) -#define fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) +#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) +#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT) + +extern void __this_fixmap_does_not_exist(void); + +/* + * 'index to address' translation. If anyone tries to use the idx + * directly without translation, we catch the bug with a NULL-deference + * kernel oops. Illegal ranges of incoming indices are caught too. + */ +static always_inline unsigned long fix_to_virt(const unsigned int idx) +{ + /* + * This branch gets completely eliminated after inlining, except when + * someone tries to use fixaddr indices in an illegal way (such as mixing + * up address types or using out-of-range indices). + * + * If it doesn't get removed, the linker will complain loudly with a + * reasonably clear error message. + */ + if (idx >= __end_of_fixed_addresses) + __this_fixmap_does_not_exist(); + + return __fix_to_virt(idx); +} + +static inline unsigned long virt_to_fix(const unsigned long vaddr) +{ + BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START); + return __virt_to_fix(vaddr); +} #endif diff --git a/xen/include/asm-x86/io_apic.h b/xen/include/asm-x86/io_apic.h index 1cc4e557a6..5c71c08f58 100644 --- a/xen/include/asm-x86/io_apic.h +++ b/xen/include/asm-x86/io_apic.h @@ -2,7 +2,8 @@ #define __ASM_IO_APIC_H #include -#include +#include +#include #include /* @@ -13,42 +14,91 @@ #ifdef CONFIG_X86_IO_APIC -#define APIC_MISMATCH_DEBUG +#ifdef CONFIG_PCI_MSI +static inline int use_pci_vector(void) {return 1;} +static inline void disable_edge_ioapic_vector(unsigned int vector) { } +static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { } +static inline void end_edge_ioapic_vector (unsigned int vector) { } +#define startup_level_ioapic startup_level_ioapic_vector +#define shutdown_level_ioapic mask_IO_APIC_vector +#define enable_level_ioapic unmask_IO_APIC_vector +#define disable_level_ioapic mask_IO_APIC_vector +#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector +#define end_level_ioapic end_level_ioapic_vector +#define set_ioapic_affinity set_ioapic_affinity_vector + +#define startup_edge_ioapic startup_edge_ioapic_vector +#define shutdown_edge_ioapic disable_edge_ioapic_vector +#define enable_edge_ioapic unmask_IO_APIC_vector +#define disable_edge_ioapic disable_edge_ioapic_vector +#define ack_edge_ioapic ack_edge_ioapic_vector +#define end_edge_ioapic end_edge_ioapic_vector +#else +static inline int use_pci_vector(void) {return 0;} +static inline void disable_edge_ioapic_irq(unsigned int irq) { } +static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { } +static inline void end_edge_ioapic_irq (unsigned int irq) { } +#define startup_level_ioapic startup_level_ioapic_irq +#define shutdown_level_ioapic mask_IO_APIC_irq +#define enable_level_ioapic unmask_IO_APIC_irq +#define disable_level_ioapic mask_IO_APIC_irq +#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq +#define end_level_ioapic end_level_ioapic_irq +#define set_ioapic_affinity set_ioapic_affinity_irq + +#define startup_edge_ioapic startup_edge_ioapic_irq +#define shutdown_edge_ioapic disable_edge_ioapic_irq +#define enable_edge_ioapic unmask_IO_APIC_irq +#define disable_edge_ioapic disable_edge_ioapic_irq +#define ack_edge_ioapic ack_edge_ioapic_irq +#define end_edge_ioapic end_edge_ioapic_irq +#endif #define IO_APIC_BASE(idx) \ - ((volatile int *)(fix_to_virt(FIX_IO_APIC_BASE_0 + idx) \ + ((volatile int *)(__fix_to_virt(FIX_IO_APIC_BASE_0 + idx) \ + (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK))) /* * The structure of the IO-APIC: */ -struct IO_APIC_reg_00 { - __u32 __reserved_2 : 14, - LTS : 1, - delivery_type : 1, - __reserved_1 : 8, - ID : 4, - __reserved_0 : 4; -} __attribute__ ((packed)); +union IO_APIC_reg_00 { + u32 raw; + struct { + u32 __reserved_2 : 14, + LTS : 1, + delivery_type : 1, + __reserved_1 : 8, + ID : 8; + } __attribute__ ((packed)) bits; +}; -struct IO_APIC_reg_01 { - __u32 version : 8, - __reserved_2 : 7, - PRQ : 1, - entries : 8, - __reserved_1 : 8; -} __attribute__ ((packed)); +union IO_APIC_reg_01 { + u32 raw; + struct { + u32 version : 8, + __reserved_2 : 7, + PRQ : 1, + entries : 8, + __reserved_1 : 8; + } __attribute__ ((packed)) bits; +}; -struct IO_APIC_reg_02 { - __u32 __reserved_2 : 24, - arbitration : 4, - __reserved_1 : 4; -} __attribute__ ((packed)); +union IO_APIC_reg_02 { + u32 raw; + struct { + u32 __reserved_2 : 24, + arbitration : 4, + __reserved_1 : 4; + } __attribute__ ((packed)) bits; +}; -struct IO_APIC_reg_03 { - __u32 boot_DT : 1, - __reserved_1 : 31; -} __attribute__ ((packed)); +union IO_APIC_reg_03 { + u32 raw; + struct { + u32 boot_DT : 1, + __reserved_1 : 31; + } __attribute__ ((packed)) bits; +}; /* * # of IO-APICs and # of IRQ routing registers @@ -106,7 +156,7 @@ extern struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS]; extern int mp_irq_entries; /* MP IRQ source entries */ -extern struct mpc_config_intsrc *mp_irqs; +extern struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES]; /* non-0 if default (table-less) MP configuration */ extern int mpc_default_type; @@ -124,47 +174,41 @@ static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned i } /* - * Synchronize the IO-APIC and the CPU by doing - * a dummy read from the IO-APIC + * Re-write a value: to be used for read-modify-write + * cycles where the read already set up the index register. + * + * Older SiS APIC requires we rewrite the index regiser */ -static inline void io_apic_sync(unsigned int apic) +#define sis_apic_bug 0 /* This may need propagating from domain0. */ +static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value) { - (void) *(IO_APIC_BASE(apic)+4); + if (sis_apic_bug) + *IO_APIC_BASE(apic) = reg; + *(IO_APIC_BASE(apic)+4) = value; } +/* 1 if "noapic" boot option passed */ +extern int skip_ioapic_setup; + /* * If we use the IO-APIC for IRQ routing, disable automatic * assignment of PCI IRQ's. */ -#define io_apic_assign_pci_irqs (mp_irq_entries && !skip_ioapic_setup) +#define io_apic_assign_pci_irqs (mp_irq_entries && !skip_ioapic_setup && io_apic_irqs) #ifdef CONFIG_ACPI_BOOT extern int io_apic_get_unique_id (int ioapic, int apic_id); extern int io_apic_get_version (int ioapic); extern int io_apic_get_redir_entries (int ioapic); extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int active_high_low); +#endif /*CONFIG_ACPI_BOOT*/ + +extern int (*ioapic_renumber_irq)(int ioapic, int irq); + +#else /* !CONFIG_X86_IO_APIC */ +#define io_apic_assign_pci_irqs 0 #endif -extern int skip_ioapic_setup; /* 1 for "noapic" */ - -static inline void disable_ioapic_setup(void) -{ - skip_ioapic_setup = 1; -} - -static inline int ioapic_setup_disabled(void) -{ - return skip_ioapic_setup; -} - extern int assign_irq_vector(int irq); -#else /* !CONFIG_X86_IO_APIC */ -#define io_apic_assign_pci_irqs 0 - -static inline void disable_ioapic_setup(void) -{ } - -#endif /* !CONFIG_X86_IO_APIC */ - #endif diff --git a/xen/include/asm-x86/io_ports.h b/xen/include/asm-x86/io_ports.h deleted file mode 100644 index db490bd142..0000000000 --- a/xen/include/asm-x86/io_ports.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * based on linux-2.6.10/include/asm-i386/mach-default/io_ports.h - * - * Machine specific IO port address definition for generic. - * Written by Osamu Tomita - */ -#ifndef _MACH_IO_PORTS_H -#define _MACH_IO_PORTS_H - -/* i8253A PIT registers */ -#define PIT_MODE 0x43 -#define PIT_CH0 0x40 -#define PIT_CH2 0x42 - -/* i8259A PIC registers */ -#define PIC_MASTER_CMD 0x20 -#define PIC_MASTER_IMR 0x21 -#define PIC_MASTER_ISR PIC_MASTER_CMD -#define PIC_MASTER_POLL PIC_MASTER_ISR -#define PIC_MASTER_OCW3 PIC_MASTER_ISR -#define PIC_SLAVE_CMD 0xa0 -#define PIC_SLAVE_IMR 0xa1 - -/* i8259A PIC related value */ -#define PIC_CASCADE_IR 2 -#define MASTER_ICW4_DEFAULT 0x01 -#define SLAVE_ICW4_DEFAULT 0x01 -#define PIC_ICW4_AEOI 2 - -#endif /* !_MACH_IO_PORTS_H */ diff --git a/xen/include/asm-x86/irq.h b/xen/include/asm-x86/irq.h index bc7ecfa317..1a38b524a6 100644 --- a/xen/include/asm-x86/irq.h +++ b/xen/include/asm-x86/irq.h @@ -6,59 +6,19 @@ #include #include #include +#include extern void disable_irq(unsigned int); extern void disable_irq_nosync(unsigned int); extern void enable_irq(unsigned int); -/* - * IDT vectors usable for external interrupt sources start - * at 0x20: - */ -#define FIRST_EXTERNAL_VECTOR 0x30 - -#define NR_IRQS (256 - FIRST_EXTERNAL_VECTOR) - -#define HYPERCALL_VECTOR 0x82 - -/* - * Vectors 0x30-0x3f are used for ISA interrupts. - */ - -/* - * Special IRQ vectors used by the SMP architecture, 0xf0-0xff - */ -#define SPURIOUS_APIC_VECTOR 0xff -#define ERROR_APIC_VECTOR 0xfe -#define INVALIDATE_TLB_VECTOR 0xfd -#define EVENT_CHECK_VECTOR 0xfc -#define CALL_FUNCTION_VECTOR 0xfb -#define KDB_VECTOR 0xfa - -/* - * Local APIC timer IRQ vector is on a different priority level, - * to work around the 'lost local interrupt if more than 2 IRQ - * sources per level' errata. - */ -#define LOCAL_TIMER_VECTOR 0xef - -/* - * First APIC vector available to drivers: (vectors 0x40-0xee) - * we start at 0x41 to spread out vectors evenly between priority - * levels. (0x82 is the hypercall vector) - */ -#define FIRST_DEVICE_VECTOR 0x41 -#define FIRST_SYSTEM_VECTOR 0xef - -extern int irq_vector[NR_IRQS]; +extern u8 irq_vector[NR_IRQ_VECTORS]; #define IO_APIC_VECTOR(irq) irq_vector[irq] +#define AUTO_ASSIGN -1 -/* - * Various low-level irq details needed by irq.c, process.c, - * time.c, io_apic.c and smp.c - * - * Interrupt entry/exit code at both C and assembly level - */ +extern void (*interrupt[NR_IRQS])(void); + +#define platform_legacy_irq(irq) ((irq) < 16) extern void mask_irq(unsigned int irq); extern void unmask_irq(unsigned int irq); diff --git a/xen/include/asm-x86/mach-default/apm.h b/xen/include/asm-x86/mach-default/apm.h new file mode 100644 index 0000000000..1f730b8bd1 --- /dev/null +++ b/xen/include/asm-x86/mach-default/apm.h @@ -0,0 +1,75 @@ +/* + * include/asm-i386/mach-default/apm.h + * + * Machine specific APM BIOS functions for generic. + * Split out from apm.c by Osamu Tomita + */ + +#ifndef _ASM_APM_H +#define _ASM_APM_H + +#ifdef APM_ZERO_SEGS +# define APM_DO_ZERO_SEGS \ + "pushl %%ds\n\t" \ + "pushl %%es\n\t" \ + "xorl %%edx, %%edx\n\t" \ + "mov %%dx, %%ds\n\t" \ + "mov %%dx, %%es\n\t" \ + "mov %%dx, %%fs\n\t" \ + "mov %%dx, %%gs\n\t" +# define APM_DO_POP_SEGS \ + "popl %%es\n\t" \ + "popl %%ds\n\t" +#else +# define APM_DO_ZERO_SEGS +# define APM_DO_POP_SEGS +#endif + +static inline void apm_bios_call_asm(u32 func, u32 ebx_in, u32 ecx_in, + u32 *eax, u32 *ebx, u32 *ecx, + u32 *edx, u32 *esi) +{ + /* + * N.B. We do NOT need a cld after the BIOS call + * because we always save and restore the flags. + */ + __asm__ __volatile__(APM_DO_ZERO_SEGS + "pushl %%edi\n\t" + "pushl %%ebp\n\t" + "lcall *%%cs:apm_bios_entry\n\t" + "setc %%al\n\t" + "popl %%ebp\n\t" + "popl %%edi\n\t" + APM_DO_POP_SEGS + : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx), + "=S" (*esi) + : "a" (func), "b" (ebx_in), "c" (ecx_in) + : "memory", "cc"); +} + +static inline u8 apm_bios_call_simple_asm(u32 func, u32 ebx_in, + u32 ecx_in, u32 *eax) +{ + int cx, dx, si; + u8 error; + + /* + * N.B. We do NOT need a cld after the BIOS call + * because we always save and restore the flags. + */ + __asm__ __volatile__(APM_DO_ZERO_SEGS + "pushl %%edi\n\t" + "pushl %%ebp\n\t" + "lcall *%%cs:apm_bios_entry\n\t" + "setc %%bl\n\t" + "popl %%ebp\n\t" + "popl %%edi\n\t" + APM_DO_POP_SEGS + : "=a" (*eax), "=b" (error), "=c" (cx), "=d" (dx), + "=S" (si) + : "a" (func), "b" (ebx_in), "c" (ecx_in) + : "memory", "cc"); + return error; +} + +#endif /* _ASM_APM_H */ diff --git a/xen/include/asm-x86/mach-default/bios_ebda.h b/xen/include/asm-x86/mach-default/bios_ebda.h new file mode 100644 index 0000000000..9cbd9a668a --- /dev/null +++ b/xen/include/asm-x86/mach-default/bios_ebda.h @@ -0,0 +1,15 @@ +#ifndef _MACH_BIOS_EBDA_H +#define _MACH_BIOS_EBDA_H + +/* + * there is a real-mode segmented pointer pointing to the + * 4K EBDA area at 0x40E. + */ +static inline unsigned int get_bios_ebda(void) +{ + unsigned int address = *(unsigned short *)phys_to_virt(0x40E); + address <<= 4; + return address; /* 0 means none */ +} + +#endif /* _MACH_BIOS_EBDA_H */ diff --git a/xen/include/asm-x86/mach-default/do_timer.h b/xen/include/asm-x86/mach-default/do_timer.h new file mode 100644 index 0000000000..03dd13a48a --- /dev/null +++ b/xen/include/asm-x86/mach-default/do_timer.h @@ -0,0 +1,85 @@ +/* defines for inline arch setup functions */ + +#include + +/** + * do_timer_interrupt_hook - hook into timer tick + * @regs: standard registers from interrupt + * + * Description: + * This hook is called immediately after the timer interrupt is ack'd. + * It's primary purpose is to allow architectures that don't possess + * individual per CPU clocks (like the CPU APICs supply) to broadcast the + * timer interrupt as a means of triggering reschedules etc. + **/ + +static inline void do_timer_interrupt_hook(struct pt_regs *regs) +{ + do_timer(regs); +#ifndef CONFIG_SMP + update_process_times(user_mode(regs)); +#endif +/* + * In the SMP case we use the local APIC timer interrupt to do the + * profiling, except when we simulate SMP mode on a uniprocessor + * system, in that case we have to call the local interrupt handler. + */ +#ifndef CONFIG_X86_LOCAL_APIC + profile_tick(CPU_PROFILING, regs); +#else + if (!using_apic_timer) + smp_local_timer_interrupt(regs); +#endif +} + + +/* you can safely undefine this if you don't have the Neptune chipset */ + +#define BUGGY_NEPTUN_TIMER + +/** + * do_timer_overflow - process a detected timer overflow condition + * @count: hardware timer interrupt count on overflow + * + * Description: + * This call is invoked when the jiffies count has not incremented but + * the hardware timer interrupt has. It means that a timer tick interrupt + * came along while the previous one was pending, thus a tick was missed + **/ +static inline int do_timer_overflow(int count) +{ + int i; + + spin_lock(&i8259A_lock); + /* + * This is tricky when I/O APICs are used; + * see do_timer_interrupt(). + */ + i = inb(0x20); + spin_unlock(&i8259A_lock); + + /* assumption about timer being IRQ0 */ + if (i & 0x01) { + /* + * We cannot detect lost timer interrupts ... + * well, that's why we call them lost, don't we? :) + * [hmm, on the Pentium and Alpha we can ... sort of] + */ + count -= LATCH; + } else { +#ifdef BUGGY_NEPTUN_TIMER + /* + * for the Neptun bug we know that the 'latch' + * command doesn't latch the high and low value + * of the counter atomically. Thus we have to + * substract 256 from the counter + * ... funny, isnt it? :) + */ + + count -= 256; +#else + printk("do_slow_gettimeoffset(): hardware timer problem?\n"); +#endif + } + return count; +} diff --git a/xen/include/asm-x86/mach-default/entry_arch.h b/xen/include/asm-x86/mach-default/entry_arch.h new file mode 100644 index 0000000000..bc861469bd --- /dev/null +++ b/xen/include/asm-x86/mach-default/entry_arch.h @@ -0,0 +1,34 @@ +/* + * This file is designed to contain the BUILD_INTERRUPT specifications for + * all of the extra named interrupt vectors used by the architecture. + * Usually this is the Inter Process Interrupts (IPIs) + */ + +/* + * The following vectors are part of the Linux architecture, there + * is no hardware IRQ pin equivalent for them, they are triggered + * through the ICC by us (IPIs) + */ +#ifdef CONFIG_X86_SMP +BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) +BUILD_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR) +BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) +#endif + +/* + * every pentium local APIC has two 'local interrupts', with a + * soft-definable vector attached to both interrupts, one of + * which is a timer interrupt, the other one is error counter + * overflow. Linux uses the local APIC timer interrupt to get + * a much simpler SMP time architecture: + */ +#ifdef CONFIG_X86_LOCAL_APIC +BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR) +BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) +BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) + +#ifdef CONFIG_X86_MCE_P4THERMAL +BUILD_INTERRUPT(thermal_interrupt,THERMAL_APIC_VECTOR) +#endif + +#endif diff --git a/xen/include/asm-x86/mach-default/io_ports.h b/xen/include/asm-x86/mach-default/io_ports.h new file mode 100644 index 0000000000..a96d9f6604 --- /dev/null +++ b/xen/include/asm-x86/mach-default/io_ports.h @@ -0,0 +1,30 @@ +/* + * arch/i386/mach-generic/io_ports.h + * + * Machine specific IO port address definition for generic. + * Written by Osamu Tomita + */ +#ifndef _MACH_IO_PORTS_H +#define _MACH_IO_PORTS_H + +/* i8253A PIT registers */ +#define PIT_MODE 0x43 +#define PIT_CH0 0x40 +#define PIT_CH2 0x42 + +/* i8259A PIC registers */ +#define PIC_MASTER_CMD 0x20 +#define PIC_MASTER_IMR 0x21 +#define PIC_MASTER_ISR PIC_MASTER_CMD +#define PIC_MASTER_POLL PIC_MASTER_ISR +#define PIC_MASTER_OCW3 PIC_MASTER_ISR +#define PIC_SLAVE_CMD 0xa0 +#define PIC_SLAVE_IMR 0xa1 + +/* i8259A PIC related value */ +#define PIC_CASCADE_IR 2 +#define MASTER_ICW4_DEFAULT 0x01 +#define SLAVE_ICW4_DEFAULT 0x01 +#define PIC_ICW4_AEOI 2 + +#endif /* !_MACH_IO_PORTS_H */ diff --git a/xen/include/asm-x86/mach-default/irq_vectors.h b/xen/include/asm-x86/mach-default/irq_vectors.h new file mode 100644 index 0000000000..de16b5bc9c --- /dev/null +++ b/xen/include/asm-x86/mach-default/irq_vectors.h @@ -0,0 +1,96 @@ +/* + * This file should contain #defines for all of the interrupt vector + * numbers used by this architecture. + * + * In addition, there are some standard defines: + * + * FIRST_EXTERNAL_VECTOR: + * The first free place for external interrupts + * + * SYSCALL_VECTOR: + * The IRQ vector a syscall makes the user to kernel transition + * under. + * + * TIMER_IRQ: + * The IRQ number the timer interrupt comes in at. + * + * NR_IRQS: + * The total number of interrupt vectors (including all the + * architecture specific interrupts) needed. + * + */ +#ifndef _ASM_IRQ_VECTORS_H +#define _ASM_IRQ_VECTORS_H + +/* + * IDT vectors usable for external interrupt sources start + * at 0x20: + */ +#define FIRST_EXTERNAL_VECTOR 0x20 + +#define HYPERCALL_VECTOR 0x82 + +/* + * Vectors 0x20-0x2f are used for ISA interrupts. + */ + +/* + * Special IRQ vectors used by the SMP architecture, 0xf0-0xff + * + * some of the following vectors are 'rare', they are merged + * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. + * TLB, reschedule and local APIC vectors are performance-critical. + * + * Vectors 0xf0-0xfa are free (reserved for future Linux use). + */ +#define SPURIOUS_APIC_VECTOR 0xff +#define ERROR_APIC_VECTOR 0xfe +#define INVALIDATE_TLB_VECTOR 0xfd +#define EVENT_CHECK_VECTOR 0xfc +#define CALL_FUNCTION_VECTOR 0xfb + +#define THERMAL_APIC_VECTOR 0xf0 +/* + * Local APIC timer IRQ vector is on a different priority level, + * to work around the 'lost local interrupt if more than 2 IRQ + * sources per level' errata. + */ +#define LOCAL_TIMER_VECTOR 0xef + +/* + * First APIC vector available to drivers: (vectors 0x30-0xee) + * we start at 0x31 to spread out vectors evenly between priority + * levels. (0x80 is the syscall vector) + */ +#define FIRST_DEVICE_VECTOR 0x31 +#define FIRST_SYSTEM_VECTOR 0xef + +#define TIMER_IRQ 0 + +/* + * 16 8259A IRQ's, 208 potential APIC interrupt sources. + * Right now the APIC is mostly only used for SMP. + * 256 vectors is an architectural limit. (we can have + * more than 256 devices theoretically, but they will + * have to use shared interrupts) + * Since vectors 0x00-0x1f are used/reserved for the CPU, + * the usable vector space is 0x20-0xff (224 vectors) + */ + +/* + * The maximum number of vectors supported by i386 processors + * is limited to 256. For processors other than i386, NR_VECTORS + * should be changed accordingly. + */ +#define NR_VECTORS 256 + +#include "irq_vectors_limits.h" + +#define FPU_IRQ 13 + +#define FIRST_VM86_IRQ 3 +#define LAST_VM86_IRQ 15 +#define invalid_vm86_irq(irq) ((irq) < 3 || (irq) > 15) + + +#endif /* _ASM_IRQ_VECTORS_H */ diff --git a/xen/include/asm-x86/mach-default/irq_vectors_limits.h b/xen/include/asm-x86/mach-default/irq_vectors_limits.h new file mode 100644 index 0000000000..b330026e6f --- /dev/null +++ b/xen/include/asm-x86/mach-default/irq_vectors_limits.h @@ -0,0 +1,21 @@ +#ifndef _ASM_IRQ_VECTORS_LIMITS_H +#define _ASM_IRQ_VECTORS_LIMITS_H + +#ifdef CONFIG_PCI_MSI +#define NR_IRQS FIRST_SYSTEM_VECTOR +#define NR_IRQ_VECTORS NR_IRQS +#else +#ifdef CONFIG_X86_IO_APIC +#define NR_IRQS 224 +# if (224 >= 32 * NR_CPUS) +# define NR_IRQ_VECTORS NR_IRQS +# else +# define NR_IRQ_VECTORS (32 * NR_CPUS) +# endif +#else +#define NR_IRQS 16 +#define NR_IRQ_VECTORS NR_IRQS +#endif +#endif + +#endif /* _ASM_IRQ_VECTORS_LIMITS_H */ diff --git a/xen/include/asm-x86/mach-default/mach_apic.h b/xen/include/asm-x86/mach-default/mach_apic.h new file mode 100644 index 0000000000..4bf3c5ae34 --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_apic.h @@ -0,0 +1,133 @@ +#ifndef __ASM_MACH_APIC_H +#define __ASM_MACH_APIC_H + +#include +#include + +#define APIC_DFR_VALUE (APIC_DFR_FLAT) + +static inline cpumask_t target_cpus(void) +{ +#ifdef CONFIG_SMP + return cpu_online_map; +#else + return cpumask_of_cpu(0); +#endif +} +#define TARGET_CPUS (target_cpus()) + +#define NO_BALANCE_IRQ (0) +#define esr_disable (0) + +#define NO_IOAPIC_CHECK (0) + +#define INT_DELIVERY_MODE dest_LowestPrio +#define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */ + +static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid) +{ + return physid_isset(apicid, bitmap); +} + +static inline unsigned long check_apicid_present(int bit) +{ + return physid_isset(bit, phys_cpu_present_map); +} + +/* + * Set up the logical destination ID. + * + * Intel recommends to set DFR, LDR and TPR before enabling + * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel + * document number 292116). So here it goes... + */ +static inline void init_apic_ldr(void) +{ + unsigned long val; + + apic_write_around(APIC_DFR, APIC_DFR_VALUE); + val = apic_read(APIC_LDR) & ~APIC_LDR_MASK; + val |= SET_APIC_LOGICAL_ID(1UL << smp_processor_id()); + apic_write_around(APIC_LDR, val); +} + +static inline physid_mask_t ioapic_phys_id_map(physid_mask_t phys_map) +{ + return phys_map; +} + +static inline void clustered_apic_check(void) +{ + printk("Enabling APIC mode: %s. Using %d I/O APICs\n", + "Flat", nr_ioapics); +} + +static inline int multi_timer_check(int apic, int irq) +{ + return 0; +} + +static inline int apicid_to_node(int logical_apicid) +{ + return 0; +} + +/* Mapping from cpu number to logical apicid */ +static inline int cpu_to_logical_apicid(int cpu) +{ + return 1 << cpu; +} + +static inline int cpu_present_to_apicid(int mps_cpu) +{ + if (mps_cpu < get_physical_broadcast()) + return mps_cpu; + else + return BAD_APICID; +} + +static inline physid_mask_t apicid_to_cpu_present(int phys_apicid) +{ + return physid_mask_of_physid(phys_apicid); +} + +static inline int mpc_apic_id(struct mpc_config_processor *m, + struct mpc_config_translation *translation_record) +{ + printk("Processor #%d %d:%d APIC version %d\n", + m->mpc_apicid, + (m->mpc_cpufeature & CPU_FAMILY_MASK) >> 8, + (m->mpc_cpufeature & CPU_MODEL_MASK) >> 4, + m->mpc_apicver); + return (m->mpc_apicid); +} + +static inline void setup_portio_remap(void) +{ +} + +static inline int check_phys_apicid_present(int boot_cpu_physical_apicid) +{ + return physid_isset(boot_cpu_physical_apicid, phys_cpu_present_map); +} + +static inline int apic_id_registered(void) +{ + return physid_isset(GET_APIC_ID(apic_read(APIC_ID)), phys_cpu_present_map); +} + +static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) +{ + return cpus_addr(cpumask)[0]; +} + +static inline void enable_apic_mode(void) +{ +} + +static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb) +{ + return cpuid_apic >> index_msb; +} + +#endif /* __ASM_MACH_APIC_H */ diff --git a/xen/include/asm-x86/mach-default/mach_apicdef.h b/xen/include/asm-x86/mach-default/mach_apicdef.h new file mode 100644 index 0000000000..7bcb350c3e --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_apicdef.h @@ -0,0 +1,13 @@ +#ifndef __ASM_MACH_APICDEF_H +#define __ASM_MACH_APICDEF_H + +#define APIC_ID_MASK (0xF<<24) + +static inline unsigned get_apic_id(unsigned long x) +{ + return (((x)>>24)&0xF); +} + +#define GET_APIC_ID(x) get_apic_id(x) + +#endif diff --git a/xen/include/asm-x86/mach-default/mach_ipi.h b/xen/include/asm-x86/mach-default/mach_ipi.h new file mode 100644 index 0000000000..6f2b17a200 --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_ipi.h @@ -0,0 +1,30 @@ +#ifndef __ASM_MACH_IPI_H +#define __ASM_MACH_IPI_H + +void send_IPI_mask_bitmask(cpumask_t mask, int vector); +void __send_IPI_shortcut(unsigned int shortcut, int vector); + +static inline void send_IPI_mask(cpumask_t mask, int vector) +{ + send_IPI_mask_bitmask(mask, vector); +} + +static inline void send_IPI_allbutself(int vector) +{ + /* + * if there are no other CPUs in the system then we get an APIC send + * error if we try to broadcast, thus avoid sending IPIs in this case. + */ + if (!(num_online_cpus() > 1)) + return; + + __send_IPI_shortcut(APIC_DEST_ALLBUT, vector); + return; +} + +static inline void send_IPI_all(int vector) +{ + __send_IPI_shortcut(APIC_DEST_ALLINC, vector); +} + +#endif /* __ASM_MACH_IPI_H */ diff --git a/xen/include/asm-x86/mach-default/mach_mpparse.h b/xen/include/asm-x86/mach-default/mach_mpparse.h new file mode 100644 index 0000000000..1d38324825 --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_mpparse.h @@ -0,0 +1,28 @@ +#ifndef __ASM_MACH_MPPARSE_H +#define __ASM_MACH_MPPARSE_H + +static inline void mpc_oem_bus_info(struct mpc_config_bus *m, char *name, + struct mpc_config_translation *translation) +{ +// Dprintk("Bus #%d is %s\n", m->mpc_busid, name); +} + +static inline void mpc_oem_pci_bus(struct mpc_config_bus *m, + struct mpc_config_translation *translation) +{ +} + +static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, + char *productid) +{ + return 0; +} + +/* Hook from generic ACPI tables.c */ +static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) +{ + return 0; +} + + +#endif /* __ASM_MACH_MPPARSE_H */ diff --git a/xen/include/asm-x86/mach-default/mach_mpspec.h b/xen/include/asm-x86/mach-default/mach_mpspec.h new file mode 100644 index 0000000000..6b5dadcf1d --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_mpspec.h @@ -0,0 +1,8 @@ +#ifndef __ASM_MACH_MPSPEC_H +#define __ASM_MACH_MPSPEC_H + +#define MAX_IRQ_SOURCES 256 + +#define MAX_MP_BUSSES 32 + +#endif /* __ASM_MACH_MPSPEC_H */ diff --git a/xen/include/asm-x86/mach-default/mach_reboot.h b/xen/include/asm-x86/mach-default/mach_reboot.h new file mode 100644 index 0000000000..521e227db6 --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_reboot.h @@ -0,0 +1,30 @@ +/* + * arch/i386/mach-generic/mach_reboot.h + * + * Machine specific reboot functions for generic. + * Split out from reboot.c by Osamu Tomita + */ +#ifndef _MACH_REBOOT_H +#define _MACH_REBOOT_H + +static inline void kb_wait(void) +{ + int i; + + for (i = 0; i < 0x10000; i++) + if ((inb_p(0x64) & 0x02) == 0) + break; +} + +static inline void mach_reboot(void) +{ + int i; + for (i = 0; i < 100; i++) { + kb_wait(); + udelay(50); + outb(0xfe, 0x64); /* pulse reset low */ + udelay(50); + } +} + +#endif /* !_MACH_REBOOT_H */ diff --git a/xen/include/asm-x86/mach-default/mach_time.h b/xen/include/asm-x86/mach-default/mach_time.h new file mode 100644 index 0000000000..b749aa44a8 --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_time.h @@ -0,0 +1,122 @@ +/* + * include/asm-i386/mach-default/mach_time.h + * + * Machine specific set RTC function for generic. + * Split out from time.c by Osamu Tomita + */ +#ifndef _MACH_TIME_H +#define _MACH_TIME_H + +#include + +/* for check timing call set_rtc_mmss() 500ms */ +/* used in arch/i386/time.c::do_timer_interrupt() */ +#define USEC_AFTER 500000 +#define USEC_BEFORE 500000 + +/* + * In order to set the CMOS clock precisely, set_rtc_mmss has to be + * called 500 ms after the second nowtime has started, because when + * nowtime is written into the registers of the CMOS clock, it will + * jump to the next second precisely 500 ms later. Check the Motorola + * MC146818A or Dallas DS12887 data sheet for details. + * + * BUG: This routine does not handle hour overflow properly; it just + * sets the minutes. Usually you'll only notice that after reboot! + */ +static inline int mach_set_rtc_mmss(unsigned long nowtime) +{ + int retval = 0; + int real_seconds, real_minutes, cmos_minutes; + unsigned char save_control, save_freq_select; + + save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ + CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); + + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + + cmos_minutes = CMOS_READ(RTC_MINUTES); + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + BCD_TO_BIN(cmos_minutes); + + /* + * since we're only adjusting minutes and seconds, + * don't interfere with hour overflow. This avoids + * messing with unknown time zones but requires your + * RTC not to be off by more than 15 minutes + */ + real_seconds = nowtime % 60; + real_minutes = nowtime / 60; + if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) + real_minutes += 30; /* correct for half hour time zone */ + real_minutes %= 60; + + if (abs(real_minutes - cmos_minutes) < 30) { + if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { + BIN_TO_BCD(real_seconds); + BIN_TO_BCD(real_minutes); + } + CMOS_WRITE(real_seconds,RTC_SECONDS); + CMOS_WRITE(real_minutes,RTC_MINUTES); + } else { + printk(KERN_WARNING + "set_rtc_mmss: can't update from %d to %d\n", + cmos_minutes, real_minutes); + retval = -1; + } + + /* The following flags have to be released exactly in this order, + * otherwise the DS12887 (popular MC146818A clone with integrated + * battery and quartz) will not reset the oscillator and will not + * update precisely 500 ms later. You won't find this mentioned in + * the Dallas Semiconductor data sheets, but who believes data + * sheets anyway ... -- Markus Kuhn + */ + CMOS_WRITE(save_control, RTC_CONTROL); + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); + + return retval; +} + +static inline unsigned long mach_get_cmos_time(void) +{ + unsigned int year, mon, day, hour, min, sec; + int i; + + /* The Linux interpretation of the CMOS clock register contents: + * When the Update-In-Progress (UIP) flag goes from 1 to 0, the + * RTC registers show the second which has precisely just started. + * Let's hope other operating systems interpret the RTC the same way. + */ + /* read RTC exactly on falling edge of update flag */ + for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */ + if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) + break; + for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms */ + if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) + break; + do { /* Isn't this overkill ? UIP above should guarantee consistency */ + sec = CMOS_READ(RTC_SECONDS); + min = CMOS_READ(RTC_MINUTES); + hour = CMOS_READ(RTC_HOURS); + day = CMOS_READ(RTC_DAY_OF_MONTH); + mon = CMOS_READ(RTC_MONTH); + year = CMOS_READ(RTC_YEAR); + } while (sec != CMOS_READ(RTC_SECONDS)); + if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + { + BCD_TO_BIN(sec); + BCD_TO_BIN(min); + BCD_TO_BIN(hour); + BCD_TO_BIN(day); + BCD_TO_BIN(mon); + BCD_TO_BIN(year); + } + if ((year += 1900) < 1970) + year += 100; + + return mktime(year, mon, day, hour, min, sec); +} + +#endif /* !_MACH_TIME_H */ diff --git a/xen/include/asm-x86/mach-default/mach_timer.h b/xen/include/asm-x86/mach-default/mach_timer.h new file mode 100644 index 0000000000..4b9703bb02 --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_timer.h @@ -0,0 +1,48 @@ +/* + * include/asm-i386/mach-default/mach_timer.h + * + * Machine specific calibrate_tsc() for generic. + * Split out from timer_tsc.c by Osamu Tomita + */ +/* ------ Calibrate the TSC ------- + * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset(). + * Too much 64-bit arithmetic here to do this cleanly in C, and for + * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2) + * output busy loop as low as possible. We avoid reading the CTC registers + * directly because of the awkward 8-bit access mechanism of the 82C54 + * device. + */ +#ifndef _MACH_TIMER_H +#define _MACH_TIMER_H + +#define CALIBRATE_LATCH (5 * LATCH) + +static inline void mach_prepare_counter(void) +{ + /* Set the Gate high, disable speaker */ + outb((inb(0x61) & ~0x02) | 0x01, 0x61); + + /* + * Now let's take care of CTC channel 2 + * + * Set the Gate high, program CTC channel 2 for mode 0, + * (interrupt on terminal count mode), binary count, + * load 5 * LATCH count, (LSB and MSB) to begin countdown. + * + * Some devices need a delay here. + */ + outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */ + outb_p(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */ + outb_p(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */ +} + +static inline void mach_countup(unsigned long *count_p) +{ + unsigned long count = 0; + do { + count++; + } while ((inb_p(0x61) & 0x20) == 0); + *count_p = count; +} + +#endif /* !_MACH_TIMER_H */ diff --git a/xen/include/asm-x86/mach-default/mach_traps.h b/xen/include/asm-x86/mach-default/mach_traps.h new file mode 100644 index 0000000000..c98c2880c5 --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_traps.h @@ -0,0 +1,29 @@ +/* + * include/asm-i386/mach-default/mach_traps.h + * + * Machine specific NMI handling for generic. + * Split out from traps.c by Osamu Tomita + */ +#ifndef _MACH_TRAPS_H +#define _MACH_TRAPS_H + +static inline void clear_mem_error(unsigned char reason) +{ + reason = (reason & 0xf) | 4; + outb(reason, 0x61); +} + +static inline unsigned char get_nmi_reason(void) +{ + return inb(0x61); +} + +static inline void reassert_nmi(void) +{ + outb(0x8f, 0x70); + inb(0x71); /* dummy */ + outb(0x0f, 0x70); + inb(0x71); /* dummy */ +} + +#endif /* !_MACH_TRAPS_H */ diff --git a/xen/include/asm-x86/mach-default/mach_wakecpu.h b/xen/include/asm-x86/mach-default/mach_wakecpu.h new file mode 100644 index 0000000000..673b85c9b2 --- /dev/null +++ b/xen/include/asm-x86/mach-default/mach_wakecpu.h @@ -0,0 +1,41 @@ +#ifndef __ASM_MACH_WAKECPU_H +#define __ASM_MACH_WAKECPU_H + +/* + * This file copes with machines that wakeup secondary CPUs by the + * INIT, INIT, STARTUP sequence. + */ + +#define WAKE_SECONDARY_VIA_INIT + +#define TRAMPOLINE_LOW phys_to_virt(0x467) +#define TRAMPOLINE_HIGH phys_to_virt(0x469) + +#define boot_cpu_apicid boot_cpu_physical_apicid + +static inline void wait_for_init_deassert(atomic_t *deassert) +{ + while (!atomic_read(deassert)); + return; +} + +/* Nothing to do for most platforms, since cleared by the INIT cycle */ +static inline void smp_callin_clear_local_apic(void) +{ +} + +static inline void store_NMI_vector(unsigned short *high, unsigned short *low) +{ +} + +static inline void restore_NMI_vector(unsigned short *high, unsigned short *low) +{ +} + +#if APIC_DEBUG + #define inquire_remote_apic(apicid) __inquire_remote_apic(apicid) +#else + #define inquire_remote_apic(apicid) {} +#endif + +#endif /* __ASM_MACH_WAKECPU_H */ diff --git a/xen/include/asm-x86/mach-default/pci-functions.h b/xen/include/asm-x86/mach-default/pci-functions.h new file mode 100644 index 0000000000..ed0bab4273 --- /dev/null +++ b/xen/include/asm-x86/mach-default/pci-functions.h @@ -0,0 +1,19 @@ +/* + * PCI BIOS function numbering for conventional PCI BIOS + * systems + */ + +#define PCIBIOS_PCI_FUNCTION_ID 0xb1XX +#define PCIBIOS_PCI_BIOS_PRESENT 0xb101 +#define PCIBIOS_FIND_PCI_DEVICE 0xb102 +#define PCIBIOS_FIND_PCI_CLASS_CODE 0xb103 +#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xb106 +#define PCIBIOS_READ_CONFIG_BYTE 0xb108 +#define PCIBIOS_READ_CONFIG_WORD 0xb109 +#define PCIBIOS_READ_CONFIG_DWORD 0xb10a +#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b +#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c +#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d +#define PCIBIOS_GET_ROUTING_OPTIONS 0xb10e +#define PCIBIOS_SET_PCI_HW_INT 0xb10f + diff --git a/xen/include/asm-x86/mach-default/setup_arch_post.h b/xen/include/asm-x86/mach-default/setup_arch_post.h new file mode 100644 index 0000000000..2fc4888721 --- /dev/null +++ b/xen/include/asm-x86/mach-default/setup_arch_post.h @@ -0,0 +1,40 @@ +/** + * machine_specific_memory_setup - Hook for machine specific memory setup. + * + * Description: + * This is included late in kernel/setup.c so that it can make + * use of all of the static functions. + **/ + +static char * __init machine_specific_memory_setup(void) +{ + char *who; + + + who = "BIOS-e820"; + + /* + * Try to copy the BIOS-supplied E820-map. + * + * Otherwise fake a memory map; one section from 0k->640k, + * the next section from 1mb->appropriate_mem_k + */ + sanitize_e820_map(E820_MAP, &E820_MAP_NR); + if (copy_e820_map(E820_MAP, E820_MAP_NR) < 0) { + unsigned long mem_size; + + /* compare results from other methods and take the greater */ + if (ALT_MEM_K < EXT_MEM_K) { + mem_size = EXT_MEM_K; + who = "BIOS-88"; + } else { + mem_size = ALT_MEM_K; + who = "BIOS-e801"; + } + + e820.nr_map = 0; + add_memory_region(0, LOWMEMSIZE(), E820_RAM); + add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); + } + return who; +} diff --git a/xen/include/asm-x86/mach-default/setup_arch_pre.h b/xen/include/asm-x86/mach-default/setup_arch_pre.h new file mode 100644 index 0000000000..fb42099e7b --- /dev/null +++ b/xen/include/asm-x86/mach-default/setup_arch_pre.h @@ -0,0 +1,5 @@ +/* Hook to call BIOS initialisation function */ + +/* no action for generic */ + +#define ARCH_SETUP diff --git a/xen/include/asm-x86/mach-default/smpboot_hooks.h b/xen/include/asm-x86/mach-default/smpboot_hooks.h new file mode 100644 index 0000000000..7f45f63110 --- /dev/null +++ b/xen/include/asm-x86/mach-default/smpboot_hooks.h @@ -0,0 +1,44 @@ +/* two abstractions specific to kernel/smpboot.c, mainly to cater to visws + * which needs to alter them. */ + +static inline void smpboot_clear_io_apic_irqs(void) +{ + io_apic_irqs = 0; +} + +static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) +{ + CMOS_WRITE(0xa, 0xf); + local_flush_tlb(); + Dprintk("1.\n"); + *((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4; + Dprintk("2.\n"); + *((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf; + Dprintk("3.\n"); +} + +static inline void smpboot_restore_warm_reset_vector(void) +{ + /* + * Install writable page 0 entry to set BIOS data area. + */ + local_flush_tlb(); + + /* + * Paranoid: Set warm reset code and vector here back + * to default values. + */ + CMOS_WRITE(0, 0xf); + + *((volatile long *) phys_to_virt(0x467)) = 0; +} + +static inline void smpboot_setup_io_apic(void) +{ + /* + * Here we can be sure that there is an IO-APIC in the system. Let's + * go and set it up: + */ + if (!skip_ioapic_setup && nr_ioapics) + setup_IO_APIC(); +} diff --git a/xen/include/asm-x86/mach_apic.h b/xen/include/asm-x86/mach_apic.h deleted file mode 100644 index e93b0808d5..0000000000 --- a/xen/include/asm-x86/mach_apic.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * based on linux-2.6.10/include/asm-i386/mach-default/mach_apic.h - * - */ -#ifndef __ASM_MACH_APIC_H -#define __ASM_MACH_APIC_H - -#define APIC_DFR_VALUE (APIC_DFR_FLAT) -#define esr_disable (0) - -/* - * Set up the logical destination ID. - * - * Intel recommends to set DFR, LDR and TPR before enabling - * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel - * document number 292116). So here it goes... - */ -static inline void init_apic_ldr(void) -{ - unsigned long val; - - apic_write_around(APIC_DFR, APIC_DFR_VALUE); - val = apic_read(APIC_LDR) & ~APIC_LDR_MASK; - val |= SET_APIC_LOGICAL_ID(1UL << smp_processor_id()); - apic_write_around(APIC_LDR, val); -} - -static inline int apic_id_registered(void) -{ - return test_bit(GET_APIC_ID(apic_read(APIC_ID)), &phys_cpu_present_map); -} -#endif /* __ASM_MACH_APIC_H */ diff --git a/xen/include/asm-x86/mpspec.h b/xen/include/asm-x86/mpspec.h index 1e73671c25..7add527173 100644 --- a/xen/include/asm-x86/mpspec.h +++ b/xen/include/asm-x86/mpspec.h @@ -1,242 +1,84 @@ #ifndef __ASM_MPSPEC_H #define __ASM_MPSPEC_H -#include -#include +#include +#include +#include -/* - * Structure definitions for SMP machines following the - * Intel Multiprocessing Specification 1.1 and 1.4. - */ - -/* - * This tag identifies where the SMP configuration - * information is. - */ - -#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_') - -/* - * a maximum of 16 APICs with the current APIC ID architecture. - * xAPICs can have up to 256. SAPICs have 16 ID bits. - */ -#ifdef CONFIG_X86_CLUSTERED_APIC -#define MAX_APICS 256 -#else -#define MAX_APICS 16 -#endif - -#define MAX_MPC_ENTRY 1024 - -struct intel_mp_floating -{ - char mpf_signature[4]; /* "_MP_" */ - unsigned int mpf_physptr; /* Configuration table address */ - unsigned char mpf_length; /* Our length (paragraphs) */ - unsigned char mpf_specification;/* Specification version */ - unsigned char mpf_checksum; /* Checksum (makes sum 0) */ - unsigned char mpf_feature1; /* Standard or configuration ? */ - unsigned char mpf_feature2; /* Bit7 set for IMCR|PIC */ - unsigned char mpf_feature3; /* Unused (0) */ - unsigned char mpf_feature4; /* Unused (0) */ - unsigned char mpf_feature5; /* Unused (0) */ -}; - -struct mp_config_table -{ - char mpc_signature[4]; -#define MPC_SIGNATURE "PCMP" - unsigned short mpc_length; /* Size of table */ - char mpc_spec; /* 0x01 */ - char mpc_checksum; - char mpc_oem[8]; - char mpc_productid[12]; - unsigned int mpc_oemptr; /* 0 if not present */ - unsigned short mpc_oemsize; /* 0 if not present */ - unsigned short mpc_oemcount; - unsigned int mpc_lapic; /* APIC address */ - unsigned int reserved; -}; - -/* Followed by entries */ - -#define MP_PROCESSOR 0 -#define MP_BUS 1 -#define MP_IOAPIC 2 -#define MP_INTSRC 3 -#define MP_LINTSRC 4 -#define MP_TRANSLATION 192 /* Used by IBM NUMA-Q to describe node locality */ - -struct mpc_config_processor -{ - unsigned char mpc_type; - unsigned char mpc_apicid; /* Local APIC number */ - unsigned char mpc_apicver; /* Its versions */ - unsigned char mpc_cpuflag; -#define CPU_ENABLED 1 /* Processor is available */ -#define CPU_BOOTPROCESSOR 2 /* Processor is the BP */ - unsigned int mpc_cpufeature; -#define CPU_STEPPING_MASK 0x0F -#define CPU_MODEL_MASK 0xF0 -#define CPU_FAMILY_MASK 0xF00 - unsigned int mpc_featureflag; /* CPUID feature value */ - unsigned int mpc_reserved[2]; -}; - -struct mpc_config_bus -{ - unsigned char mpc_type; - unsigned char mpc_busid; - unsigned char mpc_bustype[6] __attribute((packed)); -}; - -/* List of Bus Type string values, Intel MP Spec. */ -#define BUSTYPE_EISA "EISA" -#define BUSTYPE_ISA "ISA" -#define BUSTYPE_INTERN "INTERN" /* Internal BUS */ -#define BUSTYPE_MCA "MCA" -#define BUSTYPE_VL "VL" /* Local bus */ -#define BUSTYPE_PCI "PCI" -#define BUSTYPE_PCMCIA "PCMCIA" -#define BUSTYPE_CBUS "CBUS" -#define BUSTYPE_CBUSII "CBUSII" -#define BUSTYPE_FUTURE "FUTURE" -#define BUSTYPE_MBI "MBI" -#define BUSTYPE_MBII "MBII" -#define BUSTYPE_MPI "MPI" -#define BUSTYPE_MPSA "MPSA" -#define BUSTYPE_NUBUS "NUBUS" -#define BUSTYPE_TC "TC" -#define BUSTYPE_VME "VME" -#define BUSTYPE_XPRESS "XPRESS" - -struct mpc_config_ioapic -{ - unsigned char mpc_type; - unsigned char mpc_apicid; - unsigned char mpc_apicver; - unsigned char mpc_flags; -#define MPC_APIC_USABLE 0x01 - unsigned int mpc_apicaddr; -}; - -struct mpc_config_intsrc -{ - unsigned char mpc_type; - unsigned char mpc_irqtype; - unsigned short mpc_irqflag; - unsigned char mpc_srcbus; - unsigned char mpc_srcbusirq; - unsigned char mpc_dstapic; - unsigned char mpc_dstirq; -}; - -enum mp_irq_source_types { - mp_INT = 0, - mp_NMI = 1, - mp_SMI = 2, - mp_ExtINT = 3 -}; - -#define MP_IRQDIR_DEFAULT 0 -#define MP_IRQDIR_HIGH 1 -#define MP_IRQDIR_LOW 3 - - -struct mpc_config_lintsrc -{ - unsigned char mpc_type; - unsigned char mpc_irqtype; - unsigned short mpc_irqflag; - unsigned char mpc_srcbusid; - unsigned char mpc_srcbusirq; - unsigned char mpc_destapic; -#define MP_APIC_ALL 0xFF - unsigned char mpc_destapiclint; -}; - -struct mp_config_oemtable -{ - char oem_signature[4]; -#define MPC_OEM_SIGNATURE "_OEM" - unsigned short oem_length; /* Size of table */ - char oem_rev; /* 0x01 */ - char oem_checksum; - char mpc_oem[8]; -}; - -struct mpc_config_translation -{ - unsigned char mpc_type; - unsigned char trans_len; - unsigned char trans_type; - unsigned char trans_quad; - unsigned char trans_global; - unsigned char trans_local; - unsigned short trans_reserved; -}; - -/* - * Default configurations - * - * 1 2 CPU ISA 82489DX - * 2 2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining - * 3 2 CPU EISA 82489DX - * 4 2 CPU MCA 82489DX - * 5 2 CPU ISA+PCI - * 6 2 CPU EISA+PCI - * 7 2 CPU MCA+PCI - */ - -#ifdef CONFIG_MULTIQUAD -#define MAX_IRQ_SOURCES 512 -#else /* !CONFIG_MULTIQUAD */ -#define MAX_IRQ_SOURCES 256 -#endif /* CONFIG_MULTIQUAD */ - -#define MAX_MP_BUSSES 32 -enum mp_bustype { - MP_BUS_ISA = 1, - MP_BUS_EISA, - MP_BUS_PCI, - MP_BUS_MCA -}; -extern int *mp_bus_id_to_type; -extern int *mp_bus_id_to_node; -extern int *mp_bus_id_to_local; -extern int *mp_bus_id_to_pci_bus; +extern int mp_bus_id_to_type [MAX_MP_BUSSES]; +extern int mp_bus_id_to_node [MAX_MP_BUSSES]; +extern int mp_bus_id_to_local [MAX_MP_BUSSES]; extern int quad_local_to_mp_bus_id [NR_CPUS/4][4]; +extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES]; extern unsigned int boot_cpu_physical_apicid; -/*extern unsigned long phys_cpu_present_map;*/ extern int smp_found_config; extern void find_smp_config (void); extern void get_smp_config (void); -/*extern int nr_ioapics;*/ +extern int nr_ioapics; extern int apic_version [MAX_APICS]; -/*extern int mp_irq_entries;*/ -/*extern struct mpc_config_intsrc *mp_irqs;*/ -/*extern int mpc_default_type;*/ +extern int mp_bus_id_to_type [MAX_MP_BUSSES]; +extern int mp_irq_entries; +extern struct mpc_config_intsrc mp_irqs [MAX_IRQ_SOURCES]; +extern int mpc_default_type; +extern int mp_bus_id_to_pci_bus [MAX_MP_BUSSES]; extern int mp_current_pci_id; extern unsigned long mp_lapic_addr; -/*extern int pic_mode;*/ +extern int pic_mode; extern int using_apic_timer; #ifdef CONFIG_ACPI_BOOT extern void mp_register_lapic (u8 id, u8 enabled); extern void mp_register_lapic_address (u64 address); - -#ifdef CONFIG_X86_IO_APIC -extern void mp_register_ioapic (u8 id, u32 address, u32 irq_base); -extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 global_irq); +extern void mp_register_ioapic (u8 id, u32 address, u32 gsi_base); +extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity, u8 trigger, u32 gsi); extern void mp_config_acpi_legacy_irqs (void); -extern void mp_config_ioapic_for_sci(int irq); -extern void mp_parse_prt (void); -#else /*!CONFIG_X86_IO_APIC*/ -static inline void mp_config_ioapic_for_sci(int irq) { } -#endif /*!CONFIG_X86_IO_APIC*/ - +extern int mp_register_gsi (u32 gsi, int edge_level, int active_high_low); #endif /*CONFIG_ACPI_BOOT*/ +#define PHYSID_ARRAY_SIZE BITS_TO_LONGS(MAX_APICS) + +struct physid_mask +{ + unsigned long mask[PHYSID_ARRAY_SIZE]; +}; + +typedef struct physid_mask physid_mask_t; + +#define physid_set(physid, map) set_bit(physid, (map).mask) +#define physid_clear(physid, map) clear_bit(physid, (map).mask) +#define physid_isset(physid, map) test_bit(physid, (map).mask) +#define physid_test_and_set(physid, map) test_and_set_bit(physid, (map).mask) + +#define physids_and(dst, src1, src2) bitmap_and((dst).mask, (src1).mask, (src2).mask, MAX_APICS) +#define physids_or(dst, src1, src2) bitmap_or((dst).mask, (src1).mask, (src2).mask, MAX_APICS) +#define physids_clear(map) bitmap_zero((map).mask, MAX_APICS) +#define physids_complement(dst, src) bitmap_complement((dst).mask,(src).mask, MAX_APICS) +#define physids_empty(map) bitmap_empty((map).mask, MAX_APICS) +#define physids_equal(map1, map2) bitmap_equal((map1).mask, (map2).mask, MAX_APICS) +#define physids_weight(map) bitmap_weight((map).mask, MAX_APICS) +#define physids_shift_right(d, s, n) bitmap_shift_right((d).mask, (s).mask, n, MAX_APICS) +#define physids_shift_left(d, s, n) bitmap_shift_left((d).mask, (s).mask, n, MAX_APICS) +#define physids_coerce(map) ((map).mask[0]) + +#define physids_promote(physids) \ + ({ \ + physid_mask_t __physid_mask = PHYSID_MASK_NONE; \ + __physid_mask.mask[0] = physids; \ + __physid_mask; \ + }) + +#define physid_mask_of_physid(physid) \ + ({ \ + physid_mask_t __physid_mask = PHYSID_MASK_NONE; \ + physid_set(physid, __physid_mask); \ + __physid_mask; \ + }) + +#define PHYSID_MASK_ALL { {[0 ... PHYSID_ARRAY_SIZE-1] = ~0UL} } +#define PHYSID_MASK_NONE { {[0 ... PHYSID_ARRAY_SIZE-1] = 0UL} } + +extern physid_mask_t phys_cpu_present_map; + #endif diff --git a/xen/include/asm-x86/mpspec_def.h b/xen/include/asm-x86/mpspec_def.h new file mode 100644 index 0000000000..902c030f7f --- /dev/null +++ b/xen/include/asm-x86/mpspec_def.h @@ -0,0 +1,188 @@ +#ifndef __ASM_MPSPEC_DEF_H +#define __ASM_MPSPEC_DEF_H + +/* + * Structure definitions for SMP machines following the + * Intel Multiprocessing Specification 1.1 and 1.4. + */ + +/* + * This tag identifies where the SMP configuration + * information is. + */ + +#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_') + +#define MAX_MPC_ENTRY 1024 +#define MAX_APICS 256 + +struct intel_mp_floating +{ + char mpf_signature[4]; /* "_MP_" */ + unsigned int mpf_physptr; /* Configuration table address */ + unsigned char mpf_length; /* Our length (paragraphs) */ + unsigned char mpf_specification;/* Specification version */ + unsigned char mpf_checksum; /* Checksum (makes sum 0) */ + unsigned char mpf_feature1; /* Standard or configuration ? */ + unsigned char mpf_feature2; /* Bit7 set for IMCR|PIC */ + unsigned char mpf_feature3; /* Unused (0) */ + unsigned char mpf_feature4; /* Unused (0) */ + unsigned char mpf_feature5; /* Unused (0) */ +}; + +struct mp_config_table +{ + char mpc_signature[4]; +#define MPC_SIGNATURE "PCMP" + unsigned short mpc_length; /* Size of table */ + char mpc_spec; /* 0x01 */ + char mpc_checksum; + char mpc_oem[8]; + char mpc_productid[12]; + unsigned int mpc_oemptr; /* 0 if not present */ + unsigned short mpc_oemsize; /* 0 if not present */ + unsigned short mpc_oemcount; + unsigned int mpc_lapic; /* APIC address */ + unsigned int reserved; +}; + +/* Followed by entries */ + +#define MP_PROCESSOR 0 +#define MP_BUS 1 +#define MP_IOAPIC 2 +#define MP_INTSRC 3 +#define MP_LINTSRC 4 +#define MP_TRANSLATION 192 /* Used by IBM NUMA-Q to describe node locality */ + +struct mpc_config_processor +{ + unsigned char mpc_type; + unsigned char mpc_apicid; /* Local APIC number */ + unsigned char mpc_apicver; /* Its versions */ + unsigned char mpc_cpuflag; +#define CPU_ENABLED 1 /* Processor is available */ +#define CPU_BOOTPROCESSOR 2 /* Processor is the BP */ + unsigned int mpc_cpufeature; +#define CPU_STEPPING_MASK 0x0F +#define CPU_MODEL_MASK 0xF0 +#define CPU_FAMILY_MASK 0xF00 + unsigned int mpc_featureflag; /* CPUID feature value */ + unsigned int mpc_reserved[2]; +}; + +struct mpc_config_bus +{ + unsigned char mpc_type; + unsigned char mpc_busid; + unsigned char mpc_bustype[6] __attribute((packed)); +}; + +/* List of Bus Type string values, Intel MP Spec. */ +#define BUSTYPE_EISA "EISA" +#define BUSTYPE_ISA "ISA" +#define BUSTYPE_INTERN "INTERN" /* Internal BUS */ +#define BUSTYPE_MCA "MCA" +#define BUSTYPE_VL "VL" /* Local bus */ +#define BUSTYPE_PCI "PCI" +#define BUSTYPE_PCMCIA "PCMCIA" +#define BUSTYPE_CBUS "CBUS" +#define BUSTYPE_CBUSII "CBUSII" +#define BUSTYPE_FUTURE "FUTURE" +#define BUSTYPE_MBI "MBI" +#define BUSTYPE_MBII "MBII" +#define BUSTYPE_MPI "MPI" +#define BUSTYPE_MPSA "MPSA" +#define BUSTYPE_NUBUS "NUBUS" +#define BUSTYPE_TC "TC" +#define BUSTYPE_VME "VME" +#define BUSTYPE_XPRESS "XPRESS" +#define BUSTYPE_NEC98 "NEC98" + +struct mpc_config_ioapic +{ + unsigned char mpc_type; + unsigned char mpc_apicid; + unsigned char mpc_apicver; + unsigned char mpc_flags; +#define MPC_APIC_USABLE 0x01 + unsigned int mpc_apicaddr; +}; + +struct mpc_config_intsrc +{ + unsigned char mpc_type; + unsigned char mpc_irqtype; + unsigned short mpc_irqflag; + unsigned char mpc_srcbus; + unsigned char mpc_srcbusirq; + unsigned char mpc_dstapic; + unsigned char mpc_dstirq; +}; + +enum mp_irq_source_types { + mp_INT = 0, + mp_NMI = 1, + mp_SMI = 2, + mp_ExtINT = 3 +}; + +#define MP_IRQDIR_DEFAULT 0 +#define MP_IRQDIR_HIGH 1 +#define MP_IRQDIR_LOW 3 + + +struct mpc_config_lintsrc +{ + unsigned char mpc_type; + unsigned char mpc_irqtype; + unsigned short mpc_irqflag; + unsigned char mpc_srcbusid; + unsigned char mpc_srcbusirq; + unsigned char mpc_destapic; +#define MP_APIC_ALL 0xFF + unsigned char mpc_destapiclint; +}; + +struct mp_config_oemtable +{ + char oem_signature[4]; +#define MPC_OEM_SIGNATURE "_OEM" + unsigned short oem_length; /* Size of table */ + char oem_rev; /* 0x01 */ + char oem_checksum; + char mpc_oem[8]; +}; + +struct mpc_config_translation +{ + unsigned char mpc_type; + unsigned char trans_len; + unsigned char trans_type; + unsigned char trans_quad; + unsigned char trans_global; + unsigned char trans_local; + unsigned short trans_reserved; +}; + +/* + * Default configurations + * + * 1 2 CPU ISA 82489DX + * 2 2 CPU EISA 82489DX neither IRQ 0 timer nor IRQ 13 DMA chaining + * 3 2 CPU EISA 82489DX + * 4 2 CPU MCA 82489DX + * 5 2 CPU ISA+PCI + * 6 2 CPU EISA+PCI + * 7 2 CPU MCA+PCI + */ + +enum mp_bustype { + MP_BUS_ISA = 1, + MP_BUS_EISA, + MP_BUS_PCI, + MP_BUS_MCA, + MP_BUS_NEC98 +}; +#endif + diff --git a/xen/include/asm-x86/page.h b/xen/include/asm-x86/page.h index 59e582e4cd..64b0635ce6 100644 --- a/xen/include/asm-x86/page.h +++ b/xen/include/asm-x86/page.h @@ -131,8 +131,6 @@ static __inline__ int get_order(unsigned long size) return order; } -extern void zap_low_mappings(void); - /* Map physical byte range (@p, @p+@s) at virt address @v in pagetable @pt. */ extern int map_pages( diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index d31b9769b9..8cd4755cba 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -5,16 +5,13 @@ #define __ASM_X86_PROCESSOR_H #ifndef __ASSEMBLY__ -#include +#include +#include +#include +#include #include #include #include -#include -#include -#include -#include -#include -#include #endif /* @@ -166,7 +163,7 @@ struct cpuinfo_x86 { int x86_cache_size; /* in KB - for CPUS that support this call */ int x86_clflush_size; int x86_tlbsize; /* number of 4K pages in DTLB/ITLB combined */ -} __attribute__((__aligned__(SMP_CACHE_BYTES))); +} __cacheline_aligned; /* * capabilities of CPUs @@ -369,7 +366,7 @@ struct tss_struct { u16 bitmap; /* Pads the TSS to be cacheline-aligned (total size is 0x80). */ u8 __cacheline_filler[24]; -} __cacheline_aligned PACKED; +} __cacheline_aligned __attribute__((packed)); #define IDT_ENTRIES 256 extern idt_entry_t idt_table[]; diff --git a/xen/include/asm-x86/smp.h b/xen/include/asm-x86/smp.h index e1e9443035..f8edfd1fca 100644 --- a/xen/include/asm-x86/smp.h +++ b/xen/include/asm-x86/smp.h @@ -1,14 +1,28 @@ #ifndef __ASM_SMP_H #define __ASM_SMP_H +/* + * We need the APIC definitions automatically as part of 'smp.h' + */ #ifndef __ASSEMBLY__ #include -#include -#include -#include -#include +#include +#include #endif +#ifdef CONFIG_X86_LOCAL_APIC +#ifndef __ASSEMBLY__ +#include +#include +#include +#ifdef CONFIG_X86_IO_APIC +#include +#endif +#include +#endif +#endif + +#define BAD_APICID 0xFFu #ifdef CONFIG_SMP #ifndef __ASSEMBLY__ @@ -17,79 +31,61 @@ */ extern void smp_alloc_memory(void); -extern unsigned long phys_cpu_present_map; -extern unsigned long cpu_online_map; -extern volatile unsigned long smp_invalidate_needed; extern int pic_mode; extern int smp_num_siblings; -extern int cpu_sibling_map[]; +extern cpumask_t cpu_sibling_map[]; -/* - * On x86 all CPUs are mapped 1:1 to the APIC space. - * This simplifies scheduling and IPI sending and - * compresses data structures. - */ -static inline int cpu_logical_map(int cpu) -{ - return cpu; -} -static inline int cpu_number_map(int cpu) -{ - return cpu; -} +extern void smp_flush_tlb(void); +extern void smp_invalidate_rcv(void); /* Process an NMI */ +extern void (*mtrr_hook) (void); +extern void zap_low_mappings (void); -/* - * Some lowlevel functions might want to know about - * the real APIC ID <-> CPU # mapping. - */ #define MAX_APICID 256 -extern volatile int cpu_to_physical_apicid[NR_CPUS]; -extern volatile int physical_apicid_to_cpu[MAX_APICID]; -extern volatile int cpu_to_logical_apicid[NR_CPUS]; -extern volatile int logical_apicid_to_cpu[MAX_APICID]; - -/* - * General functions that each host system must provide. - */ - -/*extern void smp_boot_cpus(void);*/ -extern void smp_store_cpu_info(int id); /* Store per CPU info (like the initial udelay numbers */ +extern u8 x86_cpu_to_apicid[]; /* * This function is needed by all SMP systems. It must _always_ be valid * from the initial startup. We map APIC_BASE very early in page_setup(), * so this is correct in the x86 case. */ +#define __smp_processor_id() (current->processor) -#define smp_processor_id() (current->processor) +extern cpumask_t cpu_callout_map; +extern cpumask_t cpu_callin_map; +#define cpu_possible_map cpu_callout_map -static __inline int hard_smp_processor_id(void) +/* We don't mark CPUs online until __cpu_up(), so we need another measure */ +static inline int num_booting_cpus(void) +{ + return cpus_weight(cpu_callout_map); +} + +extern void map_cpu_to_logical_apicid(void); +extern void unmap_cpu_to_logical_apicid(int cpu); + +#ifdef CONFIG_X86_LOCAL_APIC + +#ifdef APIC_DEFINITION +extern int hard_smp_processor_id(void); +#else +#include +static inline int hard_smp_processor_id(void) { /* we don't want to mark this access volatile - bad code generation */ - return GET_APIC_ID(*(unsigned *)(APIC_BASE+APIC_ID)); + return GET_APIC_ID(*(unsigned int *)(APIC_BASE+APIC_ID)); } +#endif static __inline int logical_smp_processor_id(void) { /* we don't want to mark this access volatile - bad code generation */ - return GET_APIC_LOGICAL_ID(*(unsigned *)(APIC_BASE+APIC_LDR)); + return GET_APIC_LOGICAL_ID(*(unsigned int *)(APIC_BASE+APIC_LDR)); } +#endif #endif /* !__ASSEMBLY__ */ #define NO_PROC_ID 0xFF /* No processor magic marker */ -/* - * This magic constant controls our willingness to transfer - * a process across CPUs. Such a transfer incurs misses on the L1 - * cache, and on a P6 or P5 with multiple L2 caches L2 hits. My - * gut feeling is this will vary by board in value. For a board - * with separate L2 cache it probably depends also on the RSS, and - * for a board with shared L2 cache it ought to decay fast as other - * processes are run. - */ - -#define PROC_CHANGE_PENALTY 15 /* Schedule penalty */ - #endif #endif diff --git a/xen/include/asm-x86/smpboot.h b/xen/include/asm-x86/smpboot.h index 7a0b157114..6def59963b 100644 --- a/xen/include/asm-x86/smpboot.h +++ b/xen/include/asm-x86/smpboot.h @@ -1,132 +1,16 @@ #ifndef __ASM_SMPBOOT_H #define __ASM_SMPBOOT_H -/*emum for clustered_apic_mode values*/ -enum{ - CLUSTERED_APIC_NONE = 0, - CLUSTERED_APIC_XAPIC, - CLUSTERED_APIC_NUMAQ -}; - -#ifdef CONFIG_X86_CLUSTERED_APIC -extern unsigned int apic_broadcast_id; -extern unsigned char clustered_apic_mode; -extern unsigned char esr_disable; -extern unsigned char int_delivery_mode; -extern unsigned int int_dest_addr_mode; -extern int cyclone_setup(char*); - -static inline void detect_clustered_apic(char* oem, char* prod) -{ - /* - * Can't recognize Summit xAPICs at present, so use the OEM ID. - */ - if (!strncmp(oem, "IBM ENSW", 8) && !strncmp(prod, "VIGIL SMP", 9)){ - clustered_apic_mode = CLUSTERED_APIC_XAPIC; - apic_broadcast_id = APIC_BROADCAST_ID_XAPIC; - int_dest_addr_mode = APIC_DEST_PHYSICAL; - int_delivery_mode = dest_Fixed; - esr_disable = 1; - /*Start cyclone clock*/ - cyclone_setup(0); - /* check for ACPI tables */ - } else if (!strncmp(oem, "IBM", 3) && - (!strncmp(prod, "SERVIGIL", 8) || - !strncmp(prod, "EXA", 3) || - !strncmp(prod, "RUTHLESS", 8))){ - clustered_apic_mode = CLUSTERED_APIC_XAPIC; - apic_broadcast_id = APIC_BROADCAST_ID_XAPIC; - int_dest_addr_mode = APIC_DEST_PHYSICAL; - int_delivery_mode = dest_Fixed; - esr_disable = 1; - /*Start cyclone clock*/ - cyclone_setup(0); - } else if (!strncmp(oem, "IBM NUMA", 8)){ - clustered_apic_mode = CLUSTERED_APIC_NUMAQ; - apic_broadcast_id = APIC_BROADCAST_ID_APIC; - int_dest_addr_mode = APIC_DEST_LOGICAL; - int_delivery_mode = dest_LowestPrio; - esr_disable = 1; - } -} -#define INT_DEST_ADDR_MODE (int_dest_addr_mode) -#define INT_DELIVERY_MODE (int_delivery_mode) -#else /* CONFIG_X86_CLUSTERED_APIC */ -#define apic_broadcast_id (APIC_BROADCAST_ID_APIC) -#define clustered_apic_mode (CLUSTERED_APIC_NONE) -#define esr_disable (0) -#define detect_clustered_apic(x,y) -#define INT_DEST_ADDR_MODE (APIC_DEST_LOGICAL) /* logical delivery */ -#define INT_DELIVERY_MODE (dest_LowestPrio) -#endif /* CONFIG_X86_CLUSTERED_APIC */ -#define BAD_APICID 0xFFu - -#define TRAMPOLINE_LOW phys_to_virt((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?0x8:0x467) -#define TRAMPOLINE_HIGH phys_to_virt((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?0xa:0x469) - -#define boot_cpu_apicid ((clustered_apic_mode == CLUSTERED_APIC_NUMAQ)?boot_cpu_logical_apicid:boot_cpu_physical_apicid) - -extern unsigned char raw_phys_apicid[NR_CPUS]; - -/* - * How to map from the cpu_present_map - */ -static inline int cpu_present_to_apicid(int mps_cpu) -{ - if (clustered_apic_mode == CLUSTERED_APIC_XAPIC) - return raw_phys_apicid[mps_cpu]; - if(clustered_apic_mode == CLUSTERED_APIC_NUMAQ) - return (mps_cpu/4)*16 + (1<<(mps_cpu%4)); - return mps_cpu; -} - static inline unsigned long apicid_to_phys_cpu_present(int apicid) { - if(clustered_apic_mode) - return 1UL << (((apicid >> 4) << 2) + (apicid & 0x3)); return 1UL << apicid; } -#define physical_to_logical_apicid(phys_apic) ( (1ul << (phys_apic & 0x3)) | (phys_apic & 0xF0u) ) - -/* - * Mappings between logical cpu number and logical / physical apicid - * The first four macros are trivial, but it keeps the abstraction consistent - */ extern volatile int logical_apicid_2_cpu[]; extern volatile int cpu_2_logical_apicid[]; extern volatile int physical_apicid_2_cpu[]; extern volatile int cpu_2_physical_apicid[]; -#define logical_apicid_to_cpu(apicid) logical_apicid_2_cpu[apicid] -#define cpu_to_logical_apicid(cpu) cpu_2_logical_apicid[cpu] -#define physical_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid] -#define cpu_to_physical_apicid(cpu) cpu_2_physical_apicid[cpu] -#ifdef CONFIG_MULTIQUAD /* use logical IDs to bootstrap */ -#define boot_apicid_to_cpu(apicid) logical_apicid_2_cpu[apicid] -#define cpu_to_boot_apicid(cpu) cpu_2_logical_apicid[cpu] -#else /* !CONFIG_MULTIQUAD */ /* use physical IDs to bootstrap */ #define boot_apicid_to_cpu(apicid) physical_apicid_2_cpu[apicid] -#define cpu_to_boot_apicid(cpu) cpu_2_physical_apicid[cpu] -#endif /* CONFIG_MULTIQUAD */ -#ifdef CONFIG_X86_CLUSTERED_APIC -static inline int target_cpus(void) -{ - static int cpu; - switch(clustered_apic_mode){ - case CLUSTERED_APIC_NUMAQ: - /* Broadcast intrs to local quad only. */ - return APIC_BROADCAST_ID_APIC; - case CLUSTERED_APIC_XAPIC: - /*round robin the interrupts*/ - cpu = (cpu+1)%smp_num_cpus; - return cpu_to_physical_apicid(cpu); - default: - } - return cpu_online_map; -} -#else -#define target_cpus() (cpu_online_map) -#endif #endif diff --git a/xen/include/asm-x86/system.h b/xen/include/asm-x86/system.h index 49355af7d6..cd0619008d 100644 --- a/xen/include/asm-x86/system.h +++ b/xen/include/asm-x86/system.h @@ -112,6 +112,7 @@ static always_inline unsigned long __cmpxchg(volatile void *ptr, unsigned long o return old; } +#define __HAVE_ARCH_CMPXCHG #define cmpxchg(ptr,o,n)\ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\ (unsigned long)(n),sizeof(*(ptr)))) diff --git a/xen/include/asm-x86/time.h b/xen/include/asm-x86/time.h index 2256145bec..8f48cd31dc 100644 --- a/xen/include/asm-x86/time.h +++ b/xen/include/asm-x86/time.h @@ -2,6 +2,6 @@ #ifndef __X86_TIME_H__ #define __X86_TIME_H__ -/* nothing */ +extern int timer_ack; #endif /* __X86_TIME_H__ */ diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h index feda09036a..b84f047651 100644 --- a/xen/include/xen/acpi.h +++ b/xen/include/xen/acpi.h @@ -80,7 +80,7 @@ typedef struct { struct acpi_table_rsdt { struct acpi_table_header header; - u32 entry[1]; + u32 entry[8]; } __attribute__ ((packed)); /* Extended System Description Table (XSDT) */ @@ -232,9 +232,28 @@ struct acpi_table_hpet { u8 page_protect; } __attribute__ ((packed)); +/* + * Simple Boot Flags + * http://www.microsoft.com/whdc/hwdev/resources/specs/simp_bios.mspx + */ +struct acpi_table_sbf +{ + u8 sbf_signature[4]; + u32 sbf_len; + u8 sbf_revision; + u8 sbf_csum; + u8 sbf_oemid[6]; + u8 sbf_oemtable[8]; + u8 sbf_revdata[4]; + u8 sbf_creator[4]; + u8 sbf_crearev[4]; + u8 sbf_cmos; + u8 sbf_spare[3]; +} __attribute__ ((packed)); + /* * System Resource Affinity Table (SRAT) - * see http://www.microsoft.com/hwdev/design/srat.htm + * http://www.microsoft.com/whdc/hwdev/platform/proc/SRAT.mspx */ struct acpi_table_srat { @@ -309,7 +328,7 @@ struct acpi_table_sbst { /* Embedded Controller Boot Resources Table (ECDT) */ struct acpi_table_ecdt { - struct acpi_table_header header; + struct acpi_table_header header; struct acpi_generic_address ec_control; struct acpi_generic_address ec_data; u32 uid; @@ -317,6 +336,15 @@ struct acpi_table_ecdt { char ec_id[0]; } __attribute__ ((packed)); +/* PCI MMCONFIG */ + +struct acpi_table_mcfg { + struct acpi_table_header header; + u8 reserved[8]; + u32 base_address; + u32 base_reserved; +} __attribute__ ((packed)); + /* Table Handlers */ enum acpi_table_id { @@ -338,6 +366,7 @@ enum acpi_table_id { ACPI_SSDT, ACPI_SPMI, ACPI_HPET, + ACPI_MCFG, ACPI_TABLE_COUNT }; @@ -345,18 +374,19 @@ typedef int (*acpi_table_handler) (unsigned long phys_addr, unsigned long size); extern acpi_table_handler acpi_table_ops[ACPI_TABLE_COUNT]; -typedef int (*acpi_madt_entry_handler) (acpi_table_entry_header *header); +typedef int (*acpi_madt_entry_handler) (acpi_table_entry_header *header, const unsigned long end); char * __acpi_map_table (unsigned long phys_addr, unsigned long size); unsigned long acpi_find_rsdp (void); int acpi_boot_init (void); +int acpi_boot_table_init (void); int acpi_numa_init (void); int acpi_table_init (void); int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler); int acpi_get_table_header_early (enum acpi_table_id id, struct acpi_table_header **header); -int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler); -int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler); +int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries); +int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries); void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr); void acpi_table_print_madt_entry (acpi_table_entry_header *madt); void acpi_table_print_srat_entry (acpi_table_entry_header *srat); @@ -367,15 +397,45 @@ void acpi_numa_processor_affinity_init (struct acpi_table_processor_affinity *pa void acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma); void acpi_numa_arch_fixup(void); -#else /*!CONFIG_ACPI_BOOT*/ +#ifdef CONFIG_ACPI_HOTPLUG_CPU +/* Arch dependent functions for cpu hotplug support */ +int acpi_map_lsapic(acpi_handle handle, int *pcpu); +int acpi_unmap_lsapic(int cpu); +#endif /* CONFIG_ACPI_HOTPLUG_CPU */ + +extern int acpi_mp_config; + +extern u32 pci_mmcfg_base_addr; + +extern int sbf_port ; + +#else /*!CONFIG_ACPI_BOOT*/ + +#define acpi_mp_config 0 static inline int acpi_boot_init(void) { return 0; } -#endif /*!CONFIG_ACPI_BOOT*/ +static inline int acpi_boot_table_init(void) +{ + return 0; +} +#endif /*!CONFIG_ACPI_BOOT*/ + +unsigned int acpi_register_gsi (u32 gsi, int edge_level, int active_high_low); +int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); + +/* + * This function undoes the effect of one call to acpi_register_gsi(). + * If this matches the last registration, any IRQ resources for gsi + * are freed. + */ +#ifdef CONFIG_ACPI_DEALLOCATE_IRQ +void acpi_unregister_gsi (u32 gsi); +#endif #ifdef CONFIG_ACPI_PCI @@ -400,7 +460,11 @@ extern struct acpi_prt_list acpi_prt; struct pci_dev; int acpi_pci_irq_enable (struct pci_dev *dev); -int acpi_pci_irq_init (void); +void acpi_penalize_isa_irq(int irq); + +#ifdef CONFIG_ACPI_DEALLOCATE_IRQ +void acpi_pci_irq_disable (struct pci_dev *dev); +#endif struct acpi_pci_driver { struct acpi_pci_driver *next; @@ -415,14 +479,15 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver); #ifdef CONFIG_ACPI_EC -int ec_read(u8 addr, u8 *val); -int ec_write(u8 addr, u8 val); +extern int ec_read(u8 addr, u8 *val); +extern int ec_write(u8 addr, u8 val); #endif /*CONFIG_ACPI_EC*/ #ifdef CONFIG_ACPI_INTERPRETER -int acpi_blacklisted(void); +extern int acpi_blacklisted(void); +extern void acpi_bios_year(char *s); #else /*!CONFIG_ACPI_INTERPRETER*/ @@ -433,4 +498,41 @@ static inline int acpi_blacklisted(void) #endif /*!CONFIG_ACPI_INTERPRETER*/ +#define ACPI_CSTATE_LIMIT_DEFINED /* for driver builds */ +#ifdef CONFIG_ACPI + +/* + * Set highest legal C-state + * 0: C0 okay, but not C1 + * 1: C1 okay, but not C2 + * 2: C2 okay, but not C3 etc. + */ + +extern unsigned int max_cstate; + +static inline unsigned int acpi_get_cstate_limit(void) +{ + return max_cstate; +} +static inline void acpi_set_cstate_limit(unsigned int new_limit) +{ + max_cstate = new_limit; + return; +} +#else +static inline unsigned int acpi_get_cstate_limit(void) { return 0; } +static inline void acpi_set_cstate_limit(unsigned int new_limit) { return; } +#endif + +#ifdef CONFIG_ACPI_NUMA +int acpi_get_pxm(acpi_handle handle); +#else +static inline int acpi_get_pxm(acpi_handle handle) +{ + return 0; +} +#endif + +extern int pnpacpi_disabled; + #endif /*_LINUX_ACPI_H*/ diff --git a/xen/include/xen/bitmap.h b/xen/include/xen/bitmap.h new file mode 100644 index 0000000000..c91a10aef0 --- /dev/null +++ b/xen/include/xen/bitmap.h @@ -0,0 +1,249 @@ +#ifndef __XEN_BITMAP_H +#define __XEN_BITMAP_H + +#ifndef __ASSEMBLY__ + +#include +#include +#include + +/* + * bitmaps provide bit arrays that consume one or more unsigned + * longs. The bitmap interface and available operations are listed + * here, in bitmap.h + * + * Function implementations generic to all architectures are in + * lib/bitmap.c. Functions implementations that are architecture + * specific are in various include/asm-/bitops.h headers + * and other arch/ specific files. + * + * See lib/bitmap.c for more details. + */ + +/* + * The available bitmap operations and their rough meaning in the + * case that the bitmap is a single unsigned long are thus: + * + * bitmap_zero(dst, nbits) *dst = 0UL + * bitmap_fill(dst, nbits) *dst = ~0UL + * bitmap_copy(dst, src, nbits) *dst = *src + * bitmap_and(dst, src1, src2, nbits) *dst = *src1 & *src2 + * bitmap_or(dst, src1, src2, nbits) *dst = *src1 | *src2 + * bitmap_xor(dst, src1, src2, nbits) *dst = *src1 ^ *src2 + * bitmap_andnot(dst, src1, src2, nbits) *dst = *src1 & ~(*src2) + * bitmap_complement(dst, src, nbits) *dst = ~(*src) + * bitmap_equal(src1, src2, nbits) Are *src1 and *src2 equal? + * bitmap_intersects(src1, src2, nbits) Do *src1 and *src2 overlap? + * bitmap_subset(src1, src2, nbits) Is *src1 a subset of *src2? + * bitmap_empty(src, nbits) Are all bits zero in *src? + * bitmap_full(src, nbits) Are all bits set in *src? + * bitmap_weight(src, nbits) Hamming Weight: number set bits + * bitmap_shift_right(dst, src, n, nbits) *dst = *src >> n + * bitmap_shift_left(dst, src, n, nbits) *dst = *src << n + */ + +/* + * Also the following operations in asm/bitops.h apply to bitmaps. + * + * set_bit(bit, addr) *addr |= bit + * clear_bit(bit, addr) *addr &= ~bit + * change_bit(bit, addr) *addr ^= bit + * test_bit(bit, addr) Is bit set in *addr? + * test_and_set_bit(bit, addr) Set bit and return old value + * test_and_clear_bit(bit, addr) Clear bit and return old value + * test_and_change_bit(bit, addr) Change bit and return old value + * find_first_zero_bit(addr, nbits) Position first zero bit in *addr + * find_first_bit(addr, nbits) Position first set bit in *addr + * find_next_zero_bit(addr, nbits, bit) Position next zero bit in *addr >= bit + * find_next_bit(addr, nbits, bit) Position next set bit in *addr >= bit + */ + +/* + * The DECLARE_BITMAP(name,bits) macro, in xen/types.h, can be used + * to declare an array named 'name' of just enough unsigned longs to + * contain all bit positions from 0 to 'bits' - 1. + */ + +/* + * lib/bitmap.c provides these functions: + */ + +extern int __bitmap_empty(const unsigned long *bitmap, int bits); +extern int __bitmap_full(const unsigned long *bitmap, int bits); +extern int __bitmap_equal(const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits); +extern void __bitmap_complement(unsigned long *dst, const unsigned long *src, + int bits); +extern void __bitmap_shift_right(unsigned long *dst, + const unsigned long *src, int shift, int bits); +extern void __bitmap_shift_left(unsigned long *dst, + const unsigned long *src, int shift, int bits); +extern void __bitmap_and(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits); +extern void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits); +extern void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits); +extern void __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits); +extern int __bitmap_intersects(const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits); +extern int __bitmap_subset(const unsigned long *bitmap1, + const unsigned long *bitmap2, int bits); +extern int __bitmap_weight(const unsigned long *bitmap, int bits); + +extern int bitmap_find_free_region(unsigned long *bitmap, int bits, int order); +extern void bitmap_release_region(unsigned long *bitmap, int pos, int order); +extern int bitmap_allocate_region(unsigned long *bitmap, int pos, int order); + +#define BITMAP_LAST_WORD_MASK(nbits) \ +( \ + ((nbits) % BITS_PER_LONG) ? \ + (1UL<<((nbits) % BITS_PER_LONG))-1 : ~0UL \ +) + +static inline void bitmap_zero(unsigned long *dst, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = 0UL; + else { + int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); + memset(dst, 0, len); + } +} + +static inline void bitmap_fill(unsigned long *dst, int nbits) +{ + size_t nlongs = BITS_TO_LONGS(nbits); + if (nlongs > 1) { + int len = (nlongs - 1) * sizeof(unsigned long); + memset(dst, 0xff, len); + } + dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits); +} + +static inline void bitmap_copy(unsigned long *dst, const unsigned long *src, + int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = *src; + else { + int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); + memcpy(dst, src, len); + } +} + +static inline void bitmap_and(unsigned long *dst, const unsigned long *src1, + const unsigned long *src2, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = *src1 & *src2; + else + __bitmap_and(dst, src1, src2, nbits); +} + +static inline void bitmap_or(unsigned long *dst, const unsigned long *src1, + const unsigned long *src2, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = *src1 | *src2; + else + __bitmap_or(dst, src1, src2, nbits); +} + +static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1, + const unsigned long *src2, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = *src1 ^ *src2; + else + __bitmap_xor(dst, src1, src2, nbits); +} + +static inline void bitmap_andnot(unsigned long *dst, const unsigned long *src1, + const unsigned long *src2, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = *src1 & ~(*src2); + else + __bitmap_andnot(dst, src1, src2, nbits); +} + +static inline void bitmap_complement(unsigned long *dst, const unsigned long *src, + int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = ~(*src) & BITMAP_LAST_WORD_MASK(nbits); + else + __bitmap_complement(dst, src, nbits); +} + +static inline int bitmap_equal(const unsigned long *src1, + const unsigned long *src2, int nbits) +{ + if (nbits <= BITS_PER_LONG) + return ! ((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits)); + else + return __bitmap_equal(src1, src2, nbits); +} + +static inline int bitmap_intersects(const unsigned long *src1, + const unsigned long *src2, int nbits) +{ + if (nbits <= BITS_PER_LONG) + return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0; + else + return __bitmap_intersects(src1, src2, nbits); +} + +static inline int bitmap_subset(const unsigned long *src1, + const unsigned long *src2, int nbits) +{ + if (nbits <= BITS_PER_LONG) + return ! ((*src1 & ~(*src2)) & BITMAP_LAST_WORD_MASK(nbits)); + else + return __bitmap_subset(src1, src2, nbits); +} + +static inline int bitmap_empty(const unsigned long *src, int nbits) +{ + if (nbits <= BITS_PER_LONG) + return ! (*src & BITMAP_LAST_WORD_MASK(nbits)); + else + return __bitmap_empty(src, nbits); +} + +static inline int bitmap_full(const unsigned long *src, int nbits) +{ + if (nbits <= BITS_PER_LONG) + return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits)); + else + return __bitmap_full(src, nbits); +} + +static inline int bitmap_weight(const unsigned long *src, int nbits) +{ + return __bitmap_weight(src, nbits); +} + +static inline void bitmap_shift_right(unsigned long *dst, + const unsigned long *src, int n, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = *src >> n; + else + __bitmap_shift_right(dst, src, n, nbits); +} + +static inline void bitmap_shift_left(unsigned long *dst, + const unsigned long *src, int n, int nbits) +{ + if (nbits <= BITS_PER_LONG) + *dst = (*src << n) & BITMAP_LAST_WORD_MASK(nbits); + else + __bitmap_shift_left(dst, src, n, nbits); +} + +#endif /* __ASSEMBLY__ */ + +#endif /* __XEN_BITMAP_H */ diff --git a/xen/include/xen/bitops.h b/xen/include/xen/bitops.h new file mode 100644 index 0000000000..e743c0059d --- /dev/null +++ b/xen/include/xen/bitops.h @@ -0,0 +1,129 @@ +#ifndef _LINUX_BITOPS_H +#define _LINUX_BITOPS_H +#include + +/* + * ffs: find first bit set. This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ + +static inline int generic_ffs(int x) +{ + int r = 1; + + if (!x) + return 0; + if (!(x & 0xffff)) { + x >>= 16; + r += 16; + } + if (!(x & 0xff)) { + x >>= 8; + r += 8; + } + if (!(x & 0xf)) { + x >>= 4; + r += 4; + } + if (!(x & 3)) { + x >>= 2; + r += 2; + } + if (!(x & 1)) { + x >>= 1; + r += 1; + } + return r; +} + +/* + * fls: find last bit set. + */ + +static __inline__ int generic_fls(int x) +{ + int r = 32; + + if (!x) + return 0; + if (!(x & 0xffff0000u)) { + x <<= 16; + r -= 16; + } + if (!(x & 0xff000000u)) { + x <<= 8; + r -= 8; + } + if (!(x & 0xf0000000u)) { + x <<= 4; + r -= 4; + } + if (!(x & 0xc0000000u)) { + x <<= 2; + r -= 2; + } + if (!(x & 0x80000000u)) { + x <<= 1; + r -= 1; + } + return r; +} + +/* + * Include this here because some architectures need generic_ffs/fls in + * scope + */ +#include + +/* + * hweightN: returns the hamming weight (i.e. the number + * of bits set) of a N-bit word + */ + +static inline unsigned int generic_hweight32(unsigned int w) +{ + unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); + res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); + return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); +} + +static inline unsigned int generic_hweight16(unsigned int w) +{ + unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555); + res = (res & 0x3333) + ((res >> 2) & 0x3333); + res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F); + return (res & 0x00FF) + ((res >> 8) & 0x00FF); +} + +static inline unsigned int generic_hweight8(unsigned int w) +{ + unsigned int res = (w & 0x55) + ((w >> 1) & 0x55); + res = (res & 0x33) + ((res >> 2) & 0x33); + return (res & 0x0F) + ((res >> 4) & 0x0F); +} + +static inline unsigned long generic_hweight64(__u64 w) +{ +#if BITS_PER_LONG < 64 + return generic_hweight32((unsigned int)(w >> 32)) + + generic_hweight32((unsigned int)w); +#else + u64 res; + res = (w & 0x5555555555555555ul) + ((w >> 1) & 0x5555555555555555ul); + res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul); + res = (res & 0x0F0F0F0F0F0F0F0Ful) + ((res >> 4) & 0x0F0F0F0F0F0F0F0Ful); + res = (res & 0x00FF00FF00FF00FFul) + ((res >> 8) & 0x00FF00FF00FF00FFul); + res = (res & 0x0000FFFF0000FFFFul) + ((res >> 16) & 0x0000FFFF0000FFFFul); + return (res & 0x00000000FFFFFFFFul) + ((res >> 32) & 0x00000000FFFFFFFFul); +#endif +} + +static inline unsigned long hweight_long(unsigned long w) +{ + return sizeof(w) == 4 ? generic_hweight32(w) : generic_hweight64(w); +} + +#endif diff --git a/xen/include/xen/config.h b/xen/include/xen/config.h index 95101174ba..ca3650f80f 100644 --- a/xen/include/xen/config.h +++ b/xen/include/xen/config.h @@ -15,7 +15,7 @@ #define always_inline __inline__ __attribute__ ((always_inline)) -/* syslog levels ==> nothing! */ +/* Linux syslog levels. */ #define KERN_NOTICE "" #define KERN_WARNING "" #define KERN_DEBUG "" @@ -25,6 +25,10 @@ #define KERN_EMERG "" #define KERN_ALERT "" +/* Linux 'checker' project. */ +#define __iomem +#define __user + #ifdef VERBOSE #define DPRINTK(_f, _a...) printk("(file=%s, line=%d) " _f, \ __FILE__ , __LINE__ , ## _a ) diff --git a/xen/include/xen/cpumask.h b/xen/include/xen/cpumask.h new file mode 100644 index 0000000000..33723fbd9a --- /dev/null +++ b/xen/include/xen/cpumask.h @@ -0,0 +1,25 @@ +/* + * XXX This to be replaced with the Linux file in the near future. + */ + +#ifndef __XEN_CPUMASK_H__ +#define __XEN_CPUMASK_H__ + +#include + +typedef u32 cpumask_t; + +extern cpumask_t cpu_online_map; + +static inline int cpus_weight(cpumask_t w) +{ + unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); + res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); + return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); +} + +#define cpus_addr(_m) (&(_m)) + +#endif /* __XEN_CPUMASK_H__ */ diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h index 6c77460f41..f419f0c182 100644 --- a/xen/include/xen/irq.h +++ b/xen/include/xen/irq.h @@ -2,6 +2,7 @@ #define __XEN_IRQ_H__ #include +#include #include #include #include @@ -35,7 +36,7 @@ struct hw_interrupt_type { void (*disable)(unsigned int irq); void (*ack)(unsigned int irq); void (*end)(unsigned int irq); - void (*set_affinity)(unsigned int irq, unsigned long mask); + void (*set_affinity)(unsigned int irq, cpumask_t mask); }; typedef struct hw_interrupt_type hw_irq_controller; diff --git a/xen/include/xen/smp.h b/xen/include/xen/smp.h index df80e23295..811e25ac24 100644 --- a/xen/include/xen/smp.h +++ b/xen/include/xen/smp.h @@ -46,6 +46,17 @@ extern void smp_commence(void); extern int smp_call_function( void (*func) (void *info), void *info, int retry, int wait); +/* + * Call a function on all processors + */ +static inline int on_each_cpu(void (*func) (void *info), void *info, + int retry, int wait) +{ + int ret = smp_call_function(func, info, retry, wait); + func(info); + return ret; +} + /* * True once the per process idle is forked */ @@ -85,7 +96,15 @@ extern volatile int smp_msg_id; #define cpu_logical_map(cpu) 0 #define cpu_number_map(cpu) 0 #define smp_call_function(func,info,retry,wait) 0 +#define on_each_cpu(func,info,retry,wait) ({ func(info); 0; }) #define cpu_online_map 1 #endif + +#ifdef __smp_processor_id +#define smp_processor_id() __smp_processor_id() +#else +extern unsigned int smp_processor_id(void); +#endif + #endif diff --git a/xen/include/xen/spinlock.h b/xen/include/xen/spinlock.h index ef58ba591b..73184daad8 100644 --- a/xen/include/xen/spinlock.h +++ b/xen/include/xen/spinlock.h @@ -82,4 +82,7 @@ typedef struct { int gcc_is_buggy; } rwlock_t; #define write_lock(_lock) _raw_write_lock(_lock) #define write_unlock(_lock) _raw_write_unlock(_lock) +#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED +#define DEFINE_RWLOCK(x) rwlock_t x = RW_LOCK_UNLOCKED + #endif /* __SPINLOCK_H__ */ diff --git a/xen/include/xen/types.h b/xen/include/xen/types.h index cd55353dfe..6258a745cf 100644 --- a/xen/include/xen/types.h +++ b/xen/include/xen/types.h @@ -1,8 +1,14 @@ #ifndef __TYPES_H__ #define __TYPES_H__ +#include #include +#define BITS_TO_LONGS(bits) \ + (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) +#define DECLARE_BITMAP(name,bits) \ + unsigned long name[BITS_TO_LONGS(bits)] + #ifndef NULL #define NULL ((void*)0) #endif From 030eb992da7ab2e40d809fe91506fa0570363bde Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Mon, 9 May 2005 18:51:24 +0000 Subject: [PATCH 29/54] bitkeeper revision 1.1389.9.3 (427fb12c-ZTnIDL6puEsDOsDVeEKJg) Move per-domain-per-cpu variables out of shared page for security --- xen/arch/ia64/asm-offsets.c | 4 +- xen/arch/ia64/process.c | 5 +- xen/arch/ia64/vcpu.c | 134 ++++++++++++++++----------------- xen/include/asm-ia64/domain.h | 20 ++++- xen/include/public/arch-ia64.h | 20 +---- 5 files changed, 93 insertions(+), 90 deletions(-) diff --git a/xen/arch/ia64/asm-offsets.c b/xen/arch/ia64/asm-offsets.c index f7b2fbd67e..4326ea0078 100644 --- a/xen/arch/ia64/asm-offsets.c +++ b/xen/arch/ia64/asm-offsets.c @@ -50,8 +50,8 @@ void foo(void) //DEFINE(IA64_TASK_SIGHAND_OFFSET,offsetof (struct task_struct, sighand)); //DEFINE(IA64_TASK_SIGNAL_OFFSET,offsetof (struct task_struct, signal)); //DEFINE(IA64_TASK_TGID_OFFSET, offsetof (struct task_struct, tgid)); - DEFINE(IA64_TASK_THREAD_KSP_OFFSET, offsetof (struct task_struct, thread.ksp)); - DEFINE(IA64_TASK_THREAD_ON_USTACK_OFFSET, offsetof (struct task_struct, thread.on_ustack)); + DEFINE(IA64_TASK_THREAD_KSP_OFFSET, offsetof (struct exec_domain, arch._thread.ksp)); + DEFINE(IA64_TASK_THREAD_ON_USTACK_OFFSET, offsetof (struct exec_domain, arch._thread.on_ustack)); BLANK(); diff --git a/xen/arch/ia64/process.c b/xen/arch/ia64/process.c index 27115d1b39..985ba7cbed 100644 --- a/xen/arch/ia64/process.c +++ b/xen/arch/ia64/process.c @@ -51,6 +51,7 @@ extern unsigned long dom0_start, dom0_size; IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | IA64_PSR_IA) #define PSCB(x,y) x->vcpu_info->arch.y +#define PSCBX(x,y) x->arch.y extern unsigned long vcpu_verbose; @@ -154,7 +155,7 @@ panic_domain(regs,"psr.ic off, delivering fault=%lx,iip=%p,ifa=%p,isr=%p,PSCB.ii } //printf("Delivering NESTED DATA TLB fault\n"); vector = IA64_DATA_NESTED_TLB_VECTOR; - regs->cr_iip = ((unsigned long) PSCB(ed,iva) + vector) & ~0xffUL; + regs->cr_iip = ((unsigned long) PSCBX(ed,iva) + vector) & ~0xffUL; regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET; // NOTE: nested trap must NOT pass PSCB address //regs->r31 = (unsigned long) &PSCB(ed); @@ -187,7 +188,7 @@ panic_domain(regs,"psr.ic off, delivering fault=%lx,iip=%p,ifa=%p,isr=%p,PSCB.ii PSCB(ed,ifs) = 0; PSCB(ed,incomplete_regframe) = 0; - regs->cr_iip = ((unsigned long) PSCB(ed,iva) + vector) & ~0xffUL; + regs->cr_iip = ((unsigned long) PSCBX(ed,iva) + vector) & ~0xffUL; regs->cr_ipsr = (regs->cr_ipsr & ~DELIVER_PSR_CLR) | DELIVER_PSR_SET; #ifdef CONFIG_SMP #error "sharedinfo doesn't handle smp yet" diff --git a/xen/arch/ia64/vcpu.c b/xen/arch/ia64/vcpu.c index f07d5ab788..c46e7c48d8 100644 --- a/xen/arch/ia64/vcpu.c +++ b/xen/arch/ia64/vcpu.c @@ -1,6 +1,6 @@ /* * Virtualized CPU functions - * + * * Copyright (C) 2004 Hewlett-Packard Co. * Dan Magenheimer (dan.magenheimer@hp.com) * @@ -26,6 +26,7 @@ typedef union { // this def for vcpu_regs won't work if kernel stack is present #define vcpu_regs(vcpu) ((struct pt_regs *) vcpu->arch.regs) #define PSCB(x,y) x->vcpu_info->arch.y +#define PSCBX(x,y) x->arch.y #define TRUE 1 #define FALSE 0 @@ -289,9 +290,9 @@ BOOLEAN vcpu_get_psr_i(VCPU *vcpu) UINT64 vcpu_get_ipsr_int_state(VCPU *vcpu,UINT64 prevpsr) { - UINT64 dcr = PSCB(vcpu,dcr); + UINT64 dcr = PSCBX(vcpu,dcr); PSR psr = {0}; - + //printf("*** vcpu_get_ipsr_int_state (0x%016lx)...",prevpsr); psr.i64 = prevpsr; psr.ia64_psr.be = 0; if (dcr & IA64_DCR_BE) psr.ia64_psr.be = 1; @@ -317,13 +318,13 @@ extern unsigned long privop_trace; //verbose("vcpu_get_dcr: called @%p\n",PSCB(vcpu,iip)); // Reads of cr.dcr on Xen always have the sign bit set, so // a domain can differentiate whether it is running on SP or not - *pval = PSCB(vcpu,dcr) | 0x8000000000000000L; + *pval = PSCBX(vcpu,dcr) | 0x8000000000000000L; return (IA64_NO_FAULT); } IA64FAULT vcpu_get_iva(VCPU *vcpu, UINT64 *pval) { - *pval = PSCB(vcpu,iva) & ~0x7fffL; + *pval = PSCBX(vcpu,iva) & ~0x7fffL; return (IA64_NO_FAULT); } @@ -423,13 +424,13 @@ extern unsigned long privop_trace; // a domain can differentiate whether it is running on SP or not // Thus, writes of DCR should ignore the sign bit //verbose("vcpu_set_dcr: called\n"); - PSCB(vcpu,dcr) = val & ~0x8000000000000000L; + PSCBX(vcpu,dcr) = val & ~0x8000000000000000L; return (IA64_NO_FAULT); } IA64FAULT vcpu_set_iva(VCPU *vcpu, UINT64 val) { - PSCB(vcpu,iva) = val & ~0x7fffL; + PSCBX(vcpu,iva) = val & ~0x7fffL; return (IA64_NO_FAULT); } @@ -523,16 +524,16 @@ void vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector) return; } if (!test_bit(vector,PSCB(vcpu,delivery_mask))) return; - if (test_bit(vector,PSCB(vcpu,irr))) { + if (test_bit(vector,PSCBX(vcpu,irr))) { //printf("vcpu_pend_interrupt: overrun\n"); } - set_bit(vector,PSCB(vcpu,irr)); + set_bit(vector,PSCBX(vcpu,irr)); PSCB(vcpu,pending_interruption) = 1; } void early_tick(VCPU *vcpu) { - UINT64 *p = &PSCB(vcpu,irr[3]); + UINT64 *p = &PSCBX(vcpu,irr[3]); printf("vcpu_check_pending: about to deliver early tick\n"); printf("&irr[0]=%p, irr[0]=0x%lx\n",p,*p); } @@ -550,9 +551,9 @@ UINT64 vcpu_check_pending_interrupts(VCPU *vcpu) { UINT64 *p, *q, *r, bits, bitnum, mask, i, vector; - p = &PSCB(vcpu,irr[3]); + p = &PSCBX(vcpu,irr[3]); q = &PSCB(vcpu,delivery_mask[3]); - r = &PSCB(vcpu,insvc[3]); + r = &PSCBX(vcpu,insvc[3]); for (i = 3; ; p--, q--, r--, i--) { bits = *p & *q; if (bits) break; // got a potential interrupt @@ -592,9 +593,9 @@ UINT64 vcpu_check_pending_interrupts(VCPU *vcpu) #if 0 if (vector == (PSCB(vcpu,itv) & 0xff)) { UINT64 now = ia64_get_itc(); - UINT64 itm = PSCB(vcpu,domain_itm); + UINT64 itm = PSCBX(vcpu,domain_itm); if (now < itm) early_tick(vcpu); - + } #endif return vector; @@ -654,13 +655,13 @@ IA64FAULT vcpu_get_ivr(VCPU *vcpu, UINT64 *pval) i = vector >> 6; mask = 1L << (vector & 0x3f); //printf("ZZZZZZ vcpu_get_ivr: setting insvc mask for vector %ld\n",vector); - PSCB(vcpu,insvc[i]) |= mask; - PSCB(vcpu,irr[i]) &= ~mask; + PSCBX(vcpu,insvc[i]) |= mask; + PSCBX(vcpu,irr[i]) &= ~mask; //PSCB(vcpu,pending_interruption)--; *pval = vector; // if delivering a timer interrupt, remember domain_itm if (vector == (PSCB(vcpu,itv) & 0xff)) { - PSCB(vcpu,domain_itm_last) = PSCB(vcpu,domain_itm); + PSCBX(vcpu,domain_itm_last) = PSCBX(vcpu,domain_itm); } return IA64_NO_FAULT; } @@ -775,7 +776,7 @@ IA64FAULT vcpu_set_eoi(VCPU *vcpu, UINT64 val) UINT64 *p, bits, vec, bitnum; int i; - p = &PSCB(vcpu,insvc[3]); + p = &PSCBX(vcpu,insvc[3]); for (i = 3; (i >= 0) && !(bits = *p); i--, p--); if (i < 0) { printf("Trying to EOI interrupt when none are in-service.\r\n"); @@ -826,8 +827,8 @@ extern unsigned long privop_trace; if (val & 0xef00) return (IA64_ILLOP_FAULT); PSCB(vcpu,itv) = val; if (val & 0x10000) { -printf("**** vcpu_set_itv(%d): vitm=%lx, setting to 0\n",val,PSCB(vcpu,domain_itm)); - PSCB(vcpu,domain_itm) = 0; +printf("**** vcpu_set_itv(%d): vitm=%lx, setting to 0\n",val,PSCBX(vcpu,domain_itm)); + PSCBX(vcpu,domain_itm) = 0; } else vcpu_enable_timer(vcpu,1000000L); return (IA64_NO_FAULT); @@ -860,14 +861,14 @@ BOOLEAN vcpu_timer_disabled(VCPU *vcpu) BOOLEAN vcpu_timer_inservice(VCPU *vcpu) { UINT64 itv = PSCB(vcpu,itv); - return (test_bit(itv, PSCB(vcpu,insvc))); + return (test_bit(itv, PSCBX(vcpu,insvc))); } BOOLEAN vcpu_timer_expired(VCPU *vcpu) { - unsigned long domain_itm = PSCB(vcpu,domain_itm); + unsigned long domain_itm = PSCBX(vcpu,domain_itm); unsigned long now = ia64_get_itc(); - + if (!domain_itm) return FALSE; if (now < domain_itm) return FALSE; if (vcpu_timer_disabled(vcpu)) return FALSE; @@ -892,36 +893,36 @@ void vcpu_safe_set_itm(unsigned long val) void vcpu_set_next_timer(VCPU *vcpu) { - UINT64 d = PSCB(vcpu,domain_itm); - //UINT64 s = PSCB(vcpu,xen_itm); + UINT64 d = PSCBX(vcpu,domain_itm); + //UINT64 s = PSCBX(vcpu,xen_itm); UINT64 s = local_cpu_data->itm_next; UINT64 now = ia64_get_itc(); - //UINT64 interval = PSCB(vcpu,xen_timer_interval); + //UINT64 interval = PSCBX(vcpu,xen_timer_interval); /* gloss over the wraparound problem for now... we know it exists * but it doesn't matter right now */ #if 0 /* ensure at least next SP tick is in the future */ - if (!interval) PSCB(vcpu,xen_itm) = now + + if (!interval) PSCBX(vcpu,xen_itm) = now + #if 0 (running_on_sim() ? SIM_DEFAULT_CLOCK_RATE : - DEFAULT_CLOCK_RATE); + DEFAULT_CLOCK_RATE); #else 3000000; //printf("vcpu_set_next_timer: HACK!\n"); #endif #if 0 - if (PSCB(vcpu,xen_itm) < now) - while (PSCB(vcpu,xen_itm) < now + (interval>>1)) - PSCB(vcpu,xen_itm) += interval; + if (PSCBX(vcpu,xen_itm) < now) + while (PSCBX(vcpu,xen_itm) < now + (interval>>1)) + PSCBX(vcpu,xen_itm) += interval; #endif #endif if (is_idle_task(vcpu->domain)) { printf("****** vcpu_set_next_timer called during idle!!\n"); } - //s = PSCB(vcpu,xen_itm); + //s = PSCBX(vcpu,xen_itm); if (d && (d > now) && (d < s)) { vcpu_safe_set_itm(d); //using_domain_as_itm++; @@ -935,10 +936,10 @@ void vcpu_set_next_timer(VCPU *vcpu) // parameter is a time interval specified in cycles void vcpu_enable_timer(VCPU *vcpu,UINT64 cycles) { - PSCB(vcpu,xen_timer_interval) = cycles; + PSCBX(vcpu,xen_timer_interval) = cycles; vcpu_set_next_timer(vcpu); printf("vcpu_enable_timer(%d): interval set to %d cycles\n", - PSCB(vcpu,xen_timer_interval)); + PSCBX(vcpu,xen_timer_interval)); __set_bit(PSCB(vcpu,itv), PSCB(vcpu,delivery_mask)); } @@ -948,30 +949,30 @@ IA64FAULT vcpu_set_itm(VCPU *vcpu, UINT64 val) //if (val < now) val = now + 1000; //printf("*** vcpu_set_itm: called with %lx\n",val); - PSCB(vcpu,domain_itm) = val; + PSCBX(vcpu,domain_itm) = val; vcpu_set_next_timer(vcpu); return (IA64_NO_FAULT); } IA64FAULT vcpu_set_itc(VCPU *vcpu, UINT64 val) { - + UINT64 oldnow = ia64_get_itc(); - UINT64 olditm = PSCB(vcpu,domain_itm); + UINT64 olditm = PSCBX(vcpu,domain_itm); unsigned long d = olditm - oldnow; unsigned long x = local_cpu_data->itm_next - oldnow; - + UINT64 newnow = val, min_delta; local_irq_disable(); if (olditm) { printf("**** vcpu_set_itc(%lx): vitm changed to %lx\n",val,newnow+d); - PSCB(vcpu,domain_itm) = newnow + d; + PSCBX(vcpu,domain_itm) = newnow + d; } local_cpu_data->itm_next = newnow + x; - d = PSCB(vcpu,domain_itm); + d = PSCBX(vcpu,domain_itm); x = local_cpu_data->itm_next; - + ia64_set_itc(newnow); if (d && (d > newnow) && (d < x)) { vcpu_safe_set_itm(d); @@ -1006,7 +1007,7 @@ void vcpu_pend_timer(VCPU *vcpu) if (vcpu_timer_disabled(vcpu)) return; //if (vcpu_timer_inservice(vcpu)) return; - if (PSCB(vcpu,domain_itm_last) == PSCB(vcpu,domain_itm)) { + if (PSCBX(vcpu,domain_itm_last) == PSCBX(vcpu,domain_itm)) { // already delivered an interrupt for this so // don't deliver another return; @@ -1014,7 +1015,7 @@ void vcpu_pend_timer(VCPU *vcpu) #if 0 // attempt to flag "timer tick before its due" source { - UINT64 itm = PSCB(vcpu,domain_itm); + UINT64 itm = PSCBX(vcpu,domain_itm); UINT64 now = ia64_get_itc(); if (now < itm) printf("******* vcpu_pend_timer: pending before due!\n"); } @@ -1026,7 +1027,7 @@ void vcpu_pend_timer(VCPU *vcpu) UINT64 vcpu_timer_pending_early(VCPU *vcpu) { UINT64 now = ia64_get_itc(); - UINT64 itm = PSCB(vcpu,domain_itm); + UINT64 itm = PSCBX(vcpu,domain_itm); if (vcpu_timer_disabled(vcpu)) return 0; if (!itm) return 0; @@ -1038,7 +1039,7 @@ void vcpu_poke_timer(VCPU *vcpu) { UINT64 itv = PSCB(vcpu,itv) & 0xff; UINT64 now = ia64_get_itc(); - UINT64 itm = PSCB(vcpu,domain_itm); + UINT64 itm = PSCBX(vcpu,domain_itm); UINT64 irr; if (vcpu_timer_disabled(vcpu)) return; @@ -1048,8 +1049,8 @@ void vcpu_poke_timer(VCPU *vcpu) while(1); } // using 0xef instead of itv so can get real irr - if (now > itm && !test_bit(0xefL, PSCB(vcpu,insvc))) { - if (!test_bit(0xefL,PSCB(vcpu,irr))) { + if (now > itm && !test_bit(0xefL, PSCBX(vcpu,insvc))) { + if (!test_bit(0xefL,PSCBX(vcpu,irr))) { irr = ia64_getreg(_IA64_REG_CR_IRR3); if (irr & (1L<<(0xef-0xc0))) return; if (now-itm>0x800000) @@ -1106,7 +1107,7 @@ printf("SI_CR_IIP/IPSR/IFS_OFFSET CHANGED, SEE dorfirfi\n"); printf("SI_CR_IIP=0x%x,IPSR=0x%x,IFS_OFFSET=0x%x\n",SI_OFS(iip),SI_OFS(ipsr),SI_OFS(ifs)); while(1); } - // TODO: validate PSCB(vcpu,iip) + // TODO: validate PSCB(vcpu,iip) // TODO: PSCB(vcpu,ipsr) = psr; PSCB(vcpu,ipsr) = psr.i64; // now set up the trampoline @@ -1353,7 +1354,6 @@ IA64FAULT vcpu_get_cpuid(VCPU *vcpu, UINT64 reg, UINT64 *pval) unsigned long vcpu_get_rr_ve(VCPU *vcpu,UINT64 vadr) { - ia64_rr rr; rr.rrval = PSCB(vcpu,rrs)[vadr>>61]; @@ -1363,7 +1363,6 @@ unsigned long vcpu_get_rr_ve(VCPU *vcpu,UINT64 vadr) unsigned long vcpu_get_rr_ps(VCPU *vcpu,UINT64 vadr) { - ia64_rr rr; rr.rrval = PSCB(vcpu,rrs)[vadr>>61]; @@ -1373,7 +1372,6 @@ unsigned long vcpu_get_rr_ps(VCPU *vcpu,UINT64 vadr) unsigned long vcpu_get_rr_rid(VCPU *vcpu,UINT64 vadr) { - ia64_rr rr; rr.rrval = PSCB(vcpu,rrs)[vadr>>61]; @@ -1460,8 +1458,8 @@ TR_ENTRY *vcpu_match_tr_entry(VCPU *vcpu, TR_ENTRY *trp, UINT64 ifa, int count) for (i = 0; i < count; i++, trp++) { if (!trp->p) continue; if (physicalize_rid(vcpu,trp->rid) != rid) continue; - if (ifa < trp->vadr) continue; - if (ifa >= (trp->vadr + (1L << trp->ps)) - 1) continue; + if (ifa < trp->vadr) continue; + if (ifa >= (trp->vadr + (1L << trp->ps)) - 1) continue; //if (trp->key && !match_pkr(vcpu,trp->key)) continue; return trp; } @@ -1472,9 +1470,9 @@ TR_ENTRY *match_tr(VCPU *vcpu, unsigned long ifa) { TR_ENTRY *trp; - trp = vcpu_match_tr_entry(vcpu,vcpu->vcpu_info->arch.dtrs,ifa,NDTRS); + trp = vcpu_match_tr_entry(vcpu,vcpu->arch.dtrs,ifa,NDTRS); if (trp) return trp; - trp = vcpu_match_tr_entry(vcpu,vcpu->vcpu_info->arch.itrs,ifa,NITRS); + trp = vcpu_match_tr_entry(vcpu,vcpu->arch.itrs,ifa,NITRS); if (trp) return trp; return 0; } @@ -1485,7 +1483,8 @@ IA64FAULT vcpu_itr_d(VCPU *vcpu, UINT64 slot, UINT64 pte, TR_ENTRY *trp; if (slot >= NDTRS) return IA64_RSVDREG_FAULT; - trp = &PSCB(vcpu,dtrs[slot]); + trp = &PSCBX(vcpu,dtrs[slot]); +//printf("***** itr.d: setting slot %d: ifa=%p\n",slot,ifa); vcpu_set_tr_entry(trp,pte,itir,ifa); return IA64_NO_FAULT; } @@ -1496,7 +1495,8 @@ IA64FAULT vcpu_itr_i(VCPU *vcpu, UINT64 slot, UINT64 pte, TR_ENTRY *trp; if (slot >= NITRS) return IA64_RSVDREG_FAULT; - trp = &PSCB(vcpu,itrs[slot]); + trp = &PSCBX(vcpu,itrs[slot]); +//printf("***** itr.i: setting slot %d: ifa=%p\n",slot,ifa); vcpu_set_tr_entry(trp,pte,itir,ifa); return IA64_NO_FAULT; } @@ -1539,12 +1539,12 @@ void vcpu_itc_no_srlz(VCPU *vcpu, UINT64 IorD, UINT64 vaddr, UINT64 pte, UINT64 #endif if (IorD & 0x4) return; // don't place in 1-entry TLB if (IorD & 0x1) { - vcpu_set_tr_entry(&PSCB(vcpu,itlb),pte,ps<<2,vaddr); - PSCB(vcpu,itlb_pte) = mp_pte; + vcpu_set_tr_entry(&PSCBX(vcpu,itlb),pte,ps<<2,vaddr); + PSCBX(vcpu,itlb_pte) = mp_pte; } if (IorD & 0x2) { - vcpu_set_tr_entry(&PSCB(vcpu,dtlb),pte,ps<<2,vaddr); - PSCB(vcpu,dtlb_pte) = mp_pte; + vcpu_set_tr_entry(&PSCBX(vcpu,dtlb),pte,ps<<2,vaddr); + PSCBX(vcpu,dtlb_pte) = mp_pte; } } @@ -1554,9 +1554,9 @@ unsigned long match_dtlb(VCPU *vcpu, unsigned long ifa, unsigned long *ps, unsig { TR_ENTRY *trp; - if (trp = vcpu_match_tr_entry(vcpu,&vcpu->vcpu_info->arch.dtlb,ifa,1)) { + if (trp = vcpu_match_tr_entry(vcpu,&vcpu->arch.dtlb,ifa,1)) { if (ps) *ps = trp->ps; - if (mp_pte) *mp_pte = vcpu->vcpu_info->arch.dtlb_pte; + if (mp_pte) *mp_pte = vcpu->arch.dtlb_pte; return (trp->page_flags); } return 0UL; @@ -1660,8 +1660,8 @@ IA64FAULT vcpu_ptc_e(VCPU *vcpu, UINT64 vadr) #endif local_flush_tlb_all(); // just invalidate the "whole" tlb - vcpu_purge_tr_entry(&PSCB(vcpu,dtlb)); - vcpu_purge_tr_entry(&PSCB(vcpu,itlb)); + vcpu_purge_tr_entry(&PSCBX(vcpu,dtlb)); + vcpu_purge_tr_entry(&PSCBX(vcpu,itlb)); return IA64_NO_FAULT; } @@ -1681,8 +1681,8 @@ IA64FAULT vcpu_ptc_ga(VCPU *vcpu,UINT64 vadr,UINT64 addr_range) vhpt_flush_address(vadr,addr_range); #endif ia64_global_tlb_purge(vadr,vadr+addr_range,PAGE_SHIFT); - vcpu_purge_tr_entry(&PSCB(vcpu,dtlb)); - vcpu_purge_tr_entry(&PSCB(vcpu,itlb)); + vcpu_purge_tr_entry(&PSCBX(vcpu,dtlb)); + vcpu_purge_tr_entry(&PSCBX(vcpu,itlb)); return IA64_NO_FAULT; } diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h index 6425368f51..619d450a00 100644 --- a/xen/include/asm-ia64/domain.h +++ b/xen/include/asm-ia64/domain.h @@ -37,10 +37,28 @@ struct arch_domain { #define shared_info_va arch.shared_info_va struct arch_exec_domain { +#if 1 + TR_ENTRY itrs[NITRS]; + TR_ENTRY dtrs[NDTRS]; + TR_ENTRY itlb; + TR_ENTRY dtlb; + unsigned long itlb_pte; + unsigned long dtlb_pte; + unsigned long irr[4]; + unsigned long insvc[4]; + unsigned long iva; + unsigned long dcr; + unsigned long itc; + unsigned long domain_itm; + unsigned long domain_itm_last; + unsigned long xen_itm; + unsigned long xen_timer_interval; +#endif void *regs; /* temporary until find a better way to do privops */ - struct thread_struct _thread; struct mm_struct *active_mm; + struct thread_struct _thread; // this must be last }; + #define active_mm arch.active_mm #define thread arch._thread diff --git a/xen/include/public/arch-ia64.h b/xen/include/public/arch-ia64.h index ad24299a0d..8c785d65d6 100644 --- a/xen/include/public/arch-ia64.h +++ b/xen/include/public/arch-ia64.h @@ -63,24 +63,8 @@ typedef struct { unsigned long bank1_regs[16]; // bank1 regs (r16-r31) when bank0 active unsigned long rrs[8]; // region registers unsigned long krs[8]; // kernel registers - unsigned long pkrs[8]; // protection key registers - // FIXME: These shouldn't be here as they can be overwritten by guests - // and validation at TLB miss time would be too expensive. - TR_ENTRY itrs[NITRS]; - TR_ENTRY dtrs[NDTRS]; - TR_ENTRY itlb; - TR_ENTRY dtlb; - unsigned long itlb_pte; - unsigned long dtlb_pte; - unsigned long irr[4]; - unsigned long insvc[4]; - unsigned long iva; - unsigned long dcr; - unsigned long itc; - unsigned long domain_itm; - unsigned long domain_itm_last; - unsigned long xen_itm; - unsigned long xen_timer_interval; + unsigned long pkrs[8]; // protection key registers + unsigned long tmp[8]; // temp registers (e.g. for hyperprivops) //} PACKED arch_shared_info_t; } arch_vcpu_info_t; // DON'T PACK From f69ab07dabd04fb419d9441347f776aa075f6040 Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Mon, 9 May 2005 23:30:20 +0000 Subject: [PATCH 30/54] bitkeeper revision 1.1389.9.4 (427ff28cpHTPvFmKde6BQbpMm2W-Qw) Add itc hyperprivop code and hyperprivop counters --- xen/arch/ia64/privop.c | 103 ++++++++++++++++++++++++++---------- xen/arch/ia64/process.c | 2 +- xen/arch/ia64/vcpu.c | 14 +++++ xen/include/asm-ia64/vcpu.h | 2 + 4 files changed, 92 insertions(+), 29 deletions(-) diff --git a/xen/arch/ia64/privop.c b/xen/arch/ia64/privop.c index c17adc5bde..f617d2d0b4 100644 --- a/xen/arch/ia64/privop.c +++ b/xen/arch/ia64/privop.c @@ -205,7 +205,8 @@ IA64FAULT priv_itc_d(VCPU *vcpu, INST64 inst) return(IA64_ILLOP_FAULT); if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT) return(IA64_ILLOP_FAULT); - pte = vcpu_get_gr(vcpu,inst.M41.r2); + if (!inst.inst) pte = vcpu_get_tmp(vcpu,0); + else pte = vcpu_get_gr(vcpu,inst.M41.r2); return (vcpu_itc_d(vcpu,pte,itir,ifa)); } @@ -219,7 +220,8 @@ IA64FAULT priv_itc_i(VCPU *vcpu, INST64 inst) return(IA64_ILLOP_FAULT); if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT) return(IA64_ILLOP_FAULT); - pte = vcpu_get_gr(vcpu,inst.M41.r2); + if (!inst.inst) pte = vcpu_get_tmp(vcpu,0); + else pte = vcpu_get_gr(vcpu,inst.M41.r2); return (vcpu_itc_i(vcpu,pte,itir,ifa)); } @@ -695,7 +697,7 @@ priv_handle_op(VCPU *vcpu, REGS *regs, int privlvl) //printf("We who are about do die salute you\n"); printf("handle_op: can't handle privop at 0x%lx (op=0x%016lx) slot %d (type=%d)\n", iip, (UINT64)inst.inst, slot, slot_type); - //printf("vtop(0x%lx)==0x%lx\r\n", iip, tr_vtop(iip)); + //printf("vtop(0x%lx)==0x%lx\n", iip, tr_vtop(iip)); //thread_mozambique("privop fault\n"); return (IA64_ILLOP_FAULT); } @@ -759,19 +761,37 @@ priv_emulate(VCPU *vcpu, REGS *regs, UINT64 isr) // FIXME: Move these to include/public/arch-ia64? -#define HYPERPRIVOP_RFI 1 -#define HYPERPRIVOP_RSM_DT 2 -#define HYPERPRIVOP_SSM_DT 3 -#define HYPERPRIVOP_COVER 4 +#define HYPERPRIVOP_RFI 0x1 +#define HYPERPRIVOP_RSM_DT 0x2 +#define HYPERPRIVOP_SSM_DT 0x3 +#define HYPERPRIVOP_COVER 0x4 +#define HYPERPRIVOP_ITC_D 0x5 +#define HYPERPRIVOP_ITC_I 0x6 +#define HYPERPRIVOP_MAX 0x6 + +char *hyperpriv_str[HYPERPRIVOP_MAX+1] = { + 0, "rfi", "rsm.dt", "ssm.dt", "cover", "itc.d", "itc.i", + 0 +}; + +unsigned long hyperpriv_cnt[HYPERPRIVOP_MAX+1] = { 0 }; /* hyperprivops are generally executed in assembly (with physical psr.ic off) * so this code is primarily used for debugging them */ int -ia64_hyperprivop(unsigned long iim) +ia64_hyperprivop(unsigned long iim, REGS *regs) { struct exec_domain *ed = (struct domain *) current; + INST64 inst; + UINT64 val; // FIXME: Add instrumentation for these +// FIXME: Handle faults appropriately for these + if (!iim || iim > HYPERPRIVOP_MAX) { + printf("bad hyperprivop; ignored\n"); + return 1; + } + hyperpriv_cnt[iim]++; switch(iim) { case HYPERPRIVOP_RFI: (void)vcpu_rfi(ed); @@ -785,6 +805,14 @@ ia64_hyperprivop(unsigned long iim) case HYPERPRIVOP_COVER: (void)vcpu_cover(ed); return 1; + case HYPERPRIVOP_ITC_D: + inst.inst = 0; + (void)priv_itc_d(ed,inst); + return 1; + case HYPERPRIVOP_ITC_I: + inst.inst = 0; + (void)priv_itc_i(ed,inst); + return 1; } return 0; } @@ -843,61 +871,61 @@ int dump_privop_counts(char *buf) sum += privcnt.rfi; sum += privcnt.bsw0; sum += privcnt.bsw1; sum += privcnt.cover; for (i=0; i < 64; i++) sum += privcnt.Mpriv_cnt[i]; - s += sprintf(s,"Privop statistics: (Total privops: %ld)\r\n",sum); + s += sprintf(s,"Privop statistics: (Total privops: %ld)\n",sum); if (privcnt.mov_to_ar_imm) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.mov_to_ar_imm, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.mov_to_ar_imm, "mov_to_ar_imm", (privcnt.mov_to_ar_imm*100L)/sum); if (privcnt.mov_to_ar_reg) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.mov_to_ar_reg, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.mov_to_ar_reg, "mov_to_ar_reg", (privcnt.mov_to_ar_reg*100L)/sum); if (privcnt.mov_from_ar) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.mov_from_ar, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.mov_from_ar, "privified-mov_from_ar", (privcnt.mov_from_ar*100L)/sum); if (privcnt.ssm) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.ssm, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.ssm, "ssm", (privcnt.ssm*100L)/sum); if (privcnt.rsm) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.rsm, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.rsm, "rsm", (privcnt.rsm*100L)/sum); if (privcnt.rfi) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.rfi, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.rfi, "rfi", (privcnt.rfi*100L)/sum); if (privcnt.bsw0) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.bsw0, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.bsw0, "bsw0", (privcnt.bsw0*100L)/sum); if (privcnt.bsw1) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.bsw1, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.bsw1, "bsw1", (privcnt.bsw1*100L)/sum); if (privcnt.cover) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.cover, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.cover, "cover", (privcnt.cover*100L)/sum); if (privcnt.fc) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.fc, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.fc, "privified-fc", (privcnt.fc*100L)/sum); if (privcnt.cpuid) - s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.cpuid, + s += sprintf(s,"%10d %s [%d%%]\n", privcnt.cpuid, "privified-getcpuid", (privcnt.cpuid*100L)/sum); for (i=0; i < 64; i++) if (privcnt.Mpriv_cnt[i]) { - if (!Mpriv_str[i]) s += sprintf(s,"PRIVSTRING NULL!!\r\n"); - else s += sprintf(s,"%10d %s [%d%%]\r\n", privcnt.Mpriv_cnt[i], + if (!Mpriv_str[i]) s += sprintf(s,"PRIVSTRING NULL!!\n"); + else s += sprintf(s,"%10d %s [%d%%]\n", privcnt.Mpriv_cnt[i], Mpriv_str[i], (privcnt.Mpriv_cnt[i]*100L)/sum); if (i == 0x24) { // mov from CR s += sprintf(s," ["); for (j=0; j < 128; j++) if (from_cr_cnt[j]) { if (!cr_str[j]) - s += sprintf(s,"PRIVSTRING NULL!!\r\n"); + s += sprintf(s,"PRIVSTRING NULL!!\n"); s += sprintf(s,"%s(%d),",cr_str[j],from_cr_cnt[j]); } - s += sprintf(s,"]\r\n"); + s += sprintf(s,"]\n"); } else if (i == 0x2c) { // mov to CR s += sprintf(s," ["); for (j=0; j < 128; j++) if (to_cr_cnt[j]) { if (!cr_str[j]) - s += sprintf(s,"PRIVSTRING NULL!!\r\n"); + s += sprintf(s,"PRIVSTRING NULL!!\n"); s += sprintf(s,"%s(%d),",cr_str[j],to_cr_cnt[j]); } - s += sprintf(s,"]\r\n"); + s += sprintf(s,"]\n"); } } return s - buf; @@ -919,7 +947,7 @@ int zero_privop_counts(char *buf) for (i=0; i < 64; i++) privcnt.Mpriv_cnt[i] = 0; for (j=0; j < 128; j++) from_cr_cnt[j] = 0; for (j=0; j < 128; j++) to_cr_cnt[j] = 0; - s += sprintf(s,"All privop statistics zeroed\r\n"); + s += sprintf(s,"All privop statistics zeroed\n"); return s - buf; } @@ -943,7 +971,7 @@ int dump_privop_addrs(char *buf) { int i,j; char *s = buf; - s += sprintf(s,"Privop addresses:\r\n"); + s += sprintf(s,"Privop addresses:\n"); for (i = 0; i < PRIVOP_COUNT_NINSTS; i++) { struct privop_addr_count *v = &privop_addr_counter[i]; s += sprintf(s,"%s:\n",v->instname); @@ -969,12 +997,30 @@ void zero_privop_addrs(void) } #endif +int dump_hyperprivop_counts(char *buf) +{ + int i; + char *s = buf; + s += sprintf(s,"Hyperprivops:\n"); + for (i = 1; i <= HYPERPRIVOP_MAX; i++) + if (hyperpriv_cnt[i]) + s += sprintf("%10d %s\n", + hyperpriv_cnt[i], hyperpriv_str[i]); +} + +void zero_hyperprivop_counts(void) +{ + int i; + for (i = 0; i <= HYPERPRIVOP_MAX; i++) hyperpriv_cnt[i] = 0; +} + #define TMPBUFLEN 8*1024 int dump_privop_counts_to_user(char __user *ubuf, int len) { char buf[TMPBUFLEN]; int n = dump_privop_counts(buf); + n += dump_hyperprivop_counts(buf + n); #ifdef PRIVOP_ADDR_COUNT n += dump_privop_addrs(buf + n); #endif @@ -988,6 +1034,7 @@ int zero_privop_counts_to_user(char __user *ubuf, int len) char buf[TMPBUFLEN]; int n = zero_privop_counts(buf); + zero_hyperprivop_counts(); #ifdef PRIVOP_ADDR_COUNT zero_privop_addrs(); #endif diff --git a/xen/arch/ia64/process.c b/xen/arch/ia64/process.c index 985ba7cbed..1e0c10f53f 100644 --- a/xen/arch/ia64/process.c +++ b/xen/arch/ia64/process.c @@ -724,7 +724,7 @@ ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, u vcpu_increment_iip(current); } else if (!PSCB(ed,interrupt_collection_enabled)) { - if (ia64_hyperprivop(iim)) + if (ia64_hyperprivop(iim,regs)) vcpu_increment_iip(current); } else reflect_interruption(ifa,isr,iim,regs,IA64_BREAK_VECTOR); diff --git a/xen/arch/ia64/vcpu.c b/xen/arch/ia64/vcpu.c index c46e7c48d8..29b20a4df0 100644 --- a/xen/arch/ia64/vcpu.c +++ b/xen/arch/ia64/vcpu.c @@ -848,6 +848,20 @@ IA64FAULT vcpu_set_cmcv(VCPU *vcpu, UINT64 val) return (IA64_NO_FAULT); } +/************************************************************************** + VCPU temporary register access routines +**************************************************************************/ +UINT64 vcpu_get_tmp(VCPU *vcpu, UINT64 index) +{ + if (index > 7) return 0; + return PSCB(vcpu,tmp[index]); +} + +void vcpu_set_tmp(VCPU *vcpu, UINT64 index, UINT64 val) +{ + if (index <= 7) PSCB(vcpu,tmp[index]) = val; +} + /************************************************************************** Interval timer routines **************************************************************************/ diff --git a/xen/include/asm-ia64/vcpu.h b/xen/include/asm-ia64/vcpu.h index e3bcfbde79..bb24bad2b2 100644 --- a/xen/include/asm-ia64/vcpu.h +++ b/xen/include/asm-ia64/vcpu.h @@ -147,6 +147,8 @@ extern void vcpu_set_next_timer(VCPU *vcpu); extern BOOLEAN vcpu_timer_expired(VCPU *vcpu); extern UINT64 vcpu_deliverable_interrupts(VCPU *vcpu); extern void vcpu_itc_no_srlz(VCPU *vcpu, UINT64, UINT64, UINT64, UINT64, UINT64); +extern UINT64 vcpu_get_tmp(VCPU *, UINT64); +extern void vcpu_set_tmp(VCPU *, UINT64, UINT64); #endif From de36879421e4facb7ac26f428626a58dec887969 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 10 May 2005 09:54:46 +0000 Subject: [PATCH 31/54] bitkeeper revision 1.1389.5.40 (428084e6OcTkByL6plgj4UPN6alYkA) Fix the 64-bit build. Signed-off-by: Keir Fraser --- .rootkeys | 1 + xen/arch/x86/acpi/boot.c | 5 +- xen/arch/x86/mm.c | 10 +- xen/arch/x86/mpparse.c | 2 +- xen/arch/x86/shadow.c | 13 +- xen/common/sched_sedf.c | 53 ++--- xen/include/asm-x86/bitops.h | 1 + xen/include/asm-x86/x86_32/domain_page.h | 49 +++-- xen/include/asm-x86/x86_64/domain_page.h | 8 + xen/include/xen/inttypes.h | 251 +++++++++++++++++++++++ xen/include/xen/lib.h | 1 + 11 files changed, 333 insertions(+), 61 deletions(-) create mode 100644 xen/include/xen/inttypes.h diff --git a/.rootkeys b/.rootkeys index f742604409..8ae8c05f21 100644 --- a/.rootkeys +++ b/.rootkeys @@ -1450,6 +1450,7 @@ 3ddb79c1W0lQca8gRV7sN6j3iY4Luw xen/include/xen/event.h 41262590CyJy4vd42dnqzsn8-eeGvw xen/include/xen/grant_table.h 3ddb79c0GurNF9tDWqQbAwJFH8ugfA xen/include/xen/init.h +428084e41zemtCAtYLcD9bUzwE35SA xen/include/xen/inttypes.h 3ddb79c1nzaWu8NoF4xCCMSFJR4MlA xen/include/xen/ioport.h 3ddb79c2qAxCOABlkKtD8Txohe-qEw xen/include/xen/irq.h 3ddb79c2b3qe-6Ann09FqZBF4IrJaQ xen/include/xen/irq_cpustat.h diff --git a/xen/arch/x86/acpi/boot.c b/xen/arch/x86/acpi/boot.c index 971b3d352c..184d10af9b 100644 --- a/xen/arch/x86/acpi/boot.c +++ b/xen/arch/x86/acpi/boot.c @@ -44,7 +44,6 @@ int sbf_port; /* XXX XEN */ static inline void acpi_madt_oem_check(char *oem_id, char *oem_table_id) { } extern void __init clustered_apic_check(void); static inline int ioapic_setup_disabled(void) { return 0; } -#include #else /* X86 */ @@ -110,7 +109,7 @@ char *__acpi_map_table(unsigned long phys_addr, unsigned long size) if (!phys_addr || !size) return NULL; - if (phys_addr < (end_pfn_map << PAGE_SHIFT)) + if (phys_addr < (max_page << PAGE_SHIFT)) return __va(phys_addr); return NULL; @@ -155,7 +154,7 @@ char *__acpi_map_table(unsigned long phys, unsigned long size) mapped_size += PAGE_SIZE; } - return ((unsigned char *) base + offset); + return ((char *) base + offset); } #endif diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 2f4356477a..f62ab9c91d 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -1813,8 +1813,7 @@ int do_mmu_update( struct exec_domain *ed = current; struct domain *d = ed->domain; u32 type_info; - struct map_dom_mem_cache mapcache = MAP_DOM_MEM_CACHE_INIT; - struct map_dom_mem_cache sh_mapcache = MAP_DOM_MEM_CACHE_INIT; + struct map_dom_mem_cache mapcache, sh_mapcache; LOCK_BIGLOCK(d); @@ -1830,6 +1829,9 @@ int do_mmu_update( (void)get_user(done, pdone); } + init_map_domain_mem_cache(&mapcache); + init_map_domain_mem_cache(&sh_mapcache); + if ( !set_foreigndom(cpu, foreigndom) ) { rc = -EINVAL; @@ -2037,8 +2039,8 @@ int do_mmu_update( } out: - unmap_domain_mem_cache(&mapcache); - unmap_domain_mem_cache(&sh_mapcache); + destroy_map_domain_mem_cache(&mapcache); + destroy_map_domain_mem_cache(&sh_mapcache); process_deferred_ops(cpu); diff --git a/xen/arch/x86/mpparse.c b/xen/arch/x86/mpparse.c index 39a7619edc..09a55805e1 100644 --- a/xen/arch/x86/mpparse.c +++ b/xen/arch/x86/mpparse.c @@ -690,7 +690,7 @@ void __init get_smp_config (void) * Read the physical hardware table. Anything here will * override the defaults. */ - if (!smp_read_mpc((void *)mpf->mpf_physptr)) { + if (!smp_read_mpc((void *)(unsigned long)mpf->mpf_physptr)) { smp_found_config = 0; printk(KERN_ERR "BIOS bug, MP table errors detected!...\n"); printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n"); diff --git a/xen/arch/x86/shadow.c b/xen/arch/x86/shadow.c index 5e06fd1464..788c3fc6b9 100644 --- a/xen/arch/x86/shadow.c +++ b/xen/arch/x86/shadow.c @@ -808,12 +808,15 @@ alloc_p2m_table(struct domain *d) struct pfn_info *page, *l2page; l2_pgentry_t *l2; unsigned long mfn, pfn; - struct map_dom_mem_cache l2cache = MAP_DOM_MEM_CACHE_INIT; - struct map_dom_mem_cache l1cache = MAP_DOM_MEM_CACHE_INIT; + struct map_dom_mem_cache l1cache, l2cache; l2page = alloc_domheap_page(NULL); - if ( !l2page ) + if ( l2page == NULL ) return 0; + + init_map_domain_mem_cache(&l1cache); + init_map_domain_mem_cache(&l2cache); + d->arch.phys_table = mk_pagetable(page_to_phys(l2page)); l2 = map_domain_mem_with_cache(page_to_phys(l2page), &l2cache); memset(l2, 0, PAGE_SIZE); @@ -848,8 +851,8 @@ alloc_p2m_table(struct domain *d) list_ent = page->list.next; } - unmap_domain_mem_cache(&l2cache); - unmap_domain_mem_cache(&l1cache); + destroy_map_domain_mem_cache(&l2cache); + destroy_map_domain_mem_cache(&l1cache); return 1; } diff --git a/xen/common/sched_sedf.c b/xen/common/sched_sedf.c index e10c7783b8..6bd8b5a0be 100644 --- a/xen/common/sched_sedf.c +++ b/xen/common/sched_sedf.c @@ -1,4 +1,4 @@ -/******************************************************************************* +/****************************************************************************** * Simple EDF scheduler for xen * * by Stephan Diestelhorst (C) 2004 Cambridge University @@ -180,9 +180,10 @@ static inline void extraq_add_sort_update(struct exec_domain *d, int i, int sub) struct sedf_edom_info *curinf; ASSERT(!extraq_on(d,i)); - PRINT(3, "Adding domain %i.%i (score= %i, short_pen= %lli) to L%i "\ - "extraq\n", d->domain->id, d->id, EDOM_INFO(d)->score[i], - EDOM_INFO(d)->short_block_lost_tot, i); + PRINT(3, "Adding domain %i.%i (score= %i, short_pen= %"PRIi64")" + " to L%i extraq\n", + d->domain->id, d->id, EDOM_INFO(d)->score[i], + EDOM_INFO(d)->short_block_lost_tot, i); /*iterate through all elements to find our "hole" and on our way update all the other scores*/ list_for_each(cur,EXTRAQ(d->processor,i)){ @@ -266,8 +267,8 @@ static inline void __del_from_queue(struct exec_domain *d) { struct list_head *list = LIST(d); ASSERT(__task_on_queue(d)); - PRINT(3,"Removing domain %i.%i (bop= %llu) from runq/waitq\n", d->domain->id, - d->id, PERIOD_BEGIN(EDOM_INFO(d))); + PRINT(3,"Removing domain %i.%i (bop= %"PRIu64") from runq/waitq\n", + d->domain->id, d->id, PERIOD_BEGIN(EDOM_INFO(d))); list_del(list); list->next = NULL; ASSERT(!__task_on_queue(d)); @@ -307,8 +308,8 @@ int name##_comp(struct list_head* el1, struct list_head* el2) \ DOMAIN_COMPARER(waitq, list, PERIOD_BEGIN(d1), PERIOD_BEGIN(d2)) static inline void __add_to_waitqueue_sort(struct exec_domain *d) { ASSERT(!__task_on_queue(d)); - PRINT(3,"Adding domain %i.%i (bop= %llu) to waitq\n", d->domain->id, - d->id, PERIOD_BEGIN(EDOM_INFO(d))); + PRINT(3,"Adding domain %i.%i (bop= %"PRIu64") to waitq\n", + d->domain->id, d->id, PERIOD_BEGIN(EDOM_INFO(d))); list_insert_sort(WAITQ(d->processor), LIST(d), waitq_comp); ASSERT(__task_on_queue(d)); } @@ -320,8 +321,8 @@ static inline void __add_to_waitqueue_sort(struct exec_domain *d) { */ DOMAIN_COMPARER(runq, list, d1->deadl_abs, d2->deadl_abs) static inline void __add_to_runqueue_sort(struct exec_domain *d) { - PRINT(3,"Adding domain %i.%i (deadl= %llu) to runq\n", d->domain->id, - d->id, EDOM_INFO(d)->deadl_abs); + PRINT(3,"Adding domain %i.%i (deadl= %"PRIu64") to runq\n", + d->domain->id, d->id, EDOM_INFO(d)->deadl_abs); list_insert_sort(RUNQ(d->processor), LIST(d), runq_comp); } @@ -530,9 +531,9 @@ struct list_head* waitq) { /*we missed the deadline or the slice was already finished... might hapen because of dom_adj.*/ - PRINT(4,"\tDomain %i.%i exceeded it's deadline/"\ - "slice (%llu / %llu) now: %llu "\ - "cputime: %llu\n", + PRINT(4,"\tDomain %i.%i exceeded it's deadline/" + "slice (%"PRIu64" / %"PRIu64") now: %"PRIu64 + " cputime: %"PRIu64"\n", curinf->exec_domain->domain->id, curinf->exec_domain->id, curinf->deadl_abs, curinf->slice, now, @@ -599,7 +600,7 @@ static inline void desched_extra_dom(s_time_t now, struct exec_domain* d) { /*reduce block lost, probably more sophistication here!*/ /*inf->short_block_lost_tot -= EXTRA_QUANTUM;*/ inf->short_block_lost_tot -= now - inf->sched_start_abs; - PRINT(3,"Domain %i.%i: Short_block_loss: %lli\n", + PRINT(3,"Domain %i.%i: Short_block_loss: %"PRIi64"\n", inf->exec_domain->domain->id, inf->exec_domain->id, inf->short_block_lost_tot); if (inf->short_block_lost_tot <= 0) { @@ -796,7 +797,7 @@ sched_done: /*TODO: Do something USEFUL when this happens and find out, why it still can happen!!!*/ if (ret.time<0) { - printk("Ouch! We are seriously BEHIND schedule! %lli\n", + printk("Ouch! We are seriously BEHIND schedule! %"PRIi64"\n", ret.time); ret.time = EXTRA_QUANTUM; } @@ -1158,8 +1159,8 @@ void sedf_wake(struct exec_domain *d) { /*initial setup of the deadline*/ inf->deadl_abs = now + inf->slice; - PRINT(3,"waking up domain %i.%i (deadl= %llu period= %llu "\ - "now= %llu)\n", d->domain->id, d->id, inf->deadl_abs, + PRINT(3,"waking up domain %i.%i (deadl= %"PRIu64" period= %"PRIu64" "\ + "now= %"PRIu64")\n", d->domain->id, d->id, inf->deadl_abs, inf->period, now); #ifdef SEDF_STATS inf->block_tot++; @@ -1220,8 +1221,8 @@ void sedf_wake(struct exec_domain *d) { extraq_check_add_unblocked(d, 1); } } - PRINT(3,"woke up domain %i.%i (deadl= %llu period= %llu "\ - "now= %llu)\n", d->domain->id, d->id, inf->deadl_abs, + PRINT(3,"woke up domain %i.%i (deadl= %"PRIu64" period= %"PRIu64" "\ + "now= %"PRIu64")\n", d->domain->id, d->id, inf->deadl_abs, inf->period, now); if (PERIOD_BEGIN(inf) > now) { __add_to_waitqueue_sort(d); @@ -1258,21 +1259,21 @@ void sedf_wake(struct exec_domain *d) { static void sedf_dump_domain(struct exec_domain *d) { printk("%i.%i has=%c ", d->domain->id, d->id, test_bit(EDF_RUNNING, &d->flags) ? 'T':'F'); - printk("p=%llu sl=%llu ddl=%llu w=%hu c=%llu sc=%i xtr(%s)=%llu ew=%hu", + printk("p=%"PRIu64" sl=%"PRIu64" ddl=%"PRIu64" w=%hu c=%"PRIu64" sc=%i xtr(%s)=%"PRIu64" ew=%hu", EDOM_INFO(d)->period, EDOM_INFO(d)->slice, EDOM_INFO(d)->deadl_abs, EDOM_INFO(d)->weight, d->cpu_time, EDOM_INFO(d)->score[EXTRA_UTIL_Q], (EDOM_INFO(d)->status & EXTRA_AWARE) ? "yes" : "no", EDOM_INFO(d)->extra_time_tot, EDOM_INFO(d)->extraweight); if (d->cpu_time !=0) - printf(" (%llu%%)", (EDOM_INFO(d)->extra_time_tot * 100) + printf(" (%"PRIu64"%%)", (EDOM_INFO(d)->extra_time_tot * 100) / d->cpu_time); #ifdef SEDF_STATS if (EDOM_INFO(d)->block_time_tot!=0) - printf(" pen=%llu%%", (EDOM_INFO(d)->penalty_time_tot * 100) / + printf(" pen=%"PRIu64"%%", (EDOM_INFO(d)->penalty_time_tot * 100) / EDOM_INFO(d)->block_time_tot); if (EDOM_INFO(d)->block_tot!=0) printf("\n blks=%u sh=%u (%u%%) (shc=%u (%u%%) shex=%i "\ - "shexsl=%i) l=%u (%u%%) avg: b=%llu p=%llu", + "shexsl=%i) l=%u (%u%%) avg: b=%"PRIu64" p=%"PRIu64"", EDOM_INFO(d)->block_tot, EDOM_INFO(d)->short_block_tot, (EDOM_INFO(d)->short_block_tot * 100) / EDOM_INFO(d)->block_tot, EDOM_INFO(d)->short_cont, @@ -1296,7 +1297,7 @@ static void sedf_dump_cpu_state(int i) struct exec_domain *ed; int loop = 0; - printk("now=%llu\n",NOW()); + printk("now=%"PRIu64"\n",NOW()); queue = RUNQ(i); printk("RUNQ rq %lx n: %lx, p: %lx\n", (unsigned long)queue, (unsigned long) queue->next, (unsigned long) queue->prev); @@ -1396,8 +1397,8 @@ static inline int sedf_adjust_weights(struct sched_adjdom_cmd *cmd) { static int sedf_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd) { struct exec_domain *ed; - PRINT(2,"sedf_adjdom was called, domain-id %i new period %llu "\ - "new slice %llu\nlatency %llu extra:%s\n", + PRINT(2,"sedf_adjdom was called, domain-id %i new period %"PRIu64" "\ + "new slice %"PRIu64"\nlatency %"PRIu64" extra:%s\n", p->id, cmd->u.sedf.period, cmd->u.sedf.slice, cmd->u.sedf.latency, (cmd->u.sedf.extratime)?"yes":"no"); if ( cmd->direction == SCHED_INFO_PUT ) diff --git a/xen/include/asm-x86/bitops.h b/xen/include/asm-x86/bitops.h index cf98f2e118..2337197670 100644 --- a/xen/include/asm-x86/bitops.h +++ b/xen/include/asm-x86/bitops.h @@ -368,6 +368,7 @@ static __inline__ unsigned long find_first_set_bit(unsigned long word) * The Hamming Weight of a number is the total number of bits set in it. */ +#define hweight64(x) generic_hweight64(x) #define hweight32(x) generic_hweight32(x) #define hweight16(x) generic_hweight16(x) #define hweight8(x) generic_hweight8(x) diff --git a/xen/include/asm-x86/x86_32/domain_page.h b/xen/include/asm-x86/x86_32/domain_page.h index 0220de530e..b0ffad43a4 100644 --- a/xen/include/asm-x86/x86_32/domain_page.h +++ b/xen/include/asm-x86/x86_32/domain_page.h @@ -33,40 +33,45 @@ struct map_dom_mem_cache { #define MAP_DOM_MEM_CACHE_INIT { .pa = 0 } -static inline void * -map_domain_mem_with_cache(unsigned long pa, - struct map_dom_mem_cache *cache) +static inline void +init_map_domain_mem_cache(struct map_dom_mem_cache *cache) { - if ( likely(cache != NULL) ) + ASSERT(cache != NULL); + *cache = MAP_DOM_MEM_CACHE_INIT; +} + +static inline void * +map_domain_mem_with_cache(unsigned long pa, struct map_dom_mem_cache *cache) +{ + ASSERT(cache != NULL); + + if ( likely(cache->pa) ) { - if ( likely(cache->pa) ) - { - if ( likely((pa & PAGE_MASK) == (cache->pa & PAGE_MASK)) ) - goto done; - unmap_domain_mem(cache->va); - } - cache->pa = (pa & PAGE_MASK) | 1; - cache->va = map_domain_mem(cache->pa); - done: - return (void *)(((unsigned long)cache->va & PAGE_MASK) | - (pa & ~PAGE_MASK)); + if ( likely((pa & PAGE_MASK) == (cache->pa & PAGE_MASK)) ) + goto done; + unmap_domain_mem(cache->va); } - return map_domain_mem(pa); + cache->pa = (pa & PAGE_MASK) | 1; + cache->va = map_domain_mem(cache->pa); + + done: + return (void *)(((unsigned long)cache->va & PAGE_MASK) | + (pa & ~PAGE_MASK)); } static inline void -unmap_domain_mem_with_cache(void *va, - struct map_dom_mem_cache *cache) +unmap_domain_mem_with_cache(void *va, struct map_dom_mem_cache *cache) { - if ( unlikely(!cache) ) - unmap_domain_mem(va); + ASSERT(cache != NULL); + unmap_domain_mem(va); } static inline void -unmap_domain_mem_cache(struct map_dom_mem_cache *cache) +destroy_map_domain_mem_cache(struct map_dom_mem_cache *cache) { - if ( likely(cache != NULL) && likely(cache->pa) ) + ASSERT(cache != NULL); + if ( likely(cache->pa) ) { unmap_domain_mem(cache->va); cache->pa = 0; diff --git a/xen/include/asm-x86/x86_64/domain_page.h b/xen/include/asm-x86/x86_64/domain_page.h index 8a6081cde4..2a59fb1e5e 100644 --- a/xen/include/asm-x86/x86_64/domain_page.h +++ b/xen/include/asm-x86/x86_64/domain_page.h @@ -10,4 +10,12 @@ #define map_domain_mem(_pa) phys_to_virt(_pa) #define unmap_domain_mem(_va) ((void)(_va)) +struct map_dom_mem_cache { +}; + +#define init_map_domain_mem_cache(_c) ((void)(_c)) +#define map_domain_mem_with_cache(_p,_c) (map_domain_mem(_p)) +#define unmap_domain_mem_with_cache(_v,_c) ((void)(_v)) +#define destroy_map_domain_mem_cache(_c) ((void)(_c)) + #endif /* __ASM_DOMAIN_PAGE_H__ */ diff --git a/xen/include/xen/inttypes.h b/xen/include/xen/inttypes.h new file mode 100644 index 0000000000..2163244326 --- /dev/null +++ b/xen/include/xen/inttypes.h @@ -0,0 +1,251 @@ +/* Copyright (C) 1997-2001, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* + * ISO C99: 7.8 Format conversion of integer types + */ + +#ifndef _XEN_INTTYPES_H +#define _XEN_INTTYPES_H 1 + +#include +#include + +# if BITS_PER_LONG == 64 +# define __PRI64_PREFIX "l" +# define __PRIPTR_PREFIX "l" +# else +# define __PRI64_PREFIX "ll" +# define __PRIPTR_PREFIX +# endif + +/* Macros for printing format specifiers. */ + +/* Decimal notation. */ +# define PRId8 "d" +# define PRId16 "d" +# define PRId32 "d" +# define PRId64 __PRI64_PREFIX "d" + +# define PRIdLEAST8 "d" +# define PRIdLEAST16 "d" +# define PRIdLEAST32 "d" +# define PRIdLEAST64 __PRI64_PREFIX "d" + +# define PRIdFAST8 "d" +# define PRIdFAST16 __PRIPTR_PREFIX "d" +# define PRIdFAST32 __PRIPTR_PREFIX "d" +# define PRIdFAST64 __PRI64_PREFIX "d" + + +# define PRIi8 "i" +# define PRIi16 "i" +# define PRIi32 "i" +# define PRIi64 __PRI64_PREFIX "i" + +# define PRIiLEAST8 "i" +# define PRIiLEAST16 "i" +# define PRIiLEAST32 "i" +# define PRIiLEAST64 __PRI64_PREFIX "i" + +# define PRIiFAST8 "i" +# define PRIiFAST16 __PRIPTR_PREFIX "i" +# define PRIiFAST32 __PRIPTR_PREFIX "i" +# define PRIiFAST64 __PRI64_PREFIX "i" + +/* Octal notation. */ +# define PRIo8 "o" +# define PRIo16 "o" +# define PRIo32 "o" +# define PRIo64 __PRI64_PREFIX "o" + +# define PRIoLEAST8 "o" +# define PRIoLEAST16 "o" +# define PRIoLEAST32 "o" +# define PRIoLEAST64 __PRI64_PREFIX "o" + +# define PRIoFAST8 "o" +# define PRIoFAST16 __PRIPTR_PREFIX "o" +# define PRIoFAST32 __PRIPTR_PREFIX "o" +# define PRIoFAST64 __PRI64_PREFIX "o" + +/* Unsigned integers. */ +# define PRIu8 "u" +# define PRIu16 "u" +# define PRIu32 "u" +# define PRIu64 __PRI64_PREFIX "u" + +# define PRIuLEAST8 "u" +# define PRIuLEAST16 "u" +# define PRIuLEAST32 "u" +# define PRIuLEAST64 __PRI64_PREFIX "u" + +# define PRIuFAST8 "u" +# define PRIuFAST16 __PRIPTR_PREFIX "u" +# define PRIuFAST32 __PRIPTR_PREFIX "u" +# define PRIuFAST64 __PRI64_PREFIX "u" + +/* lowercase hexadecimal notation. */ +# define PRIx8 "x" +# define PRIx16 "x" +# define PRIx32 "x" +# define PRIx64 __PRI64_PREFIX "x" + +# define PRIxLEAST8 "x" +# define PRIxLEAST16 "x" +# define PRIxLEAST32 "x" +# define PRIxLEAST64 __PRI64_PREFIX "x" + +# define PRIxFAST8 "x" +# define PRIxFAST16 __PRIPTR_PREFIX "x" +# define PRIxFAST32 __PRIPTR_PREFIX "x" +# define PRIxFAST64 __PRI64_PREFIX "x" + +/* UPPERCASE hexadecimal notation. */ +# define PRIX8 "X" +# define PRIX16 "X" +# define PRIX32 "X" +# define PRIX64 __PRI64_PREFIX "X" + +# define PRIXLEAST8 "X" +# define PRIXLEAST16 "X" +# define PRIXLEAST32 "X" +# define PRIXLEAST64 __PRI64_PREFIX "X" + +# define PRIXFAST8 "X" +# define PRIXFAST16 __PRIPTR_PREFIX "X" +# define PRIXFAST32 __PRIPTR_PREFIX "X" +# define PRIXFAST64 __PRI64_PREFIX "X" + + +/* Macros for printing `intmax_t' and `uintmax_t'. */ +# define PRIdMAX __PRI64_PREFIX "d" +# define PRIiMAX __PRI64_PREFIX "i" +# define PRIoMAX __PRI64_PREFIX "o" +# define PRIuMAX __PRI64_PREFIX "u" +# define PRIxMAX __PRI64_PREFIX "x" +# define PRIXMAX __PRI64_PREFIX "X" + + +/* Macros for printing `intptr_t' and `uintptr_t'. */ +# define PRIdPTR __PRIPTR_PREFIX "d" +# define PRIiPTR __PRIPTR_PREFIX "i" +# define PRIoPTR __PRIPTR_PREFIX "o" +# define PRIuPTR __PRIPTR_PREFIX "u" +# define PRIxPTR __PRIPTR_PREFIX "x" +# define PRIXPTR __PRIPTR_PREFIX "X" + + +/* Macros for scanning format specifiers. */ + +/* Signed decimal notation. */ +# define SCNd8 "hhd" +# define SCNd16 "hd" +# define SCNd32 "d" +# define SCNd64 __PRI64_PREFIX "d" + +# define SCNdLEAST8 "hhd" +# define SCNdLEAST16 "hd" +# define SCNdLEAST32 "d" +# define SCNdLEAST64 __PRI64_PREFIX "d" + +# define SCNdFAST8 "hhd" +# define SCNdFAST16 __PRIPTR_PREFIX "d" +# define SCNdFAST32 __PRIPTR_PREFIX "d" +# define SCNdFAST64 __PRI64_PREFIX "d" + +/* Signed decimal notation. */ +# define SCNi8 "hhi" +# define SCNi16 "hi" +# define SCNi32 "i" +# define SCNi64 __PRI64_PREFIX "i" + +# define SCNiLEAST8 "hhi" +# define SCNiLEAST16 "hi" +# define SCNiLEAST32 "i" +# define SCNiLEAST64 __PRI64_PREFIX "i" + +# define SCNiFAST8 "hhi" +# define SCNiFAST16 __PRIPTR_PREFIX "i" +# define SCNiFAST32 __PRIPTR_PREFIX "i" +# define SCNiFAST64 __PRI64_PREFIX "i" + +/* Unsigned decimal notation. */ +# define SCNu8 "hhu" +# define SCNu16 "hu" +# define SCNu32 "u" +# define SCNu64 __PRI64_PREFIX "u" + +# define SCNuLEAST8 "hhu" +# define SCNuLEAST16 "hu" +# define SCNuLEAST32 "u" +# define SCNuLEAST64 __PRI64_PREFIX "u" + +# define SCNuFAST8 "hhu" +# define SCNuFAST16 __PRIPTR_PREFIX "u" +# define SCNuFAST32 __PRIPTR_PREFIX "u" +# define SCNuFAST64 __PRI64_PREFIX "u" + +/* Octal notation. */ +# define SCNo8 "hho" +# define SCNo16 "ho" +# define SCNo32 "o" +# define SCNo64 __PRI64_PREFIX "o" + +# define SCNoLEAST8 "hho" +# define SCNoLEAST16 "ho" +# define SCNoLEAST32 "o" +# define SCNoLEAST64 __PRI64_PREFIX "o" + +# define SCNoFAST8 "hho" +# define SCNoFAST16 __PRIPTR_PREFIX "o" +# define SCNoFAST32 __PRIPTR_PREFIX "o" +# define SCNoFAST64 __PRI64_PREFIX "o" + +/* Hexadecimal notation. */ +# define SCNx8 "hhx" +# define SCNx16 "hx" +# define SCNx32 "x" +# define SCNx64 __PRI64_PREFIX "x" + +# define SCNxLEAST8 "hhx" +# define SCNxLEAST16 "hx" +# define SCNxLEAST32 "x" +# define SCNxLEAST64 __PRI64_PREFIX "x" + +# define SCNxFAST8 "hhx" +# define SCNxFAST16 __PRIPTR_PREFIX "x" +# define SCNxFAST32 __PRIPTR_PREFIX "x" +# define SCNxFAST64 __PRI64_PREFIX "x" + + +/* Macros for scanning `intmax_t' and `uintmax_t'. */ +# define SCNdMAX __PRI64_PREFIX "d" +# define SCNiMAX __PRI64_PREFIX "i" +# define SCNoMAX __PRI64_PREFIX "o" +# define SCNuMAX __PRI64_PREFIX "u" +# define SCNxMAX __PRI64_PREFIX "x" + +/* Macros for scaning `intptr_t' and `uintptr_t'. */ +# define SCNdPTR __PRIPTR_PREFIX "d" +# define SCNiPTR __PRIPTR_PREFIX "i" +# define SCNoPTR __PRIPTR_PREFIX "o" +# define SCNuPTR __PRIPTR_PREFIX "u" +# define SCNxPTR __PRIPTR_PREFIX "x" + +#endif /* _XEN_INTTYPES_H */ diff --git a/xen/include/xen/lib.h b/xen/include/xen/lib.h index 91c34ce232..b8a981a632 100644 --- a/xen/include/xen/lib.h +++ b/xen/include/xen/lib.h @@ -1,6 +1,7 @@ #ifndef __LIB_H__ #define __LIB_H__ +#include #include #include #include From 17a7536bd9527ee840b0f07edd85f8a753f20a92 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 10 May 2005 10:02:28 +0000 Subject: [PATCH 32/54] bitkeeper revision 1.1389.5.41 (428086b4WGIdNR8TJaRkbtDcDMeorg) Fix the 32-bit build (broken by previous changeset). Signed-off-by: Keir Fraser --- xen/arch/x86/Makefile | 1 + xen/include/asm-x86/x86_32/domain_page.h | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index ddb605e9cf..dfc64ddf9c 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -35,6 +35,7 @@ clean: rm -f x86_32/*.o x86_32/*~ x86_32/core rm -f x86_64/*.o x86_64/*~ x86_64/core rm -f mtrr/*.o mtrr/*~ mtrr/core + rm -f acpi/*.o acpi/*~ acpi/core delete-unfresh-files: # nothing diff --git a/xen/include/asm-x86/x86_32/domain_page.h b/xen/include/asm-x86/x86_32/domain_page.h index b0ffad43a4..7ebb72eb72 100644 --- a/xen/include/asm-x86/x86_32/domain_page.h +++ b/xen/include/asm-x86/x86_32/domain_page.h @@ -31,13 +31,11 @@ struct map_dom_mem_cache { void *va; }; -#define MAP_DOM_MEM_CACHE_INIT { .pa = 0 } - static inline void init_map_domain_mem_cache(struct map_dom_mem_cache *cache) { ASSERT(cache != NULL); - *cache = MAP_DOM_MEM_CACHE_INIT; + cache->pa = 0; } static inline void * From f172606a1ab710715cf782369cacf97fa94adb95 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Tue, 10 May 2005 10:19:53 +0000 Subject: [PATCH 33/54] bitkeeper revision 1.1389.11.1 (42808ac9uy5txhByMBPYs1-aOPf9YA) Kconfig: Disable IRQBALANCE for now since there's no re-route pirq's in Xen yet. Signed-off-by: Christian Limpach --- linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig b/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig index 3ed45ade7b..8d64f00930 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/Kconfig @@ -636,7 +636,7 @@ config MTRR config IRQBALANCE bool "Enable kernel irq balancing" - depends on SMP && X86_IO_APIC + depends on SMP && X86_IO_APIC && !XEN default y help The default yes will allow the kernel to do irq load balancing. From 46966baa2b86ad110539d53a9887050fb63abb18 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 10 May 2005 10:52:14 +0000 Subject: [PATCH 34/54] bitkeeper revision 1.1389.12.1 (4280925ekcX_kR7M1jSOr7hTahPv2A) Remove asm/pci.h. Signed-off-by: Keir Fraser --- .rootkeys | 1 - xen/arch/x86/setup.c | 8 -------- xen/include/asm-x86/pci.h | 35 ----------------------------------- xen/include/xen/pci.h | 4 ---- 4 files changed, 48 deletions(-) delete mode 100644 xen/include/asm-x86/pci.h diff --git a/.rootkeys b/.rootkeys index 8ae8c05f21..064cb3d7d0 100644 --- a/.rootkeys +++ b/.rootkeys @@ -1376,7 +1376,6 @@ 41aaf567Mi3OishhvrCtET1y-mxQBg xen/include/asm-x86/mtrr.h 41a61536MFhNalgbVmYGXAhQsPTZNw xen/include/asm-x86/multicall.h 3ddb79c3xjYnrv5t3VqYlR4tNEOl4Q xen/include/asm-x86/page.h -3ddb79c3ysKUbxZuwKBRK3WXU2TlEg xen/include/asm-x86/pci.h 42422fb0FVX-TJkSvAXnbfwMf19XFA xen/include/asm-x86/physdev.h 3ddb79c2QF5-pZGzuX4QukPCDAl59A xen/include/asm-x86/processor.h 40cf1596bim9F9DNdV75klgRSZ6Y2A xen/include/asm-x86/regs.h diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 37cc2c4684..f4967e9317 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -341,12 +341,8 @@ static void __init do_initcalls(void) (*call)(); } -unsigned long pci_mem_start = 0x10000000; - static void __init start_of_day(void) { - unsigned long low_mem_size; - #ifdef MEMORY_GUARD /* Unmap the first page of CPU0's stack. */ extern unsigned long cpu0_stack[]; @@ -362,10 +358,6 @@ static void __init start_of_day(void) arch_do_createdomain(current); - /* Tell the PCI layer not to allocate too close to the RAM area.. */ - low_mem_size = ((max_page << PAGE_SHIFT) + 0xfffff) & ~0xfffff; - if ( low_mem_size > pci_mem_start ) pci_mem_start = low_mem_size; - identify_cpu(&boot_cpu_data); /* get CPU type info */ if ( cpu_has_fxsr ) set_in_cr4(X86_CR4_OSFXSR); if ( cpu_has_xmm ) set_in_cr4(X86_CR4_OSXMMEXCPT); diff --git a/xen/include/asm-x86/pci.h b/xen/include/asm-x86/pci.h deleted file mode 100644 index c5f72c0fae..0000000000 --- a/xen/include/asm-x86/pci.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __X86_PCI_H -#define __X86_PCI_H - -#include - -/* Can be used to override the logic in pci_scan_bus for skipping - already-configured bus numbers - to be used for buggy BIOSes - or architectures with incomplete PCI setup by the loader */ - -#ifdef CONFIG_PCI -extern unsigned int pcibios_assign_all_busses(void); -#else -#define pcibios_assign_all_busses() 0 -#endif -#define pcibios_scan_all_fns(a,b) 0 - -extern unsigned long pci_mem_start; -#define PCIBIOS_MIN_IO 0x1000 -#define PCIBIOS_MIN_MEM (pci_mem_start) - -void pcibios_config_init(void); -struct pci_bus * pcibios_scan_root(int bus); -extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value); -extern int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value); - -void pcibios_set_master(struct pci_dev *dev); -void pcibios_penalize_isa_irq(int irq); -struct irq_routing_table *pcibios_get_irq_routing_table(void); -int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq); - -#include -#include -#include - -#endif /* __X86_PCI_H */ diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h index 5f8740a31c..046328d11e 100644 --- a/xen/include/xen/pci.h +++ b/xen/include/xen/pci.h @@ -678,10 +678,6 @@ void pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t addr); #endif /* CONFIG_PCI */ -/* Include architecture-dependent settings and functions */ - -#include - /* * If the system does not have PCI, clearly these return errors. Define * these as simple inline functions to avoid hair in drivers. From 95ff68cdc7aebe0879930129c4b10e73e84b6ff6 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 10 May 2005 10:53:03 +0000 Subject: [PATCH 35/54] bitkeeper revision 1.1389.5.44 (4280928fXpCA_GX9SyUz9gLg1XVEVw) Fix x86/64 bootup. Signed-off-by: Keir Fraser --- xen/arch/x86/mpparse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/arch/x86/mpparse.c b/xen/arch/x86/mpparse.c index 09a55805e1..83d93ef3e6 100644 --- a/xen/arch/x86/mpparse.c +++ b/xen/arch/x86/mpparse.c @@ -725,7 +725,7 @@ void __init get_smp_config (void) static int __init smp_scan_config (unsigned long base, unsigned long length) { - unsigned long *bp = phys_to_virt(base); + unsigned int *bp = phys_to_virt(base); struct intel_mp_floating *mpf; Dprintk("Scan SMP from %p for %ld bytes.\n", bp,length); From 8874ef8c82454b3dced8b9bba1ead4da556af27e Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 10 May 2005 10:53:32 +0000 Subject: [PATCH 36/54] bitkeeper revision 1.1389.5.45 (428092ac-yDbfUH2hZkDdl0sU-Sv8Q) Various cleanups. Signed-off-by: Keir Fraser --- xen/arch/x86/io_apic.c | 37 +------------------------------ xen/arch/x86/mtrr/main.c | 1 + xen/arch/x86/traps.c | 5 +++-- xen/arch/x86/x86_32/asm-offsets.c | 2 +- xen/arch/x86/x86_32/mm.c | 2 +- xen/arch/x86/x86_64/mm.c | 2 +- xen/include/asm-x86/fixmap.h | 23 +------------------ 7 files changed, 9 insertions(+), 63 deletions(-) diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c index 929117c95c..3e7c89cf0e 100644 --- a/xen/arch/x86/io_apic.c +++ b/xen/arch/x86/io_apic.c @@ -1233,7 +1233,6 @@ static inline void UNEXPECTED_IO_APIC(void) void __init print_IO_APIC(void) { -#ifndef NDEBUG int apic, i; union IO_APIC_reg_00 reg_00; union IO_APIC_reg_01 reg_01; @@ -1377,7 +1376,7 @@ void __init print_IO_APIC(void) } printk(KERN_INFO ".................................... done.\n"); -#endif /* !NDEBUG */ + return; } @@ -1830,26 +1829,6 @@ static struct hw_interrupt_type lapic_irq_type = { .end = end_lapic_irq }; -#if 0 -static void setup_nmi (void) -{ - /* - * Dirty trick to enable the NMI watchdog ... - * We put the 8259A master into AEOI mode and - * unmask on all local APICs LVT0 as NMI. - * - * The idea to use the 8259A in AEOI mode ('8259A Virtual Wire') - * is from Maciej W. Rozycki - so we do not have to EOI from - * the NMI handler or the timer interrupt. - */ - apic_printk(APIC_VERBOSE, KERN_INFO "activating NMI Watchdog ..."); - - on_each_cpu(enable_NMI_through_LVT0, NULL, 1, 1); - - apic_printk(APIC_VERBOSE, " done.\n"); -} -#endif - /* * This looks a bit hackish but it's about the only one way of sending * a few INTA cycles to 8259As and any associated glue logic. ICR does @@ -1953,14 +1932,6 @@ static inline void check_timer(void) */ unmask_IO_APIC_irq(0); if (timer_irq_works()) { -#if 0 - if (nmi_watchdog == NMI_IO_APIC) { - disable_8259A_irq(0); - setup_nmi(); - enable_8259A_irq(0); - check_nmi_watchdog(); - } -#endif return; } clear_IO_APIC_pin(0, pin1); @@ -1980,12 +1951,6 @@ static inline void check_timer(void) replace_pin_at_irq(0, 0, pin1, 0, pin2); else add_pin_to_irq(0, 0, pin2); -#if 0 - if (nmi_watchdog == NMI_IO_APIC) { - setup_nmi(); - check_nmi_watchdog(); - } -#endif return; } /* diff --git a/xen/arch/x86/mtrr/main.c b/xen/arch/x86/mtrr/main.c index 02b4b46004..b7c4713c69 100644 --- a/xen/arch/x86/mtrr/main.c +++ b/xen/arch/x86/mtrr/main.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index bdb15968bb..52bd64ac9b 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -115,7 +115,8 @@ asmlinkage void fatal_trap(int trapnr, struct cpu_user_regs *regs) if ( trapnr == TRAP_page_fault ) { __asm__ __volatile__ ("mov %%cr2,%0" : "=r" (cr2) : ); - printk("Faulting linear address might be %p\n", _p(cr2)); + printk("Faulting linear address: %p\n", _p(cr2)); + show_page_walk(cr2); } printk("************************************\n"); @@ -349,7 +350,7 @@ asmlinkage int do_page_fault(struct cpu_user_regs *regs) show_page_walk(addr); panic("CPU%d FATAL PAGE FAULT\n" "[error_code=%04x]\n" - "Faulting linear address might be %p\n", + "Faulting linear address: %p\n", smp_processor_id(), regs->error_code, addr); return 0; } diff --git a/xen/arch/x86/x86_32/asm-offsets.c b/xen/arch/x86/x86_32/asm-offsets.c index b440b0501e..7015b2a861 100644 --- a/xen/arch/x86/x86_32/asm-offsets.c +++ b/xen/arch/x86/x86_32/asm-offsets.c @@ -90,7 +90,7 @@ void __dummy__(void) OFFSET(MULTICALL_result, multicall_entry_t, args[5]); BLANK(); - DEFINE(FIXMAP_apic_base, __fix_to_virt(FIX_APIC_BASE)); + DEFINE(FIXMAP_apic_base, fix_to_virt(FIX_APIC_BASE)); BLANK(); DEFINE(IRQSTAT_shift, LOG_2(sizeof(irq_cpustat_t))); diff --git a/xen/arch/x86/x86_32/mm.c b/xen/arch/x86/x86_32/mm.c index e88195a8e1..045d904c21 100644 --- a/xen/arch/x86/x86_32/mm.c +++ b/xen/arch/x86/x86_32/mm.c @@ -83,7 +83,7 @@ void __set_fixmap( { if ( unlikely(idx >= __end_of_fixed_addresses) ) BUG(); - map_pages(idle_pg_table, __fix_to_virt(idx), p, PAGE_SIZE, flags); + map_pages(idle_pg_table, fix_to_virt(idx), p, PAGE_SIZE, flags); } diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c index 3becac2024..a1db5acd05 100644 --- a/xen/arch/x86/x86_64/mm.c +++ b/xen/arch/x86/x86_64/mm.c @@ -125,7 +125,7 @@ void __set_fixmap( { if ( unlikely(idx >= __end_of_fixed_addresses) ) BUG(); - map_pages(idle_pg_table, __fix_to_virt(idx), p, PAGE_SIZE, flags); + map_pages(idle_pg_table, fix_to_virt(idx), p, PAGE_SIZE, flags); } diff --git a/xen/include/asm-x86/fixmap.h b/xen/include/asm-x86/fixmap.h index d2d8ef183e..c70b2a8b01 100644 --- a/xen/include/asm-x86/fixmap.h +++ b/xen/include/asm-x86/fixmap.h @@ -56,28 +56,7 @@ extern void __set_fixmap( #define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) #define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT) -extern void __this_fixmap_does_not_exist(void); - -/* - * 'index to address' translation. If anyone tries to use the idx - * directly without translation, we catch the bug with a NULL-deference - * kernel oops. Illegal ranges of incoming indices are caught too. - */ -static always_inline unsigned long fix_to_virt(const unsigned int idx) -{ - /* - * This branch gets completely eliminated after inlining, except when - * someone tries to use fixaddr indices in an illegal way (such as mixing - * up address types or using out-of-range indices). - * - * If it doesn't get removed, the linker will complain loudly with a - * reasonably clear error message. - */ - if (idx >= __end_of_fixed_addresses) - __this_fixmap_does_not_exist(); - - return __fix_to_virt(idx); -} +#define fix_to_virt(x) (__fix_to_virt(x)) static inline unsigned long virt_to_fix(const unsigned long vaddr) { From e8c69a1186c72df781589144180009f711845619 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 10 May 2005 11:05:32 +0000 Subject: [PATCH 37/54] bitkeeper revision 1.1389.5.46 (4280957c13dvEVUuixaYEHltnt6E1A) Fix ACPI initialisation. Signed-off-by: Keir Fraser --- xen/arch/x86/setup.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index f4967e9317..ac659a52de 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -77,12 +77,7 @@ unsigned long wait_init_idle; struct exec_domain *idle_task[NR_CPUS] = { &idle0_exec_domain }; -#ifdef CONFIG_ACPI_INTERPRETER -int acpi_disabled = 0; -#else -int acpi_disabled = 1; -#endif -EXPORT_SYMBOL(acpi_disabled); +int acpi_disabled; int phys_proc_id[NR_CPUS]; int logical_proc_id[NR_CPUS]; @@ -375,7 +370,10 @@ static void __init start_of_day(void) #endif paging_init(); /* not much here now, but sets up fixmap */ if ( !opt_noacpi ) + { + acpi_boot_table_init(); acpi_boot_init(); + } #ifdef CONFIG_SMP if ( smp_found_config ) get_smp_config(); From 63c60c630f4a770a5380bee8df85daab20ef984d Mon Sep 17 00:00:00 2001 From: "mafetter@fleming.research" Date: Tue, 10 May 2005 11:15:11 +0000 Subject: [PATCH 38/54] bitkeeper revision 1.1389.13.1 (428097bfFCQnxc6PG1CYe-6KhZD8kA) Minor shadow code improvements. --- xen/arch/x86/shadow.c | 43 ++++++++++++++++-------------------- xen/common/perfc.c | 1 + xen/include/asm-x86/shadow.h | 22 ++++++++---------- 3 files changed, 29 insertions(+), 37 deletions(-) diff --git a/xen/arch/x86/shadow.c b/xen/arch/x86/shadow.c index 5e06fd1464..9769e060c1 100644 --- a/xen/arch/x86/shadow.c +++ b/xen/arch/x86/shadow.c @@ -1898,37 +1898,34 @@ void shadow_mark_va_out_of_sync( * Returns 0 otherwise. */ static int snapshot_entry_matches( - struct exec_domain *ed, unsigned long gmfn, unsigned index) + struct domain *d, l1_pgentry_t *guest_pt, + unsigned long gpfn, unsigned index) { - unsigned long gpfn = __mfn_to_gpfn(ed->domain, gmfn); - unsigned long smfn = __shadow_status(ed->domain, gpfn, PGT_snapshot); - unsigned long *guest, *snapshot; - int compare; - - ASSERT( ! IS_INVALID_M2P_ENTRY(gpfn) ); + unsigned long smfn = __shadow_status(d, gpfn, PGT_snapshot); + l1_pgentry_t *snapshot; // could be L1s or L2s or ... + int entries_match; perfc_incrc(snapshot_entry_matches_calls); if ( !smfn ) return 0; - guest = map_domain_mem(gmfn << PAGE_SHIFT); snapshot = map_domain_mem(smfn << PAGE_SHIFT); // This could probably be smarter, but this is sufficent for // our current needs. // - compare = (guest[index] == snapshot[index]); + entries_match = !l1e_has_changed(&guest_pt[index], &snapshot[index], + PAGE_FLAG_MASK); - unmap_domain_mem(guest); unmap_domain_mem(snapshot); #ifdef PERF_COUNTERS - if ( compare ) + if ( entries_match ) perfc_incrc(snapshot_entry_matches_true); #endif - return compare; + return entries_match; } /* @@ -1939,37 +1936,35 @@ int __shadow_out_of_sync(struct exec_domain *ed, unsigned long va) { struct domain *d = ed->domain; unsigned long l2mfn = pagetable_get_pfn(ed->arch.guest_table); + unsigned long l2pfn = __mfn_to_gpfn(d, l2mfn); l2_pgentry_t l2e; - unsigned long l1mfn; + unsigned long l1pfn, l1mfn; ASSERT(spin_is_locked(&d->arch.shadow_lock)); + ASSERT(VALID_M2P(l2pfn)); perfc_incrc(shadow_out_of_sync_calls); - // PERF BUG: snapshot_entry_matches will call map_domain_mem() on the l2 - // page, but it's already available at ed->arch.guest_vtable... - // Ditto for the sl2 page and ed->arch.shadow_vtable. - // if ( page_out_of_sync(&frame_table[l2mfn]) && - !snapshot_entry_matches(ed, l2mfn, l2_table_offset(va)) ) + !snapshot_entry_matches(d, (l1_pgentry_t *)ed->arch.guest_vtable, + l2pfn, l2_table_offset(va)) ) return 1; __guest_get_l2e(ed, va, &l2e); if ( !(l2e_get_flags(l2e) & _PAGE_PRESENT) ) return 0; - l1mfn = __gpfn_to_mfn(d, l2e_get_pfn(l2e)); + l1pfn = l2e_get_pfn(l2e); + l1mfn = __gpfn_to_mfn(d, l1pfn); // If the l1 pfn is invalid, it can't be out of sync... if ( !VALID_MFN(l1mfn) ) return 0; - // PERF BUG: snapshot_entry_matches will call map_domain_mem() on the l1 - // page, but it's already available at linear_pg_table[l1_linear_offset()]. - // Ditto for the sl1 page and shadow_linear_pg_table[]... - // if ( page_out_of_sync(&frame_table[l1mfn]) && - !snapshot_entry_matches(ed, l1mfn, l1_table_offset(va)) ) + !snapshot_entry_matches( + d, &linear_pg_table[l1_linear_offset(va) & ~(L1_PAGETABLE_ENTRIES-1)], + l1pfn, l1_table_offset(va)) ) return 1; return 0; diff --git a/xen/common/perfc.c b/xen/common/perfc.c index 14ac09af41..f98910c91c 100644 --- a/xen/common/perfc.c +++ b/xen/common/perfc.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h index 3871cca08d..d991a51f93 100644 --- a/xen/include/asm-x86/shadow.h +++ b/xen/include/asm-x86/shadow.h @@ -518,9 +518,9 @@ update_hl2e(struct exec_domain *ed, unsigned long va) else new_hl2e = l1e_empty(); - // only do the ref counting if something important changed. + // only do the ref counting if something has changed. // - if ( (l1e_has_changed(&old_hl2e, &new_hl2e, _PAGE_PRESENT)) ) + if ( (l1e_has_changed(&old_hl2e, &new_hl2e, PAGE_FLAG_MASK)) ) { if ( (l1e_get_flags(new_hl2e) & _PAGE_PRESENT) && !shadow_get_page(ed->domain, pfn_to_page(l1e_get_pfn(new_hl2e)), @@ -531,14 +531,15 @@ update_hl2e(struct exec_domain *ed, unsigned long va) shadow_put_page(ed->domain, pfn_to_page(l1e_get_pfn(old_hl2e))); need_flush = 1; } - } - ed->arch.hl2_vtable[l2_table_offset(va)] = new_hl2e; + ed->arch.hl2_vtable[l2_table_offset(va)] = new_hl2e; - if ( need_flush ) - { - perfc_incrc(update_hl2e_invlpg); - local_flush_tlb_one(&linear_pg_table[l1_linear_offset(va)]); + if ( need_flush ) + { + perfc_incrc(update_hl2e_invlpg); + // SMP BUG??? + local_flush_tlb_one(&linear_pg_table[l1_linear_offset(va)]); + } } } @@ -1501,11 +1502,6 @@ shadow_set_l1e(unsigned long va, l1_pgentry_t new_spte, int create_l1_shadow) struct domain *d = ed->domain; l2_pgentry_t sl2e; -#if 0 - printk("shadow_set_l1e(va=%p, new_spte=%p, create=%d)\n", - va, l1e_get_value(new_spte), create_l1_shadow); -#endif - __shadow_get_l2e(ed, va, &sl2e); if ( !(l2e_get_flags(sl2e) & _PAGE_PRESENT) ) { From de17f86b3ba78f3e69a88501de448fbfbbaeedf1 Mon Sep 17 00:00:00 2001 From: "mafetter@fleming.research" Date: Tue, 10 May 2005 11:32:50 +0000 Subject: [PATCH 39/54] bitkeeper revision 1.1389.5.48 (42809be2MsF_yD6mn_kF4ZL-8OJjkA) Fix ASSERT() caused by cleanup to map_domain_mem_with_cache() changes. --- xen/arch/x86/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index f62ab9c91d..d355b7e9af 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -1992,7 +1992,7 @@ int do_mmu_update( printk("privileged guest dom%d requests pfn=%lx to map mfn=%lx for dom%d\n", d->id, gpfn, mfn, FOREIGNDOM->id); set_machinetophys(mfn, gpfn); - set_p2m_entry(FOREIGNDOM, gpfn, mfn, NULL, NULL); + set_p2m_entry(FOREIGNDOM, gpfn, mfn, &sh_mapcache, &mapcache); okay = 1; shadow_unlock(FOREIGNDOM); break; From 46d5b271ad939669420098821b4b38e5b8d858b6 Mon Sep 17 00:00:00 2001 From: "mafetter@fleming.research" Date: Tue, 10 May 2005 12:41:09 +0000 Subject: [PATCH 40/54] bitkeeper revision 1.1389.5.49 (4280abe5EW2fJtuPr5_E283AlKrziQ) Added back the printing of perfc arrays & histograms, under compile-time control in xen/Rules.mk --- xen/Rules.mk | 4 ++++ xen/common/perfc.c | 8 ++++++++ xen/include/xen/perfc.h | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/xen/Rules.mk b/xen/Rules.mk index 1fb12e8479..1db12a3d0d 100644 --- a/xen/Rules.mk +++ b/xen/Rules.mk @@ -2,6 +2,7 @@ verbose ?= n debug ?= n perfc ?= n +perfc_arrays?= n trace ?= n optimize ?= y domu_debug ?= n @@ -54,6 +55,9 @@ endif ifeq ($(perfc),y) CFLAGS += -DPERF_COUNTERS +ifeq ($(perfc_arrays),y) +CFLAGS += -DPERF_ARRAYS +endif endif ifeq ($(trace),y) diff --git a/xen/common/perfc.c b/xen/common/perfc.c index f98910c91c..157d49ffc8 100644 --- a/xen/common/perfc.c +++ b/xen/common/perfc.c @@ -67,6 +67,14 @@ void perfc_printall(unsigned char key) for ( j = sum = 0; j < perfc_info[i].nr_elements; j++ ) sum += atomic_read(&counters[j]); printk("TOTAL[%10d] ", sum); +#ifdef PERF_ARRAYS + for ( j = 0; j < perfc_info[i].nr_elements; j++ ) + { + if ( (j != 0) && ((j % 4) == 0) ) + printk("\n "); + printk("ARR%02d[%10d] ", j, atomic_read(&counters[j])); + } +#endif counters += j; break; } diff --git a/xen/include/xen/perfc.h b/xen/include/xen/perfc.h index 6d758497b1..48c7e90fb4 100644 --- a/xen/include/xen/perfc.h +++ b/xen/include/xen/perfc.h @@ -87,6 +87,7 @@ extern struct perfcounter perfcounters; * Histogram: special treatment for 0 and 1 count. After that equally spaced * with last bucket taking the rest. */ +#ifdef PERFC_ARRAYS #define perfc_incr_histo(_x,_v,_n) \ do { \ if ( (_v) == 0 ) \ @@ -99,6 +100,9 @@ extern struct perfcounter perfcounters; else \ perfc_incra(_x, PERFC_MAX_ ## _n - 1); \ } while ( 0 ) +#else +#define perfc_incr_histo(_x,_v,_n) ((void)0) +#endif #else /* PERF_COUNTERS */ From dd53aba2e73aa348d6f026e9c324590678908a87 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Tue, 10 May 2005 13:03:18 +0000 Subject: [PATCH 41/54] bitkeeper revision 1.1389.14.1 (4280b116_nJbXsZ9VQ4cosX8Wdyi9g) boot.c: acpi_scan_rsdp's parameters are (start, len) and not (start, end). Signed-off-by: Christian Limpach --- xen/arch/x86/acpi/boot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/arch/x86/acpi/boot.c b/xen/arch/x86/acpi/boot.c index 184d10af9b..7237d5e7e2 100644 --- a/xen/arch/x86/acpi/boot.c +++ b/xen/arch/x86/acpi/boot.c @@ -647,7 +647,7 @@ acpi_find_rsdp (void) */ rsdp_phys = acpi_scan_rsdp (0, 0x400); if (!rsdp_phys) - rsdp_phys = acpi_scan_rsdp (0xE0000, 0xFFFFF); + rsdp_phys = acpi_scan_rsdp (0xE0000, 0x20000); return rsdp_phys; } From 97995e1d4268953147afb348f6725b0734b89c03 Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Tue, 10 May 2005 13:31:06 +0000 Subject: [PATCH 42/54] bitkeeper revision 1.1389.14.2 (4280b79axJTjlpP4pLQJ2vgfWKJ0og) smpboot_hooks.h, smpboot.c: Also setup IO APIC when running an SMP guest. Signed-off-by: Christian Limpach --- linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c | 2 ++ .../include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h | 4 ---- .../include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h | 4 ---- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c index ec1b3b9dea..bbe0963942 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c @@ -1267,9 +1267,11 @@ static void __init smp_boot_cpus(unsigned int max_cpus) #if 0 if (nmi_watchdog == NMI_LOCAL_APIC) check_nmi_watchdog(); +#endif smpboot_setup_io_apic(); +#if 0 setup_boot_APIC_clock(); /* diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h index 421a81f17b..7479f82686 100644 --- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h +++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h @@ -43,16 +43,12 @@ static inline void smpboot_restore_warm_reset_vector(void) static inline void smpboot_setup_io_apic(void) { -#if 1 - printk("smpboot_setup_io_apic\n"); -#else /* * Here we can be sure that there is an IO-APIC in the system. Let's * go and set it up: */ if (!skip_ioapic_setup && nr_ioapics) setup_IO_APIC(); -#endif } diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h b/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h index 421a81f17b..7479f82686 100644 --- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h +++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h @@ -43,16 +43,12 @@ static inline void smpboot_restore_warm_reset_vector(void) static inline void smpboot_setup_io_apic(void) { -#if 1 - printk("smpboot_setup_io_apic\n"); -#else /* * Here we can be sure that there is an IO-APIC in the system. Let's * go and set it up: */ if (!skip_ioapic_setup && nr_ioapics) setup_IO_APIC(); -#endif } From fcf68acc05db177103ebb71725b554dc153ca9ce Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Tue, 10 May 2005 13:40:14 +0000 Subject: [PATCH 43/54] bitkeeper revision 1.1389.5.52 (4280b9beG5xwTCb0TZxrZ0Cx_ku3fQ) smpboot.c: start_secondary doesn't return anything. Dprintk gets defined in apic.h now. Signed-off-by: Christian Limpach --- linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c index bbe0963942..05ca6a3ee7 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c @@ -51,11 +51,6 @@ #include #include -#if 1 -#define Dprintk(args...) -#else -#include -#endif #include #include @@ -462,7 +457,7 @@ extern void local_setup_timer(void); /* * Activate a secondary processor. */ -static int __init start_secondary(void *unused) +static void __init start_secondary(void *unused) { /* * Dont put anything before smp_callin(), SMP From a580e140f1c78f9c17f4cc59c29eb2f8b96a4dab Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Tue, 10 May 2005 13:44:26 +0000 Subject: [PATCH 44/54] bitkeeper revision 1.1389.5.53 (4280babaOVGp0TTc52Yvwumwfwdgzw) io_apic.c: Cleanup whitespace. Signed-off-by: Christian Limpach --- linux-2.6.11-xen-sparse/arch/xen/i386/kernel/io_apic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/io_apic.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/io_apic.c index 6fbaa19613..882ff3fe9c 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/io_apic.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/io_apic.c @@ -726,6 +726,7 @@ void fastcall send_IPI_self(int vector) } #endif /* !CONFIG_SMP */ + /* * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to * specific CPU-side IRQs. From a89c09bba1810cb28e091d0ebf1b2b7539a95d0a Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 10 May 2005 14:48:37 +0000 Subject: [PATCH 45/54] bitkeeper revision 1.1389.15.2 (4280c9c5w05qWQmSXarelhI1f8FZkQ) Fix level-triggered IOAPIC acknowledgement. Also a first pass at supporting PCI-MSI notifications in Xen. I think we can support these better with some interface changes in Xen. It's currently rather a kludge. Signed-off-by: Keir Fraser --- xen/arch/ia64/irq.c | 23 - xen/arch/x86/acpi/boot.c | 42 -- xen/arch/x86/io_apic.c | 493 ++---------------- xen/arch/x86/irq.c | 62 +-- xen/arch/x86/physdev.c | 11 +- xen/include/asm-x86/io_apic.h | 38 -- .../asm-x86/mach-default/irq_vectors_limits.h | 15 +- xen/include/xen/irq.h | 1 - 8 files changed, 77 insertions(+), 608 deletions(-) diff --git a/xen/arch/ia64/irq.c b/xen/arch/ia64/irq.c index 1b4e277343..2ce076e324 100644 --- a/xen/arch/ia64/irq.c +++ b/xen/arch/ia64/irq.c @@ -1468,29 +1468,6 @@ int pirq_guest_unbind(struct domain *d, int irq) spin_unlock_irqrestore(&desc->lock, flags); return 0; } - -int pirq_guest_bindable(int irq, int will_share) -{ - irq_desc_t *desc = &irq_desc[irq]; - irq_guest_action_t *action; - unsigned long flags; - int okay; - - spin_lock_irqsave(&desc->lock, flags); - - action = (irq_guest_action_t *)desc->action; - - /* - * To be bindable the IRQ must either be not currently bound (1), or - * it must be shareable (2) and not at its share limit (3). - */ - okay = ((!(desc->status & IRQ_GUEST) && (action == NULL)) || /* 1 */ - (action->shareable && will_share && /* 2 */ - (action->nr_guests != IRQ_MAX_GUESTS))); /* 3 */ - - spin_unlock_irqrestore(&desc->lock, flags); - return okay; -} #endif #ifdef XEN diff --git a/xen/arch/x86/acpi/boot.c b/xen/arch/x86/acpi/boot.c index 7237d5e7e2..ad3d043138 100644 --- a/xen/arch/x86/acpi/boot.c +++ b/xen/arch/x86/acpi/boot.c @@ -447,44 +447,6 @@ acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) #endif /* CONFIG_ACPI_BUS */ -int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) -{ -#ifdef CONFIG_X86_IO_APIC - if (use_pci_vector() && !platform_legacy_irq(gsi)) - *irq = IO_APIC_VECTOR(gsi); - else -#endif - *irq = gsi; - return 0; -} - -unsigned int acpi_register_gsi(u32 gsi, int edge_level, int active_high_low) -{ - unsigned int irq; - unsigned int plat_gsi = gsi; - -#ifdef CONFIG_PCI - /* - * Make sure all (legacy) PCI IRQs are set as level-triggered. - */ - if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) { - extern void eisa_set_level_irq(unsigned int irq); - - if (edge_level == ACPI_LEVEL_SENSITIVE) - eisa_set_level_irq(gsi); - } -#endif - -#ifdef CONFIG_X86_IO_APIC - if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) { - plat_gsi = mp_register_gsi(gsi, edge_level, active_high_low); - } -#endif - acpi_gsi_to_irq(plat_gsi, &irq); - return irq; -} -EXPORT_SYMBOL(acpi_register_gsi); - /* * ACPI based hotplug support for CPU */ @@ -856,10 +818,6 @@ acpi_boot_table_init(void) return error; } -#if 0 /*def __i386__*/ - check_acpi_pci(); -#endif - acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); /* diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c index 3e7c89cf0e..2b485a1fe1 100644 --- a/xen/arch/x86/io_apic.c +++ b/xen/arch/x86/io_apic.c @@ -64,12 +64,8 @@ static struct irq_pin_list { } irq_2_pin[PIN_MAP_SIZE]; int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; -#ifdef CONFIG_PCI_MSI #define vector_to_irq(vector) \ (platform_legacy_irq(vector) ? vector : vector_irq[vector]) -#else -#define vector_to_irq(vector) (vector) -#endif /* * The common case is 1:1 IRQ<->pin mappings. Sometimes there are @@ -145,16 +141,16 @@ static void __unmask_IO_APIC_irq (unsigned int irq) __modify_IO_APIC_irq(irq, 0, 0x00010000); } -/* mask = 1, trigger = 0 */ -static void __mask_and_edge_IO_APIC_irq (unsigned int irq) +/* trigger = 0 */ +static void __edge_IO_APIC_irq (unsigned int irq) { - __modify_IO_APIC_irq(irq, 0x00010000, 0x00008000); + __modify_IO_APIC_irq(irq, 0, 0x00008000); } -/* mask = 0, trigger = 1 */ -static void __unmask_and_level_IO_APIC_irq (unsigned int irq) +/* trigger = 1 */ +static void __level_IO_APIC_irq (unsigned int irq) { - __modify_IO_APIC_irq(irq, 0x00008000, 0x00010000); + __modify_IO_APIC_irq(irq, 0x00008000, 0); } static void mask_IO_APIC_irq (unsigned int irq) @@ -231,423 +227,6 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) spin_unlock_irqrestore(&ioapic_lock, flags); } -#if defined(CONFIG_IRQBALANCE) -# include /* kernel_thread() */ -# include /* kstat */ -# include /* kmalloc() */ -# include /* time_after() */ - -# ifdef CONFIG_BALANCED_IRQ_DEBUG -# define TDprintk(x...) do { printk("<%ld:%s:%d>: ", jiffies, __FILE__, __LINE__); printk(x); } while (0) -# define Dprintk(x...) do { TDprintk(x); } while (0) -# else -# define TDprintk(x...) -# define Dprintk(x...) -# endif - -cpumask_t __cacheline_aligned pending_irq_balance_cpumask[NR_IRQS]; - -#define IRQBALANCE_CHECK_ARCH -999 -static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH; -static int physical_balance = 0; - -struct irq_cpu_info { - unsigned long * last_irq; - unsigned long * irq_delta; - unsigned long irq; -} irq_cpu_data[NR_CPUS]; - -#define CPU_IRQ(cpu) (irq_cpu_data[cpu].irq) -#define LAST_CPU_IRQ(cpu,irq) (irq_cpu_data[cpu].last_irq[irq]) -#define IRQ_DELTA(cpu,irq) (irq_cpu_data[cpu].irq_delta[irq]) - -#define IDLE_ENOUGH(cpu,now) \ - (idle_cpu(cpu) && ((now) - irq_stat[(cpu)].idle_timestamp > 1)) - -#define IRQ_ALLOWED(cpu, allowed_mask) cpu_isset(cpu, allowed_mask) - -#define CPU_TO_PACKAGEINDEX(i) (first_cpu(cpu_sibling_map[i])) - -#define MAX_BALANCED_IRQ_INTERVAL (5*HZ) -#define MIN_BALANCED_IRQ_INTERVAL (HZ/2) -#define BALANCED_IRQ_MORE_DELTA (HZ/10) -#define BALANCED_IRQ_LESS_DELTA (HZ) - -long balanced_irq_interval = MAX_BALANCED_IRQ_INTERVAL; - -static unsigned long move(int curr_cpu, cpumask_t allowed_mask, - unsigned long now, int direction) -{ - int search_idle = 1; - int cpu = curr_cpu; - - goto inside; - - do { - if (unlikely(cpu == curr_cpu)) - search_idle = 0; -inside: - if (direction == 1) { - cpu++; - if (cpu >= NR_CPUS) - cpu = 0; - } else { - cpu--; - if (cpu == -1) - cpu = NR_CPUS-1; - } - } while (!cpu_online(cpu) || !IRQ_ALLOWED(cpu,allowed_mask) || - (search_idle && !IDLE_ENOUGH(cpu,now))); - - return cpu; -} - -static inline void balance_irq(int cpu, int irq) -{ - unsigned long now = jiffies; - cpumask_t allowed_mask; - unsigned int new_cpu; - - if (irqbalance_disabled) - return; - - cpus_and(allowed_mask, cpu_online_map, irq_affinity[irq]); - new_cpu = move(cpu, allowed_mask, now, 1); - if (cpu != new_cpu) { - irq_desc_t *desc = irq_desc + irq; - unsigned long flags; - - spin_lock_irqsave(&desc->lock, flags); - pending_irq_balance_cpumask[irq] = cpumask_of_cpu(new_cpu); - spin_unlock_irqrestore(&desc->lock, flags); - } -} - -static inline void rotate_irqs_among_cpus(unsigned long useful_load_threshold) -{ - int i, j; - Dprintk("Rotating IRQs among CPUs.\n"); - for (i = 0; i < NR_CPUS; i++) { - for (j = 0; cpu_online(i) && (j < NR_IRQS); j++) { - if (!irq_desc[j].action) - continue; - /* Is it a significant load ? */ - if (IRQ_DELTA(CPU_TO_PACKAGEINDEX(i),j) < - useful_load_threshold) - continue; - balance_irq(i, j); - } - } - balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL, - balanced_irq_interval - BALANCED_IRQ_LESS_DELTA); - return; -} - -static void do_irq_balance(void) -{ - int i, j; - unsigned long max_cpu_irq = 0, min_cpu_irq = (~0); - unsigned long move_this_load = 0; - int max_loaded = 0, min_loaded = 0; - int load; - unsigned long useful_load_threshold = balanced_irq_interval + 10; - int selected_irq; - int tmp_loaded, first_attempt = 1; - unsigned long tmp_cpu_irq; - unsigned long imbalance = 0; - cpumask_t allowed_mask, target_cpu_mask, tmp; - - for (i = 0; i < NR_CPUS; i++) { - int package_index; - CPU_IRQ(i) = 0; - if (!cpu_online(i)) - continue; - package_index = CPU_TO_PACKAGEINDEX(i); - for (j = 0; j < NR_IRQS; j++) { - unsigned long value_now, delta; - /* Is this an active IRQ? */ - if (!irq_desc[j].action) - continue; - if ( package_index == i ) - IRQ_DELTA(package_index,j) = 0; - /* Determine the total count per processor per IRQ */ - value_now = (unsigned long) kstat_cpu(i).irqs[j]; - - /* Determine the activity per processor per IRQ */ - delta = value_now - LAST_CPU_IRQ(i,j); - - /* Update last_cpu_irq[][] for the next time */ - LAST_CPU_IRQ(i,j) = value_now; - - /* Ignore IRQs whose rate is less than the clock */ - if (delta < useful_load_threshold) - continue; - /* update the load for the processor or package total */ - IRQ_DELTA(package_index,j) += delta; - - /* Keep track of the higher numbered sibling as well */ - if (i != package_index) - CPU_IRQ(i) += delta; - /* - * We have sibling A and sibling B in the package - * - * cpu_irq[A] = load for cpu A + load for cpu B - * cpu_irq[B] = load for cpu B - */ - CPU_IRQ(package_index) += delta; - } - } - /* Find the least loaded processor package */ - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_online(i)) - continue; - if (i != CPU_TO_PACKAGEINDEX(i)) - continue; - if (min_cpu_irq > CPU_IRQ(i)) { - min_cpu_irq = CPU_IRQ(i); - min_loaded = i; - } - } - max_cpu_irq = ULONG_MAX; - -tryanothercpu: - /* Look for heaviest loaded processor. - * We may come back to get the next heaviest loaded processor. - * Skip processors with trivial loads. - */ - tmp_cpu_irq = 0; - tmp_loaded = -1; - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_online(i)) - continue; - if (i != CPU_TO_PACKAGEINDEX(i)) - continue; - if (max_cpu_irq <= CPU_IRQ(i)) - continue; - if (tmp_cpu_irq < CPU_IRQ(i)) { - tmp_cpu_irq = CPU_IRQ(i); - tmp_loaded = i; - } - } - - if (tmp_loaded == -1) { - /* In the case of small number of heavy interrupt sources, - * loading some of the cpus too much. We use Ingo's original - * approach to rotate them around. - */ - if (!first_attempt && imbalance >= useful_load_threshold) { - rotate_irqs_among_cpus(useful_load_threshold); - return; - } - goto not_worth_the_effort; - } - - first_attempt = 0; /* heaviest search */ - max_cpu_irq = tmp_cpu_irq; /* load */ - max_loaded = tmp_loaded; /* processor */ - imbalance = (max_cpu_irq - min_cpu_irq) / 2; - - Dprintk("max_loaded cpu = %d\n", max_loaded); - Dprintk("min_loaded cpu = %d\n", min_loaded); - Dprintk("max_cpu_irq load = %ld\n", max_cpu_irq); - Dprintk("min_cpu_irq load = %ld\n", min_cpu_irq); - Dprintk("load imbalance = %lu\n", imbalance); - - /* if imbalance is less than approx 10% of max load, then - * observe diminishing returns action. - quit - */ - if (imbalance < (max_cpu_irq >> 3)) { - Dprintk("Imbalance too trivial\n"); - goto not_worth_the_effort; - } - -tryanotherirq: - /* if we select an IRQ to move that can't go where we want, then - * see if there is another one to try. - */ - move_this_load = 0; - selected_irq = -1; - for (j = 0; j < NR_IRQS; j++) { - /* Is this an active IRQ? */ - if (!irq_desc[j].action) - continue; - if (imbalance <= IRQ_DELTA(max_loaded,j)) - continue; - /* Try to find the IRQ that is closest to the imbalance - * without going over. - */ - if (move_this_load < IRQ_DELTA(max_loaded,j)) { - move_this_load = IRQ_DELTA(max_loaded,j); - selected_irq = j; - } - } - if (selected_irq == -1) { - goto tryanothercpu; - } - - imbalance = move_this_load; - - /* For physical_balance case, we accumlated both load - * values in the one of the siblings cpu_irq[], - * to use the same code for physical and logical processors - * as much as possible. - * - * NOTE: the cpu_irq[] array holds the sum of the load for - * sibling A and sibling B in the slot for the lowest numbered - * sibling (A), _AND_ the load for sibling B in the slot for - * the higher numbered sibling. - * - * We seek the least loaded sibling by making the comparison - * (A+B)/2 vs B - */ - load = CPU_IRQ(min_loaded) >> 1; - for_each_cpu_mask(j, cpu_sibling_map[min_loaded]) { - if (load > CPU_IRQ(j)) { - /* This won't change cpu_sibling_map[min_loaded] */ - load = CPU_IRQ(j); - min_loaded = j; - } - } - - cpus_and(allowed_mask, cpu_online_map, irq_affinity[selected_irq]); - target_cpu_mask = cpumask_of_cpu(min_loaded); - cpus_and(tmp, target_cpu_mask, allowed_mask); - - if (!cpus_empty(tmp)) { - irq_desc_t *desc = irq_desc + selected_irq; - unsigned long flags; - - Dprintk("irq = %d moved to cpu = %d\n", - selected_irq, min_loaded); - /* mark for change destination */ - spin_lock_irqsave(&desc->lock, flags); - pending_irq_balance_cpumask[selected_irq] = - cpumask_of_cpu(min_loaded); - spin_unlock_irqrestore(&desc->lock, flags); - /* Since we made a change, come back sooner to - * check for more variation. - */ - balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL, - balanced_irq_interval - BALANCED_IRQ_LESS_DELTA); - return; - } - goto tryanotherirq; - -not_worth_the_effort: - /* - * if we did not find an IRQ to move, then adjust the time interval - * upward - */ - balanced_irq_interval = min((long)MAX_BALANCED_IRQ_INTERVAL, - balanced_irq_interval + BALANCED_IRQ_MORE_DELTA); - Dprintk("IRQ worth rotating not found\n"); - return; -} - -static int balanced_irq(void *unused) -{ - int i; - unsigned long prev_balance_time = jiffies; - long time_remaining = balanced_irq_interval; - - daemonize("kirqd"); - - /* push everything to CPU 0 to give us a starting point. */ - for (i = 0 ; i < NR_IRQS ; i++) { - pending_irq_balance_cpumask[i] = cpumask_of_cpu(0); - } - - for ( ; ; ) { - set_current_state(TASK_INTERRUPTIBLE); - time_remaining = schedule_timeout(time_remaining); - try_to_freeze(PF_FREEZE); - if (time_after(jiffies, - prev_balance_time+balanced_irq_interval)) { - do_irq_balance(); - prev_balance_time = jiffies; - time_remaining = balanced_irq_interval; - } - } - return 0; -} - -static int __init balanced_irq_init(void) -{ - int i; - struct cpuinfo_x86 *c; - cpumask_t tmp; - - cpus_shift_right(tmp, cpu_online_map, 2); - c = &boot_cpu_data; - /* When not overwritten by the command line ask subarchitecture. */ - if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH) - irqbalance_disabled = NO_BALANCE_IRQ; - if (irqbalance_disabled) - return 0; - - /* disable irqbalance completely if there is only one processor online */ - if (num_online_cpus() < 2) { - irqbalance_disabled = 1; - return 0; - } - /* - * Enable physical balance only if more than 1 physical processor - * is present - */ - if (smp_num_siblings > 1 && !cpus_empty(tmp)) - physical_balance = 1; - - for (i = 0; i < NR_CPUS; i++) { - if (!cpu_online(i)) - continue; - irq_cpu_data[i].irq_delta = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL); - irq_cpu_data[i].last_irq = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL); - if (irq_cpu_data[i].irq_delta == NULL || irq_cpu_data[i].last_irq == NULL) { - printk(KERN_ERR "balanced_irq_init: out of memory"); - goto failed; - } - memset(irq_cpu_data[i].irq_delta,0,sizeof(unsigned long) * NR_IRQS); - memset(irq_cpu_data[i].last_irq,0,sizeof(unsigned long) * NR_IRQS); - } - - printk(KERN_INFO "Starting balanced_irq\n"); - if (kernel_thread(balanced_irq, NULL, CLONE_KERNEL) >= 0) - return 0; - else - printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq"); -failed: - for (i = 0; i < NR_CPUS; i++) { - if(irq_cpu_data[i].irq_delta) - kfree(irq_cpu_data[i].irq_delta); - if(irq_cpu_data[i].last_irq) - kfree(irq_cpu_data[i].last_irq); - } - return 0; -} - -int __init irqbalance_disable(char *str) -{ - irqbalance_disabled = 1; - return 0; -} - -__setup("noirqbalance", irqbalance_disable); - -static inline void move_irq(int irq) -{ - /* note - we hold the desc->lock */ - if (unlikely(!cpus_empty(pending_irq_balance_cpumask[irq]))) { - set_ioapic_affinity_irq(irq, pending_irq_balance_cpumask[irq]); - cpus_clear(pending_irq_balance_cpumask[irq]); - } -} - -late_initcall(balanced_irq_init); - -#else /* !CONFIG_IRQBALANCE */ -static inline void move_irq(int irq) { } -#endif /* CONFIG_IRQBALANCE */ - #ifndef CONFIG_SMP void fastcall send_IPI_self(int vector) { @@ -1609,7 +1188,6 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq) */ static void ack_edge_ioapic_irq(unsigned int irq) { - move_irq(irq); if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_DISABLED)) mask_IO_APIC_irq(irq); @@ -1637,12 +1215,13 @@ static unsigned int startup_level_ioapic_irq (unsigned int irq) return 0; /* don't check for pending */ } -static void end_level_ioapic_irq (unsigned int irq) +static void mask_and_ack_level_ioapic_irq (unsigned int irq) { unsigned long v; int i; - move_irq(irq); + mask_IO_APIC_irq(irq); + /* * It appears there is an erratum which affects at least version 0x11 * of I/O APIC (that's the 82093AA and cores integrated into various @@ -1671,13 +1250,17 @@ static void end_level_ioapic_irq (unsigned int irq) if (!(v & (1 << (i & 0x1f)))) { atomic_inc(&irq_mis_count); spin_lock(&ioapic_lock); - __mask_and_edge_IO_APIC_irq(irq); - __unmask_and_level_IO_APIC_irq(irq); + __edge_IO_APIC_irq(irq); + __level_IO_APIC_irq(irq); spin_unlock(&ioapic_lock); } } -#ifdef CONFIG_PCI_MSI +static void end_level_ioapic_irq (unsigned int irq) +{ + unmask_IO_APIC_irq(irq); +} + static unsigned int startup_edge_ioapic_vector(unsigned int vector) { int irq = vector_to_irq(vector); @@ -1699,6 +1282,13 @@ static unsigned int startup_level_ioapic_vector (unsigned int vector) return startup_level_ioapic_irq (irq); } +static void mask_and_ack_level_ioapic_vector (unsigned int vector) +{ + int irq = vector_to_irq(vector); + + mask_and_ack_level_ioapic_irq(irq); +} + static void end_level_ioapic_vector (unsigned int vector) { int irq = vector_to_irq(vector); @@ -1727,7 +1317,11 @@ static void set_ioapic_affinity_vector (unsigned int vector, set_ioapic_affinity_irq(irq, cpu_mask); } -#endif + +static void noop_ioapic_vector(unsigned int vector) +{ + /* nothing */ +} /* * Level and edge triggered IO-APIC interrupts need different handling, @@ -1739,24 +1333,24 @@ static void set_ioapic_affinity_vector (unsigned int vector, */ static struct hw_interrupt_type ioapic_edge_type = { .typename = "IO-APIC-edge", - .startup = startup_edge_ioapic, - .shutdown = shutdown_edge_ioapic, - .enable = enable_edge_ioapic, - .disable = disable_edge_ioapic, - .ack = ack_edge_ioapic, - .end = end_edge_ioapic, - .set_affinity = set_ioapic_affinity, + .startup = startup_edge_ioapic_vector, + .shutdown = noop_ioapic_vector, + .enable = unmask_IO_APIC_vector, + .disable = noop_ioapic_vector, + .ack = ack_edge_ioapic_vector, + .end = noop_ioapic_vector, + .set_affinity = set_ioapic_affinity_vector, }; static struct hw_interrupt_type ioapic_level_type = { .typename = "IO-APIC-level", - .startup = startup_level_ioapic, - .shutdown = shutdown_level_ioapic, - .enable = enable_level_ioapic, - .disable = disable_level_ioapic, - .ack = mask_and_ack_level_ioapic, - .end = end_level_ioapic, - .set_affinity = set_ioapic_affinity, + .startup = startup_level_ioapic_vector, + .shutdown = mask_IO_APIC_vector, + .enable = unmask_IO_APIC_vector, + .disable = mask_IO_APIC_vector, + .ack = mask_and_ack_level_ioapic_vector, + .end = end_level_ioapic_vector, + .set_affinity = set_ioapic_affinity_vector, }; static inline void init_IO_APIC_traps(void) @@ -2256,8 +1850,7 @@ int ioapic_guest_write(int apicid, int address, u32 val) return 0; /* Set the correct irq-handling type. */ - irq_desc[irq].handler = rte.trigger ? - &ioapic_level_type: &ioapic_edge_type; + ioapic_register_intr(irq, rte.vector, rte.trigger); /* Record the pin<->irq mapping. */ for ( entry = &irq_2_pin[irq]; ; entry = &irq_2_pin[entry->next] ) diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index aaaff647ce..784528ae74 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -186,26 +186,30 @@ typedef struct { struct exec_domain *guest[IRQ_MAX_GUESTS]; } irq_guest_action_t; +extern int vector_irq[]; + static void __do_IRQ_guest(int irq) { irq_desc_t *desc = &irq_desc[irq]; irq_guest_action_t *action = (irq_guest_action_t *)desc->action; struct exec_domain *ed; - int i; + int i, pirq; + + pirq = platform_legacy_irq(irq) ? irq : vector_irq[irq]; for ( i = 0; i < action->nr_guests; i++ ) { ed = action->guest[i]; - if ( !test_and_set_bit(irq, &ed->domain->pirq_mask) ) + if ( !test_and_set_bit(pirq, &ed->domain->pirq_mask) ) action->in_flight++; - send_guest_pirq(ed, irq); + send_guest_pirq(ed, pirq); } } int pirq_guest_unmask(struct domain *d) { irq_desc_t *desc; - unsigned int i, j, pirq; + unsigned int i, j, pirq, vector; u32 m; shared_info_t *s = d->shared_info; @@ -217,12 +221,13 @@ int pirq_guest_unmask(struct domain *d) j = find_first_set_bit(m); m &= ~(1 << j); pirq = (i << 5) + j; - desc = &irq_desc[pirq]; + vector = platform_legacy_irq(pirq) ? pirq : IO_APIC_VECTOR(pirq); + desc = &irq_desc[vector]; spin_lock_irq(&desc->lock); if ( !test_bit(d->pirq_to_evtchn[pirq], &s->evtchn_mask[0]) && test_and_clear_bit(pirq, &d->pirq_mask) && (--((irq_guest_action_t *)desc->action)->in_flight == 0) ) - desc->handler->end(pirq); + desc->handler->end(vector); spin_unlock_irq(&desc->lock); } } @@ -233,14 +238,17 @@ int pirq_guest_unmask(struct domain *d) int pirq_guest_bind(struct exec_domain *ed, int irq, int will_share) { struct domain *d = ed->domain; - irq_desc_t *desc = &irq_desc[irq]; + irq_desc_t *desc; irq_guest_action_t *action; unsigned long flags; - int rc = 0; + int rc = 0, vector; if ( !IS_CAPABLE_PHYSDEV(d) ) return -EPERM; + vector = platform_legacy_irq(irq) ? irq : IO_APIC_VECTOR(irq); + desc = &irq_desc[vector]; + spin_lock_irqsave(&desc->lock, flags); action = (irq_guest_action_t *)desc->action; @@ -270,12 +278,12 @@ int pirq_guest_bind(struct exec_domain *ed, int irq, int will_share) desc->depth = 0; desc->status |= IRQ_GUEST; desc->status &= ~IRQ_DISABLED; - desc->handler->startup(irq); + desc->handler->startup(vector); /* Attempt to bind the interrupt target to the correct CPU. */ if ( desc->handler->set_affinity != NULL ) desc->handler->set_affinity( - irq, apicid_to_phys_cpu_present(ed->processor)); + vector, apicid_to_phys_cpu_present(ed->processor)); } else if ( !will_share || !action->shareable ) { @@ -301,10 +309,13 @@ int pirq_guest_bind(struct exec_domain *ed, int irq, int will_share) int pirq_guest_unbind(struct domain *d, int irq) { - irq_desc_t *desc = &irq_desc[irq]; + irq_desc_t *desc; irq_guest_action_t *action; unsigned long flags; - int i; + int i, vector; + + vector = platform_legacy_irq(irq) ? irq : IO_APIC_VECTOR(irq); + desc = &irq_desc[vector]; spin_lock_irqsave(&desc->lock, flags); @@ -312,7 +323,7 @@ int pirq_guest_unbind(struct domain *d, int irq) if ( test_and_clear_bit(irq, &d->pirq_mask) && (--action->in_flight == 0) ) - desc->handler->end(irq); + desc->handler->end(vector); if ( action->nr_guests == 1 ) { @@ -321,7 +332,7 @@ int pirq_guest_unbind(struct domain *d, int irq) desc->depth = 1; desc->status |= IRQ_DISABLED; desc->status &= ~IRQ_GUEST; - desc->handler->shutdown(irq); + desc->handler->shutdown(vector); } else { @@ -335,26 +346,3 @@ int pirq_guest_unbind(struct domain *d, int irq) spin_unlock_irqrestore(&desc->lock, flags); return 0; } - -int pirq_guest_bindable(int irq, int will_share) -{ - irq_desc_t *desc = &irq_desc[irq]; - irq_guest_action_t *action; - unsigned long flags; - int okay; - - spin_lock_irqsave(&desc->lock, flags); - - action = (irq_guest_action_t *)desc->action; - - /* - * To be bindable the IRQ must either be not currently bound (1), or - * it must be shareable (2) and not at its share limit (3). - */ - okay = ((!(desc->status & IRQ_GUEST) && (action == NULL)) || /* 1 */ - (action->shareable && will_share && /* 2 */ - (action->nr_guests != IRQ_MAX_GUESTS))); /* 3 */ - - spin_unlock_irqrestore(&desc->lock, flags); - return okay; -} diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c index 5de96ec96d..048fca68ee 100644 --- a/xen/arch/x86/physdev.c +++ b/xen/arch/x86/physdev.c @@ -41,7 +41,7 @@ long do_physdev_op(physdev_op_t *uop) { physdev_op_t op; long ret; - int irq; + int irq, vector; if ( unlikely(copy_from_user(&op, uop, sizeof(op)) != 0) ) return -EFAULT; @@ -87,8 +87,13 @@ long do_physdev_op(physdev_op_t *uop) if ( (irq = op.u.irq_op.irq) >= NR_IRQS ) return -EINVAL; - op.u.irq_op.vector = assign_irq_vector(irq); - set_intr_gate(op.u.irq_op.vector, interrupt[irq]); + op.u.irq_op.vector = vector = assign_irq_vector(irq); + + if ( use_pci_vector() && !platform_legacy_irq(irq) ) + set_intr_gate(vector, interrupt[vector]); + else + set_intr_gate(vector, interrupt[irq]); + ret = 0; break; diff --git a/xen/include/asm-x86/io_apic.h b/xen/include/asm-x86/io_apic.h index 5c71c08f58..86aa452961 100644 --- a/xen/include/asm-x86/io_apic.h +++ b/xen/include/asm-x86/io_apic.h @@ -14,45 +14,7 @@ #ifdef CONFIG_X86_IO_APIC -#ifdef CONFIG_PCI_MSI static inline int use_pci_vector(void) {return 1;} -static inline void disable_edge_ioapic_vector(unsigned int vector) { } -static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { } -static inline void end_edge_ioapic_vector (unsigned int vector) { } -#define startup_level_ioapic startup_level_ioapic_vector -#define shutdown_level_ioapic mask_IO_APIC_vector -#define enable_level_ioapic unmask_IO_APIC_vector -#define disable_level_ioapic mask_IO_APIC_vector -#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector -#define end_level_ioapic end_level_ioapic_vector -#define set_ioapic_affinity set_ioapic_affinity_vector - -#define startup_edge_ioapic startup_edge_ioapic_vector -#define shutdown_edge_ioapic disable_edge_ioapic_vector -#define enable_edge_ioapic unmask_IO_APIC_vector -#define disable_edge_ioapic disable_edge_ioapic_vector -#define ack_edge_ioapic ack_edge_ioapic_vector -#define end_edge_ioapic end_edge_ioapic_vector -#else -static inline int use_pci_vector(void) {return 0;} -static inline void disable_edge_ioapic_irq(unsigned int irq) { } -static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { } -static inline void end_edge_ioapic_irq (unsigned int irq) { } -#define startup_level_ioapic startup_level_ioapic_irq -#define shutdown_level_ioapic mask_IO_APIC_irq -#define enable_level_ioapic unmask_IO_APIC_irq -#define disable_level_ioapic mask_IO_APIC_irq -#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq -#define end_level_ioapic end_level_ioapic_irq -#define set_ioapic_affinity set_ioapic_affinity_irq - -#define startup_edge_ioapic startup_edge_ioapic_irq -#define shutdown_edge_ioapic disable_edge_ioapic_irq -#define enable_edge_ioapic unmask_IO_APIC_irq -#define disable_edge_ioapic disable_edge_ioapic_irq -#define ack_edge_ioapic ack_edge_ioapic_irq -#define end_edge_ioapic end_edge_ioapic_irq -#endif #define IO_APIC_BASE(idx) \ ((volatile int *)(__fix_to_virt(FIX_IO_APIC_BASE_0 + idx) \ diff --git a/xen/include/asm-x86/mach-default/irq_vectors_limits.h b/xen/include/asm-x86/mach-default/irq_vectors_limits.h index b330026e6f..a0664d7f67 100644 --- a/xen/include/asm-x86/mach-default/irq_vectors_limits.h +++ b/xen/include/asm-x86/mach-default/irq_vectors_limits.h @@ -1,21 +1,8 @@ #ifndef _ASM_IRQ_VECTORS_LIMITS_H #define _ASM_IRQ_VECTORS_LIMITS_H -#ifdef CONFIG_PCI_MSI +/* MSI limits */ #define NR_IRQS FIRST_SYSTEM_VECTOR #define NR_IRQ_VECTORS NR_IRQS -#else -#ifdef CONFIG_X86_IO_APIC -#define NR_IRQS 224 -# if (224 >= 32 * NR_CPUS) -# define NR_IRQ_VECTORS NR_IRQS -# else -# define NR_IRQ_VECTORS (32 * NR_CPUS) -# endif -#else -#define NR_IRQS 16 -#define NR_IRQ_VECTORS NR_IRQS -#endif -#endif #endif /* _ASM_IRQ_VECTORS_LIMITS_H */ diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h index f419f0c182..9de76b8ca1 100644 --- a/xen/include/xen/irq.h +++ b/xen/include/xen/irq.h @@ -71,6 +71,5 @@ struct exec_domain; extern int pirq_guest_unmask(struct domain *p); extern int pirq_guest_bind(struct exec_domain *p, int irq, int will_share); extern int pirq_guest_unbind(struct domain *p, int irq); -extern int pirq_guest_bindable(int irq, int will_share); #endif /* __XEN_IRQ_H__ */ From b15050fc082c59b1ce13dd7244477ee3eb55f28d Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk[cl349]" Date: Tue, 10 May 2005 14:49:06 +0000 Subject: [PATCH 46/54] bitkeeper revision 1.1389.16.1 (4280c9e2jOlPDS_OBC6Lw_D6kD2DsA) smpboot.c: Fix apic setup for SMP guest kernel running on non-SMP machine. Plus minor cleanups. smpboot_hooks.h: smpboot_clear_io_apic_irqs now makes sense. smpboot.c: start_secondary doesn't return anything. Signed-off-by: Christian Limpach --- .../arch/xen/i386/kernel/smpboot.c | 17 +++-------------- .../asm-xen/asm-i386/mach-xen/smpboot_hooks.h | 4 ---- .../asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h | 4 ---- 3 files changed, 3 insertions(+), 22 deletions(-) diff --git a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c index 3e9f82f1d9..7c1ef78cd9 100644 --- a/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c +++ b/linux-2.6.11-xen-sparse/arch/xen/i386/kernel/smpboot.c @@ -54,6 +54,7 @@ #include #include +#include #include #include @@ -493,19 +494,7 @@ static void __init start_secondary(void *unused) local_irq_enable(); wmb(); - if (0) { - char *msg2 = "delay2\n"; - int timeout; - for (timeout = 0; timeout < 50000; timeout++) { - udelay(1000); - if (timeout == 2000) { - (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(msg2), msg2); - timeout = 0; - } - } - } cpu_idle(); - return 0; } /* @@ -1111,15 +1100,15 @@ static void __init smp_boot_cpus(unsigned int max_cpus) * If we couldn't find an SMP configuration at boot time, * get out of here now! */ - if (!smp_found_config /* && !acpi_lapic) */) { + if (!smp_found_config && !acpi_lapic) { printk(KERN_NOTICE "SMP motherboard not detected.\n"); smpboot_clear_io_apic_irqs(); #if 0 phys_cpu_present_map = physid_mask_of_physid(0); +#endif if (APIC_init_uniprocessor()) printk(KERN_NOTICE "Local APIC not detected." " Using dummy APIC emulation.\n"); -#endif map_cpu_to_logical_apicid(); return; } diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h index 7479f82686..c2c211e5ea 100644 --- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h +++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h @@ -3,11 +3,7 @@ static inline void smpboot_clear_io_apic_irqs(void) { -#if 1 - printk("smpboot_clear_io_apic_irqs\n"); -#else io_apic_irqs = 0; -#endif } static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h b/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h index 7479f82686..c2c211e5ea 100644 --- a/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h +++ b/linux-2.6.11-xen-sparse/include/asm-xen/asm-x86_64/mach-xen/smpboot_hooks.h @@ -3,11 +3,7 @@ static inline void smpboot_clear_io_apic_irqs(void) { -#if 1 - printk("smpboot_clear_io_apic_irqs\n"); -#else io_apic_irqs = 0; -#endif } static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) From 3cfd87898e685b6cad0fca3f3e0020537966c6cb Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Tue, 10 May 2005 15:07:49 +0000 Subject: [PATCH 47/54] bitkeeper revision 1.1389.9.5 (4280ce45ySNP-9TH6XPIhkIZcGy1LA) Fix bugs in hyperprivop counting --- xen/arch/ia64/privop.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xen/arch/ia64/privop.c b/xen/arch/ia64/privop.c index f617d2d0b4..aec763f80d 100644 --- a/xen/arch/ia64/privop.c +++ b/xen/arch/ia64/privop.c @@ -1004,8 +1004,9 @@ int dump_hyperprivop_counts(char *buf) s += sprintf(s,"Hyperprivops:\n"); for (i = 1; i <= HYPERPRIVOP_MAX; i++) if (hyperpriv_cnt[i]) - s += sprintf("%10d %s\n", + s += sprintf(s,"%10d %s\n", hyperpriv_cnt[i], hyperpriv_str[i]); + return s - buf; } void zero_hyperprivop_counts(void) From 72e4c0236f29a77cc940f7617ffc49fbeef3d798 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 10 May 2005 16:35:45 +0000 Subject: [PATCH 48/54] bitkeeper revision 1.1389.15.4 (4280e2e1TW-3Y8iE13utT8fyuaozWA) Cset exclude: kaf24@firebug.cl.cam.ac.uk|ChangeSet|20050510144837|42684 --- xen/arch/ia64/irq.c | 23 + xen/arch/x86/acpi/boot.c | 42 ++ xen/arch/x86/io_apic.c | 493 ++++++++++++++++-- xen/arch/x86/irq.c | 62 ++- xen/arch/x86/physdev.c | 11 +- xen/include/asm-x86/io_apic.h | 38 ++ .../asm-x86/mach-default/irq_vectors_limits.h | 15 +- xen/include/xen/irq.h | 1 + 8 files changed, 608 insertions(+), 77 deletions(-) diff --git a/xen/arch/ia64/irq.c b/xen/arch/ia64/irq.c index 2ce076e324..1b4e277343 100644 --- a/xen/arch/ia64/irq.c +++ b/xen/arch/ia64/irq.c @@ -1468,6 +1468,29 @@ int pirq_guest_unbind(struct domain *d, int irq) spin_unlock_irqrestore(&desc->lock, flags); return 0; } + +int pirq_guest_bindable(int irq, int will_share) +{ + irq_desc_t *desc = &irq_desc[irq]; + irq_guest_action_t *action; + unsigned long flags; + int okay; + + spin_lock_irqsave(&desc->lock, flags); + + action = (irq_guest_action_t *)desc->action; + + /* + * To be bindable the IRQ must either be not currently bound (1), or + * it must be shareable (2) and not at its share limit (3). + */ + okay = ((!(desc->status & IRQ_GUEST) && (action == NULL)) || /* 1 */ + (action->shareable && will_share && /* 2 */ + (action->nr_guests != IRQ_MAX_GUESTS))); /* 3 */ + + spin_unlock_irqrestore(&desc->lock, flags); + return okay; +} #endif #ifdef XEN diff --git a/xen/arch/x86/acpi/boot.c b/xen/arch/x86/acpi/boot.c index ad3d043138..7237d5e7e2 100644 --- a/xen/arch/x86/acpi/boot.c +++ b/xen/arch/x86/acpi/boot.c @@ -447,6 +447,44 @@ acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) #endif /* CONFIG_ACPI_BUS */ +int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) +{ +#ifdef CONFIG_X86_IO_APIC + if (use_pci_vector() && !platform_legacy_irq(gsi)) + *irq = IO_APIC_VECTOR(gsi); + else +#endif + *irq = gsi; + return 0; +} + +unsigned int acpi_register_gsi(u32 gsi, int edge_level, int active_high_low) +{ + unsigned int irq; + unsigned int plat_gsi = gsi; + +#ifdef CONFIG_PCI + /* + * Make sure all (legacy) PCI IRQs are set as level-triggered. + */ + if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) { + extern void eisa_set_level_irq(unsigned int irq); + + if (edge_level == ACPI_LEVEL_SENSITIVE) + eisa_set_level_irq(gsi); + } +#endif + +#ifdef CONFIG_X86_IO_APIC + if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) { + plat_gsi = mp_register_gsi(gsi, edge_level, active_high_low); + } +#endif + acpi_gsi_to_irq(plat_gsi, &irq); + return irq; +} +EXPORT_SYMBOL(acpi_register_gsi); + /* * ACPI based hotplug support for CPU */ @@ -818,6 +856,10 @@ acpi_boot_table_init(void) return error; } +#if 0 /*def __i386__*/ + check_acpi_pci(); +#endif + acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); /* diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c index 2b485a1fe1..3e7c89cf0e 100644 --- a/xen/arch/x86/io_apic.c +++ b/xen/arch/x86/io_apic.c @@ -64,8 +64,12 @@ static struct irq_pin_list { } irq_2_pin[PIN_MAP_SIZE]; int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1}; +#ifdef CONFIG_PCI_MSI #define vector_to_irq(vector) \ (platform_legacy_irq(vector) ? vector : vector_irq[vector]) +#else +#define vector_to_irq(vector) (vector) +#endif /* * The common case is 1:1 IRQ<->pin mappings. Sometimes there are @@ -141,16 +145,16 @@ static void __unmask_IO_APIC_irq (unsigned int irq) __modify_IO_APIC_irq(irq, 0, 0x00010000); } -/* trigger = 0 */ -static void __edge_IO_APIC_irq (unsigned int irq) +/* mask = 1, trigger = 0 */ +static void __mask_and_edge_IO_APIC_irq (unsigned int irq) { - __modify_IO_APIC_irq(irq, 0, 0x00008000); + __modify_IO_APIC_irq(irq, 0x00010000, 0x00008000); } -/* trigger = 1 */ -static void __level_IO_APIC_irq (unsigned int irq) +/* mask = 0, trigger = 1 */ +static void __unmask_and_level_IO_APIC_irq (unsigned int irq) { - __modify_IO_APIC_irq(irq, 0x00008000, 0); + __modify_IO_APIC_irq(irq, 0x00008000, 0x00010000); } static void mask_IO_APIC_irq (unsigned int irq) @@ -227,6 +231,423 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) spin_unlock_irqrestore(&ioapic_lock, flags); } +#if defined(CONFIG_IRQBALANCE) +# include /* kernel_thread() */ +# include /* kstat */ +# include /* kmalloc() */ +# include /* time_after() */ + +# ifdef CONFIG_BALANCED_IRQ_DEBUG +# define TDprintk(x...) do { printk("<%ld:%s:%d>: ", jiffies, __FILE__, __LINE__); printk(x); } while (0) +# define Dprintk(x...) do { TDprintk(x); } while (0) +# else +# define TDprintk(x...) +# define Dprintk(x...) +# endif + +cpumask_t __cacheline_aligned pending_irq_balance_cpumask[NR_IRQS]; + +#define IRQBALANCE_CHECK_ARCH -999 +static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH; +static int physical_balance = 0; + +struct irq_cpu_info { + unsigned long * last_irq; + unsigned long * irq_delta; + unsigned long irq; +} irq_cpu_data[NR_CPUS]; + +#define CPU_IRQ(cpu) (irq_cpu_data[cpu].irq) +#define LAST_CPU_IRQ(cpu,irq) (irq_cpu_data[cpu].last_irq[irq]) +#define IRQ_DELTA(cpu,irq) (irq_cpu_data[cpu].irq_delta[irq]) + +#define IDLE_ENOUGH(cpu,now) \ + (idle_cpu(cpu) && ((now) - irq_stat[(cpu)].idle_timestamp > 1)) + +#define IRQ_ALLOWED(cpu, allowed_mask) cpu_isset(cpu, allowed_mask) + +#define CPU_TO_PACKAGEINDEX(i) (first_cpu(cpu_sibling_map[i])) + +#define MAX_BALANCED_IRQ_INTERVAL (5*HZ) +#define MIN_BALANCED_IRQ_INTERVAL (HZ/2) +#define BALANCED_IRQ_MORE_DELTA (HZ/10) +#define BALANCED_IRQ_LESS_DELTA (HZ) + +long balanced_irq_interval = MAX_BALANCED_IRQ_INTERVAL; + +static unsigned long move(int curr_cpu, cpumask_t allowed_mask, + unsigned long now, int direction) +{ + int search_idle = 1; + int cpu = curr_cpu; + + goto inside; + + do { + if (unlikely(cpu == curr_cpu)) + search_idle = 0; +inside: + if (direction == 1) { + cpu++; + if (cpu >= NR_CPUS) + cpu = 0; + } else { + cpu--; + if (cpu == -1) + cpu = NR_CPUS-1; + } + } while (!cpu_online(cpu) || !IRQ_ALLOWED(cpu,allowed_mask) || + (search_idle && !IDLE_ENOUGH(cpu,now))); + + return cpu; +} + +static inline void balance_irq(int cpu, int irq) +{ + unsigned long now = jiffies; + cpumask_t allowed_mask; + unsigned int new_cpu; + + if (irqbalance_disabled) + return; + + cpus_and(allowed_mask, cpu_online_map, irq_affinity[irq]); + new_cpu = move(cpu, allowed_mask, now, 1); + if (cpu != new_cpu) { + irq_desc_t *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&desc->lock, flags); + pending_irq_balance_cpumask[irq] = cpumask_of_cpu(new_cpu); + spin_unlock_irqrestore(&desc->lock, flags); + } +} + +static inline void rotate_irqs_among_cpus(unsigned long useful_load_threshold) +{ + int i, j; + Dprintk("Rotating IRQs among CPUs.\n"); + for (i = 0; i < NR_CPUS; i++) { + for (j = 0; cpu_online(i) && (j < NR_IRQS); j++) { + if (!irq_desc[j].action) + continue; + /* Is it a significant load ? */ + if (IRQ_DELTA(CPU_TO_PACKAGEINDEX(i),j) < + useful_load_threshold) + continue; + balance_irq(i, j); + } + } + balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL, + balanced_irq_interval - BALANCED_IRQ_LESS_DELTA); + return; +} + +static void do_irq_balance(void) +{ + int i, j; + unsigned long max_cpu_irq = 0, min_cpu_irq = (~0); + unsigned long move_this_load = 0; + int max_loaded = 0, min_loaded = 0; + int load; + unsigned long useful_load_threshold = balanced_irq_interval + 10; + int selected_irq; + int tmp_loaded, first_attempt = 1; + unsigned long tmp_cpu_irq; + unsigned long imbalance = 0; + cpumask_t allowed_mask, target_cpu_mask, tmp; + + for (i = 0; i < NR_CPUS; i++) { + int package_index; + CPU_IRQ(i) = 0; + if (!cpu_online(i)) + continue; + package_index = CPU_TO_PACKAGEINDEX(i); + for (j = 0; j < NR_IRQS; j++) { + unsigned long value_now, delta; + /* Is this an active IRQ? */ + if (!irq_desc[j].action) + continue; + if ( package_index == i ) + IRQ_DELTA(package_index,j) = 0; + /* Determine the total count per processor per IRQ */ + value_now = (unsigned long) kstat_cpu(i).irqs[j]; + + /* Determine the activity per processor per IRQ */ + delta = value_now - LAST_CPU_IRQ(i,j); + + /* Update last_cpu_irq[][] for the next time */ + LAST_CPU_IRQ(i,j) = value_now; + + /* Ignore IRQs whose rate is less than the clock */ + if (delta < useful_load_threshold) + continue; + /* update the load for the processor or package total */ + IRQ_DELTA(package_index,j) += delta; + + /* Keep track of the higher numbered sibling as well */ + if (i != package_index) + CPU_IRQ(i) += delta; + /* + * We have sibling A and sibling B in the package + * + * cpu_irq[A] = load for cpu A + load for cpu B + * cpu_irq[B] = load for cpu B + */ + CPU_IRQ(package_index) += delta; + } + } + /* Find the least loaded processor package */ + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; + if (i != CPU_TO_PACKAGEINDEX(i)) + continue; + if (min_cpu_irq > CPU_IRQ(i)) { + min_cpu_irq = CPU_IRQ(i); + min_loaded = i; + } + } + max_cpu_irq = ULONG_MAX; + +tryanothercpu: + /* Look for heaviest loaded processor. + * We may come back to get the next heaviest loaded processor. + * Skip processors with trivial loads. + */ + tmp_cpu_irq = 0; + tmp_loaded = -1; + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; + if (i != CPU_TO_PACKAGEINDEX(i)) + continue; + if (max_cpu_irq <= CPU_IRQ(i)) + continue; + if (tmp_cpu_irq < CPU_IRQ(i)) { + tmp_cpu_irq = CPU_IRQ(i); + tmp_loaded = i; + } + } + + if (tmp_loaded == -1) { + /* In the case of small number of heavy interrupt sources, + * loading some of the cpus too much. We use Ingo's original + * approach to rotate them around. + */ + if (!first_attempt && imbalance >= useful_load_threshold) { + rotate_irqs_among_cpus(useful_load_threshold); + return; + } + goto not_worth_the_effort; + } + + first_attempt = 0; /* heaviest search */ + max_cpu_irq = tmp_cpu_irq; /* load */ + max_loaded = tmp_loaded; /* processor */ + imbalance = (max_cpu_irq - min_cpu_irq) / 2; + + Dprintk("max_loaded cpu = %d\n", max_loaded); + Dprintk("min_loaded cpu = %d\n", min_loaded); + Dprintk("max_cpu_irq load = %ld\n", max_cpu_irq); + Dprintk("min_cpu_irq load = %ld\n", min_cpu_irq); + Dprintk("load imbalance = %lu\n", imbalance); + + /* if imbalance is less than approx 10% of max load, then + * observe diminishing returns action. - quit + */ + if (imbalance < (max_cpu_irq >> 3)) { + Dprintk("Imbalance too trivial\n"); + goto not_worth_the_effort; + } + +tryanotherirq: + /* if we select an IRQ to move that can't go where we want, then + * see if there is another one to try. + */ + move_this_load = 0; + selected_irq = -1; + for (j = 0; j < NR_IRQS; j++) { + /* Is this an active IRQ? */ + if (!irq_desc[j].action) + continue; + if (imbalance <= IRQ_DELTA(max_loaded,j)) + continue; + /* Try to find the IRQ that is closest to the imbalance + * without going over. + */ + if (move_this_load < IRQ_DELTA(max_loaded,j)) { + move_this_load = IRQ_DELTA(max_loaded,j); + selected_irq = j; + } + } + if (selected_irq == -1) { + goto tryanothercpu; + } + + imbalance = move_this_load; + + /* For physical_balance case, we accumlated both load + * values in the one of the siblings cpu_irq[], + * to use the same code for physical and logical processors + * as much as possible. + * + * NOTE: the cpu_irq[] array holds the sum of the load for + * sibling A and sibling B in the slot for the lowest numbered + * sibling (A), _AND_ the load for sibling B in the slot for + * the higher numbered sibling. + * + * We seek the least loaded sibling by making the comparison + * (A+B)/2 vs B + */ + load = CPU_IRQ(min_loaded) >> 1; + for_each_cpu_mask(j, cpu_sibling_map[min_loaded]) { + if (load > CPU_IRQ(j)) { + /* This won't change cpu_sibling_map[min_loaded] */ + load = CPU_IRQ(j); + min_loaded = j; + } + } + + cpus_and(allowed_mask, cpu_online_map, irq_affinity[selected_irq]); + target_cpu_mask = cpumask_of_cpu(min_loaded); + cpus_and(tmp, target_cpu_mask, allowed_mask); + + if (!cpus_empty(tmp)) { + irq_desc_t *desc = irq_desc + selected_irq; + unsigned long flags; + + Dprintk("irq = %d moved to cpu = %d\n", + selected_irq, min_loaded); + /* mark for change destination */ + spin_lock_irqsave(&desc->lock, flags); + pending_irq_balance_cpumask[selected_irq] = + cpumask_of_cpu(min_loaded); + spin_unlock_irqrestore(&desc->lock, flags); + /* Since we made a change, come back sooner to + * check for more variation. + */ + balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL, + balanced_irq_interval - BALANCED_IRQ_LESS_DELTA); + return; + } + goto tryanotherirq; + +not_worth_the_effort: + /* + * if we did not find an IRQ to move, then adjust the time interval + * upward + */ + balanced_irq_interval = min((long)MAX_BALANCED_IRQ_INTERVAL, + balanced_irq_interval + BALANCED_IRQ_MORE_DELTA); + Dprintk("IRQ worth rotating not found\n"); + return; +} + +static int balanced_irq(void *unused) +{ + int i; + unsigned long prev_balance_time = jiffies; + long time_remaining = balanced_irq_interval; + + daemonize("kirqd"); + + /* push everything to CPU 0 to give us a starting point. */ + for (i = 0 ; i < NR_IRQS ; i++) { + pending_irq_balance_cpumask[i] = cpumask_of_cpu(0); + } + + for ( ; ; ) { + set_current_state(TASK_INTERRUPTIBLE); + time_remaining = schedule_timeout(time_remaining); + try_to_freeze(PF_FREEZE); + if (time_after(jiffies, + prev_balance_time+balanced_irq_interval)) { + do_irq_balance(); + prev_balance_time = jiffies; + time_remaining = balanced_irq_interval; + } + } + return 0; +} + +static int __init balanced_irq_init(void) +{ + int i; + struct cpuinfo_x86 *c; + cpumask_t tmp; + + cpus_shift_right(tmp, cpu_online_map, 2); + c = &boot_cpu_data; + /* When not overwritten by the command line ask subarchitecture. */ + if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH) + irqbalance_disabled = NO_BALANCE_IRQ; + if (irqbalance_disabled) + return 0; + + /* disable irqbalance completely if there is only one processor online */ + if (num_online_cpus() < 2) { + irqbalance_disabled = 1; + return 0; + } + /* + * Enable physical balance only if more than 1 physical processor + * is present + */ + if (smp_num_siblings > 1 && !cpus_empty(tmp)) + physical_balance = 1; + + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_online(i)) + continue; + irq_cpu_data[i].irq_delta = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL); + irq_cpu_data[i].last_irq = kmalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL); + if (irq_cpu_data[i].irq_delta == NULL || irq_cpu_data[i].last_irq == NULL) { + printk(KERN_ERR "balanced_irq_init: out of memory"); + goto failed; + } + memset(irq_cpu_data[i].irq_delta,0,sizeof(unsigned long) * NR_IRQS); + memset(irq_cpu_data[i].last_irq,0,sizeof(unsigned long) * NR_IRQS); + } + + printk(KERN_INFO "Starting balanced_irq\n"); + if (kernel_thread(balanced_irq, NULL, CLONE_KERNEL) >= 0) + return 0; + else + printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq"); +failed: + for (i = 0; i < NR_CPUS; i++) { + if(irq_cpu_data[i].irq_delta) + kfree(irq_cpu_data[i].irq_delta); + if(irq_cpu_data[i].last_irq) + kfree(irq_cpu_data[i].last_irq); + } + return 0; +} + +int __init irqbalance_disable(char *str) +{ + irqbalance_disabled = 1; + return 0; +} + +__setup("noirqbalance", irqbalance_disable); + +static inline void move_irq(int irq) +{ + /* note - we hold the desc->lock */ + if (unlikely(!cpus_empty(pending_irq_balance_cpumask[irq]))) { + set_ioapic_affinity_irq(irq, pending_irq_balance_cpumask[irq]); + cpus_clear(pending_irq_balance_cpumask[irq]); + } +} + +late_initcall(balanced_irq_init); + +#else /* !CONFIG_IRQBALANCE */ +static inline void move_irq(int irq) { } +#endif /* CONFIG_IRQBALANCE */ + #ifndef CONFIG_SMP void fastcall send_IPI_self(int vector) { @@ -1188,6 +1609,7 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq) */ static void ack_edge_ioapic_irq(unsigned int irq) { + move_irq(irq); if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_DISABLED)) mask_IO_APIC_irq(irq); @@ -1215,13 +1637,12 @@ static unsigned int startup_level_ioapic_irq (unsigned int irq) return 0; /* don't check for pending */ } -static void mask_and_ack_level_ioapic_irq (unsigned int irq) +static void end_level_ioapic_irq (unsigned int irq) { unsigned long v; int i; - mask_IO_APIC_irq(irq); - + move_irq(irq); /* * It appears there is an erratum which affects at least version 0x11 * of I/O APIC (that's the 82093AA and cores integrated into various @@ -1250,17 +1671,13 @@ static void mask_and_ack_level_ioapic_irq (unsigned int irq) if (!(v & (1 << (i & 0x1f)))) { atomic_inc(&irq_mis_count); spin_lock(&ioapic_lock); - __edge_IO_APIC_irq(irq); - __level_IO_APIC_irq(irq); + __mask_and_edge_IO_APIC_irq(irq); + __unmask_and_level_IO_APIC_irq(irq); spin_unlock(&ioapic_lock); } } -static void end_level_ioapic_irq (unsigned int irq) -{ - unmask_IO_APIC_irq(irq); -} - +#ifdef CONFIG_PCI_MSI static unsigned int startup_edge_ioapic_vector(unsigned int vector) { int irq = vector_to_irq(vector); @@ -1282,13 +1699,6 @@ static unsigned int startup_level_ioapic_vector (unsigned int vector) return startup_level_ioapic_irq (irq); } -static void mask_and_ack_level_ioapic_vector (unsigned int vector) -{ - int irq = vector_to_irq(vector); - - mask_and_ack_level_ioapic_irq(irq); -} - static void end_level_ioapic_vector (unsigned int vector) { int irq = vector_to_irq(vector); @@ -1317,11 +1727,7 @@ static void set_ioapic_affinity_vector (unsigned int vector, set_ioapic_affinity_irq(irq, cpu_mask); } - -static void noop_ioapic_vector(unsigned int vector) -{ - /* nothing */ -} +#endif /* * Level and edge triggered IO-APIC interrupts need different handling, @@ -1333,24 +1739,24 @@ static void noop_ioapic_vector(unsigned int vector) */ static struct hw_interrupt_type ioapic_edge_type = { .typename = "IO-APIC-edge", - .startup = startup_edge_ioapic_vector, - .shutdown = noop_ioapic_vector, - .enable = unmask_IO_APIC_vector, - .disable = noop_ioapic_vector, - .ack = ack_edge_ioapic_vector, - .end = noop_ioapic_vector, - .set_affinity = set_ioapic_affinity_vector, + .startup = startup_edge_ioapic, + .shutdown = shutdown_edge_ioapic, + .enable = enable_edge_ioapic, + .disable = disable_edge_ioapic, + .ack = ack_edge_ioapic, + .end = end_edge_ioapic, + .set_affinity = set_ioapic_affinity, }; static struct hw_interrupt_type ioapic_level_type = { .typename = "IO-APIC-level", - .startup = startup_level_ioapic_vector, - .shutdown = mask_IO_APIC_vector, - .enable = unmask_IO_APIC_vector, - .disable = mask_IO_APIC_vector, - .ack = mask_and_ack_level_ioapic_vector, - .end = end_level_ioapic_vector, - .set_affinity = set_ioapic_affinity_vector, + .startup = startup_level_ioapic, + .shutdown = shutdown_level_ioapic, + .enable = enable_level_ioapic, + .disable = disable_level_ioapic, + .ack = mask_and_ack_level_ioapic, + .end = end_level_ioapic, + .set_affinity = set_ioapic_affinity, }; static inline void init_IO_APIC_traps(void) @@ -1850,7 +2256,8 @@ int ioapic_guest_write(int apicid, int address, u32 val) return 0; /* Set the correct irq-handling type. */ - ioapic_register_intr(irq, rte.vector, rte.trigger); + irq_desc[irq].handler = rte.trigger ? + &ioapic_level_type: &ioapic_edge_type; /* Record the pin<->irq mapping. */ for ( entry = &irq_2_pin[irq]; ; entry = &irq_2_pin[entry->next] ) diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c index 784528ae74..aaaff647ce 100644 --- a/xen/arch/x86/irq.c +++ b/xen/arch/x86/irq.c @@ -186,30 +186,26 @@ typedef struct { struct exec_domain *guest[IRQ_MAX_GUESTS]; } irq_guest_action_t; -extern int vector_irq[]; - static void __do_IRQ_guest(int irq) { irq_desc_t *desc = &irq_desc[irq]; irq_guest_action_t *action = (irq_guest_action_t *)desc->action; struct exec_domain *ed; - int i, pirq; - - pirq = platform_legacy_irq(irq) ? irq : vector_irq[irq]; + int i; for ( i = 0; i < action->nr_guests; i++ ) { ed = action->guest[i]; - if ( !test_and_set_bit(pirq, &ed->domain->pirq_mask) ) + if ( !test_and_set_bit(irq, &ed->domain->pirq_mask) ) action->in_flight++; - send_guest_pirq(ed, pirq); + send_guest_pirq(ed, irq); } } int pirq_guest_unmask(struct domain *d) { irq_desc_t *desc; - unsigned int i, j, pirq, vector; + unsigned int i, j, pirq; u32 m; shared_info_t *s = d->shared_info; @@ -221,13 +217,12 @@ int pirq_guest_unmask(struct domain *d) j = find_first_set_bit(m); m &= ~(1 << j); pirq = (i << 5) + j; - vector = platform_legacy_irq(pirq) ? pirq : IO_APIC_VECTOR(pirq); - desc = &irq_desc[vector]; + desc = &irq_desc[pirq]; spin_lock_irq(&desc->lock); if ( !test_bit(d->pirq_to_evtchn[pirq], &s->evtchn_mask[0]) && test_and_clear_bit(pirq, &d->pirq_mask) && (--((irq_guest_action_t *)desc->action)->in_flight == 0) ) - desc->handler->end(vector); + desc->handler->end(pirq); spin_unlock_irq(&desc->lock); } } @@ -238,17 +233,14 @@ int pirq_guest_unmask(struct domain *d) int pirq_guest_bind(struct exec_domain *ed, int irq, int will_share) { struct domain *d = ed->domain; - irq_desc_t *desc; + irq_desc_t *desc = &irq_desc[irq]; irq_guest_action_t *action; unsigned long flags; - int rc = 0, vector; + int rc = 0; if ( !IS_CAPABLE_PHYSDEV(d) ) return -EPERM; - vector = platform_legacy_irq(irq) ? irq : IO_APIC_VECTOR(irq); - desc = &irq_desc[vector]; - spin_lock_irqsave(&desc->lock, flags); action = (irq_guest_action_t *)desc->action; @@ -278,12 +270,12 @@ int pirq_guest_bind(struct exec_domain *ed, int irq, int will_share) desc->depth = 0; desc->status |= IRQ_GUEST; desc->status &= ~IRQ_DISABLED; - desc->handler->startup(vector); + desc->handler->startup(irq); /* Attempt to bind the interrupt target to the correct CPU. */ if ( desc->handler->set_affinity != NULL ) desc->handler->set_affinity( - vector, apicid_to_phys_cpu_present(ed->processor)); + irq, apicid_to_phys_cpu_present(ed->processor)); } else if ( !will_share || !action->shareable ) { @@ -309,13 +301,10 @@ int pirq_guest_bind(struct exec_domain *ed, int irq, int will_share) int pirq_guest_unbind(struct domain *d, int irq) { - irq_desc_t *desc; + irq_desc_t *desc = &irq_desc[irq]; irq_guest_action_t *action; unsigned long flags; - int i, vector; - - vector = platform_legacy_irq(irq) ? irq : IO_APIC_VECTOR(irq); - desc = &irq_desc[vector]; + int i; spin_lock_irqsave(&desc->lock, flags); @@ -323,7 +312,7 @@ int pirq_guest_unbind(struct domain *d, int irq) if ( test_and_clear_bit(irq, &d->pirq_mask) && (--action->in_flight == 0) ) - desc->handler->end(vector); + desc->handler->end(irq); if ( action->nr_guests == 1 ) { @@ -332,7 +321,7 @@ int pirq_guest_unbind(struct domain *d, int irq) desc->depth = 1; desc->status |= IRQ_DISABLED; desc->status &= ~IRQ_GUEST; - desc->handler->shutdown(vector); + desc->handler->shutdown(irq); } else { @@ -346,3 +335,26 @@ int pirq_guest_unbind(struct domain *d, int irq) spin_unlock_irqrestore(&desc->lock, flags); return 0; } + +int pirq_guest_bindable(int irq, int will_share) +{ + irq_desc_t *desc = &irq_desc[irq]; + irq_guest_action_t *action; + unsigned long flags; + int okay; + + spin_lock_irqsave(&desc->lock, flags); + + action = (irq_guest_action_t *)desc->action; + + /* + * To be bindable the IRQ must either be not currently bound (1), or + * it must be shareable (2) and not at its share limit (3). + */ + okay = ((!(desc->status & IRQ_GUEST) && (action == NULL)) || /* 1 */ + (action->shareable && will_share && /* 2 */ + (action->nr_guests != IRQ_MAX_GUESTS))); /* 3 */ + + spin_unlock_irqrestore(&desc->lock, flags); + return okay; +} diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c index 048fca68ee..5de96ec96d 100644 --- a/xen/arch/x86/physdev.c +++ b/xen/arch/x86/physdev.c @@ -41,7 +41,7 @@ long do_physdev_op(physdev_op_t *uop) { physdev_op_t op; long ret; - int irq, vector; + int irq; if ( unlikely(copy_from_user(&op, uop, sizeof(op)) != 0) ) return -EFAULT; @@ -87,13 +87,8 @@ long do_physdev_op(physdev_op_t *uop) if ( (irq = op.u.irq_op.irq) >= NR_IRQS ) return -EINVAL; - op.u.irq_op.vector = vector = assign_irq_vector(irq); - - if ( use_pci_vector() && !platform_legacy_irq(irq) ) - set_intr_gate(vector, interrupt[vector]); - else - set_intr_gate(vector, interrupt[irq]); - + op.u.irq_op.vector = assign_irq_vector(irq); + set_intr_gate(op.u.irq_op.vector, interrupt[irq]); ret = 0; break; diff --git a/xen/include/asm-x86/io_apic.h b/xen/include/asm-x86/io_apic.h index 86aa452961..5c71c08f58 100644 --- a/xen/include/asm-x86/io_apic.h +++ b/xen/include/asm-x86/io_apic.h @@ -14,7 +14,45 @@ #ifdef CONFIG_X86_IO_APIC +#ifdef CONFIG_PCI_MSI static inline int use_pci_vector(void) {return 1;} +static inline void disable_edge_ioapic_vector(unsigned int vector) { } +static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { } +static inline void end_edge_ioapic_vector (unsigned int vector) { } +#define startup_level_ioapic startup_level_ioapic_vector +#define shutdown_level_ioapic mask_IO_APIC_vector +#define enable_level_ioapic unmask_IO_APIC_vector +#define disable_level_ioapic mask_IO_APIC_vector +#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector +#define end_level_ioapic end_level_ioapic_vector +#define set_ioapic_affinity set_ioapic_affinity_vector + +#define startup_edge_ioapic startup_edge_ioapic_vector +#define shutdown_edge_ioapic disable_edge_ioapic_vector +#define enable_edge_ioapic unmask_IO_APIC_vector +#define disable_edge_ioapic disable_edge_ioapic_vector +#define ack_edge_ioapic ack_edge_ioapic_vector +#define end_edge_ioapic end_edge_ioapic_vector +#else +static inline int use_pci_vector(void) {return 0;} +static inline void disable_edge_ioapic_irq(unsigned int irq) { } +static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { } +static inline void end_edge_ioapic_irq (unsigned int irq) { } +#define startup_level_ioapic startup_level_ioapic_irq +#define shutdown_level_ioapic mask_IO_APIC_irq +#define enable_level_ioapic unmask_IO_APIC_irq +#define disable_level_ioapic mask_IO_APIC_irq +#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq +#define end_level_ioapic end_level_ioapic_irq +#define set_ioapic_affinity set_ioapic_affinity_irq + +#define startup_edge_ioapic startup_edge_ioapic_irq +#define shutdown_edge_ioapic disable_edge_ioapic_irq +#define enable_edge_ioapic unmask_IO_APIC_irq +#define disable_edge_ioapic disable_edge_ioapic_irq +#define ack_edge_ioapic ack_edge_ioapic_irq +#define end_edge_ioapic end_edge_ioapic_irq +#endif #define IO_APIC_BASE(idx) \ ((volatile int *)(__fix_to_virt(FIX_IO_APIC_BASE_0 + idx) \ diff --git a/xen/include/asm-x86/mach-default/irq_vectors_limits.h b/xen/include/asm-x86/mach-default/irq_vectors_limits.h index a0664d7f67..b330026e6f 100644 --- a/xen/include/asm-x86/mach-default/irq_vectors_limits.h +++ b/xen/include/asm-x86/mach-default/irq_vectors_limits.h @@ -1,8 +1,21 @@ #ifndef _ASM_IRQ_VECTORS_LIMITS_H #define _ASM_IRQ_VECTORS_LIMITS_H -/* MSI limits */ +#ifdef CONFIG_PCI_MSI #define NR_IRQS FIRST_SYSTEM_VECTOR #define NR_IRQ_VECTORS NR_IRQS +#else +#ifdef CONFIG_X86_IO_APIC +#define NR_IRQS 224 +# if (224 >= 32 * NR_CPUS) +# define NR_IRQ_VECTORS NR_IRQS +# else +# define NR_IRQ_VECTORS (32 * NR_CPUS) +# endif +#else +#define NR_IRQS 16 +#define NR_IRQ_VECTORS NR_IRQS +#endif +#endif #endif /* _ASM_IRQ_VECTORS_LIMITS_H */ diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h index 9de76b8ca1..f419f0c182 100644 --- a/xen/include/xen/irq.h +++ b/xen/include/xen/irq.h @@ -71,5 +71,6 @@ struct exec_domain; extern int pirq_guest_unmask(struct domain *p); extern int pirq_guest_bind(struct exec_domain *p, int irq, int will_share); extern int pirq_guest_unbind(struct domain *p, int irq); +extern int pirq_guest_bindable(int irq, int will_share); #endif /* __XEN_IRQ_H__ */ From 36cdeb644f3d814d2fdc3653cdbbcac4cb3d5577 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 10 May 2005 16:45:22 +0000 Subject: [PATCH 49/54] bitkeeper revision 1.1389.15.5 (4280e522q2MiQniUbfWd_2b5yEMlkA) Fix acknowledgement of level-triggered IOAPIC interrupts. This is a second checkin, after disentangling from aborted and utterly broken PCI-MSI changes. Signed-off-by: Keir Fraser --- xen/arch/x86/io_apic.c | 32 +++++++++++++++++++++++--------- xen/include/asm-x86/io_apic.h | 2 -- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c index 3e7c89cf0e..bb69348b14 100644 --- a/xen/arch/x86/io_apic.c +++ b/xen/arch/x86/io_apic.c @@ -145,16 +145,16 @@ static void __unmask_IO_APIC_irq (unsigned int irq) __modify_IO_APIC_irq(irq, 0, 0x00010000); } -/* mask = 1, trigger = 0 */ -static void __mask_and_edge_IO_APIC_irq (unsigned int irq) +/* trigger = 0 */ +static void __edge_IO_APIC_irq (unsigned int irq) { - __modify_IO_APIC_irq(irq, 0x00010000, 0x00008000); + __modify_IO_APIC_irq(irq, 0, 0x00008000); } -/* mask = 0, trigger = 1 */ -static void __unmask_and_level_IO_APIC_irq (unsigned int irq) +/* trigger = 1 */ +static void __level_IO_APIC_irq (unsigned int irq) { - __modify_IO_APIC_irq(irq, 0x00008000, 0x00010000); + __modify_IO_APIC_irq(irq, 0x00008000, 0); } static void mask_IO_APIC_irq (unsigned int irq) @@ -1637,12 +1637,14 @@ static unsigned int startup_level_ioapic_irq (unsigned int irq) return 0; /* don't check for pending */ } -static void end_level_ioapic_irq (unsigned int irq) +static void mask_and_ack_level_ioapic_irq (unsigned int irq) { unsigned long v; int i; move_irq(irq); + + mask_IO_APIC_irq(irq); /* * It appears there is an erratum which affects at least version 0x11 * of I/O APIC (that's the 82093AA and cores integrated into various @@ -1671,12 +1673,17 @@ static void end_level_ioapic_irq (unsigned int irq) if (!(v & (1 << (i & 0x1f)))) { atomic_inc(&irq_mis_count); spin_lock(&ioapic_lock); - __mask_and_edge_IO_APIC_irq(irq); - __unmask_and_level_IO_APIC_irq(irq); + __edge_IO_APIC_irq(irq); + __level_IO_APIC_irq(irq); spin_unlock(&ioapic_lock); } } +static void end_level_ioapic_irq (unsigned int irq) +{ + unmask_IO_APIC_irq(irq); +} + #ifdef CONFIG_PCI_MSI static unsigned int startup_edge_ioapic_vector(unsigned int vector) { @@ -1699,6 +1706,13 @@ static unsigned int startup_level_ioapic_vector (unsigned int vector) return startup_level_ioapic_irq (irq); } +static void mask_and_ack_level_ioapic_vector (unsigned int vector) +{ + int irq = vector_to_irq(vector); + + mask_and_ack_level_ioapic_irq(irq); +} + static void end_level_ioapic_vector (unsigned int vector) { int irq = vector_to_irq(vector); diff --git a/xen/include/asm-x86/io_apic.h b/xen/include/asm-x86/io_apic.h index 5c71c08f58..5e9448a847 100644 --- a/xen/include/asm-x86/io_apic.h +++ b/xen/include/asm-x86/io_apic.h @@ -17,7 +17,6 @@ #ifdef CONFIG_PCI_MSI static inline int use_pci_vector(void) {return 1;} static inline void disable_edge_ioapic_vector(unsigned int vector) { } -static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { } static inline void end_edge_ioapic_vector (unsigned int vector) { } #define startup_level_ioapic startup_level_ioapic_vector #define shutdown_level_ioapic mask_IO_APIC_vector @@ -36,7 +35,6 @@ static inline void end_edge_ioapic_vector (unsigned int vector) { } #else static inline int use_pci_vector(void) {return 0;} static inline void disable_edge_ioapic_irq(unsigned int irq) { } -static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { } static inline void end_edge_ioapic_irq (unsigned int irq) { } #define startup_level_ioapic startup_level_ioapic_irq #define shutdown_level_ioapic mask_IO_APIC_irq From 12c05f0e2505b1fe287e6acb57b828622dffbbe4 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Tue, 10 May 2005 22:28:46 +0000 Subject: [PATCH 50/54] bitkeeper revision 1.1389.15.6 (4281359ejSQPcJ7qoKDaeTFt7zBKUg) Clean up #include in a few places, and fix non-CONFIG_SMP builds. xen/slab.h has unused __ARCH_HAS_SLAB_ALLOCATOR removed, but I added back include xen/mm.h for the time being -- it can go after ia64 is cleaned up to include mm.h only where necessary. Signed-off-by: Keir Fraser --- xen/common/page_alloc.c | 1 + xen/common/schedule.c | 1 + xen/drivers/char/console.c | 2 +- xen/include/asm-x86/shadow.h | 1 + xen/include/xen/cpumask.h | 2 ++ xen/include/xen/slab.h | 9 +-------- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c index fb26edc69c..5a4115c82e 100644 --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/xen/common/schedule.c b/xen/common/schedule.c index fb2db1b30f..491c2f22ac 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -34,6 +34,7 @@ #include #include #include +#include #include /* opt_sched: scheduler - default to Borrowed Virtual Time */ diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index f20d664c91..d9eb0c474a 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -17,8 +17,8 @@ #include #include #include +#include #include -#include #include #include diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h index d991a51f93..202453194f 100644 --- a/xen/include/asm-x86/shadow.h +++ b/xen/include/asm-x86/shadow.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/xen/include/xen/cpumask.h b/xen/include/xen/cpumask.h index 33723fbd9a..4881447842 100644 --- a/xen/include/xen/cpumask.h +++ b/xen/include/xen/cpumask.h @@ -9,7 +9,9 @@ typedef u32 cpumask_t; +#ifndef cpu_online_map extern cpumask_t cpu_online_map; +#endif static inline int cpus_weight(cpumask_t w) { diff --git a/xen/include/xen/slab.h b/xen/include/xen/slab.h index c4c8231f78..a3a7daf7d6 100644 --- a/xen/include/xen/slab.h +++ b/xen/include/xen/slab.h @@ -3,12 +3,7 @@ #define __SLAB_H__ #include - -#ifdef __ARCH_HAS_SLAB_ALLOCATOR - -#include - -#else +#include /* Allocate space for typed object. */ #define xmalloc(_type) ((_type *)_xmalloc(sizeof(_type), __alignof__(_type))) @@ -32,6 +27,4 @@ static inline void *_xmalloc_array(size_t size, size_t align, size_t num) return _xmalloc(size * num, align); } -#endif /* __ARCH_HAS_SLAB_ALLOCATOR */ - #endif /* __SLAB_H__ */ From 8f0d79996d5945b769dd5cdca1fd331ea174ca88 Mon Sep 17 00:00:00 2001 From: "djm@kirby.fc.hp.com" Date: Tue, 10 May 2005 22:29:32 +0000 Subject: [PATCH 51/54] bitkeeper revision 1.1389.9.6 (428135ccBlRW99tjfmtjk5XjVtLT3A) Minor adaptations for common ACPI update and other common changes --- xen/arch/ia64/domain.c | 4 +-- xen/arch/ia64/irq.c | 2 ++ xen/arch/ia64/mm_init.c | 4 +-- xen/arch/ia64/patch/linux-2.6.11/unaligned.c | 32 +++++++++++++++++--- xen/arch/ia64/process.c | 4 +-- xen/arch/ia64/xenmisc.c | 8 +++++ xen/include/asm-ia64/config.h | 8 +++++ xen/include/asm-ia64/domain.h | 2 +- 8 files changed, 53 insertions(+), 11 deletions(-) diff --git a/xen/arch/ia64/domain.c b/xen/arch/ia64/domain.c index 056e9a711b..c20f025d7a 100644 --- a/xen/arch/ia64/domain.c +++ b/xen/arch/ia64/domain.c @@ -191,7 +191,7 @@ void arch_do_createdomain(struct exec_domain *ed) // stay on kernel stack because may get interrupts! // ia64_ret_from_clone (which b0 gets in new_thread) switches // to user stack - ed->thread.on_ustack = 0; + ed->arch._thread.on_ustack = 0; } void arch_do_boot_vcpu(struct exec_domain *p) @@ -261,7 +261,7 @@ void new_thread(struct exec_domain *ed, printf("new_thread: ed=%p, start_pc=%p, regs=%p, sw=%p, new_rbs=%p, IA64_STK_OFFSET=%p, &r8=%p\n", ed,start_pc,regs,sw,new_rbs,IA64_STK_OFFSET,®s->r8); sw->b0 = (unsigned long) &ia64_ret_from_clone; - ed->thread.ksp = (unsigned long) sw - 16; + ed->arch._thread.ksp = (unsigned long) sw - 16; //ed->thread_info->flags = 0; printk("new_thread, about to call init_all_rr\n"); init_all_rr(ed); diff --git a/xen/arch/ia64/irq.c b/xen/arch/ia64/irq.c index 1b4e277343..b04d49cc70 100644 --- a/xen/arch/ia64/irq.c +++ b/xen/arch/ia64/irq.c @@ -1406,9 +1406,11 @@ int pirq_guest_bind(struct exec_domain *d, int irq, int will_share) desc->handler->startup(irq); /* Attempt to bind the interrupt target to the correct CPU. */ +#if 0 /* FIXME CONFIG_SMP ??? */ if ( desc->handler->set_affinity != NULL ) desc->handler->set_affinity( irq, apicid_to_phys_cpu_present(d->processor)); +#endif } else if ( !will_share || !action->shareable ) { diff --git a/xen/arch/ia64/mm_init.c b/xen/arch/ia64/mm_init.c index d316e05357..0e3ce45dec 100644 --- a/xen/arch/ia64/mm_init.c +++ b/xen/arch/ia64/mm_init.c @@ -227,7 +227,7 @@ ia64_set_rbs_bot (void) if (stack_size > MAX_USER_STACK_SIZE) stack_size = MAX_USER_STACK_SIZE; - current->thread.rbs_bot = STACK_TOP - stack_size; + current->arch._thread.rbs_bot = STACK_TOP - stack_size; } /* @@ -255,7 +255,7 @@ printf("ia64_init_addr_space: called, not implemented\n"); if (vma) { memset(vma, 0, sizeof(*vma)); vma->vm_mm = current->mm; - vma->vm_start = current->thread.rbs_bot & PAGE_MASK; + vma->vm_start = current->arch._thread.rbs_bot & PAGE_MASK; vma->vm_end = vma->vm_start + PAGE_SIZE; vma->vm_page_prot = protection_map[VM_DATA_DEFAULT_FLAGS & 0x7]; vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE|VM_GROWSUP; diff --git a/xen/arch/ia64/patch/linux-2.6.11/unaligned.c b/xen/arch/ia64/patch/linux-2.6.11/unaligned.c index bcc165e95e..0ed114e064 100644 --- a/xen/arch/ia64/patch/linux-2.6.11/unaligned.c +++ b/xen/arch/ia64/patch/linux-2.6.11/unaligned.c @@ -1,5 +1,5 @@ --- ../../linux-2.6.11/arch/ia64/kernel/unaligned.c 2005-03-02 00:38:25.000000000 -0700 -+++ arch/ia64/unaligned.c 2005-04-28 15:40:13.000000000 -0600 ++++ arch/ia64/unaligned.c 2005-05-10 15:46:09.000000000 -0600 @@ -437,7 +437,11 @@ } @@ -12,7 +12,31 @@ setreg (unsigned long regnum, unsigned long val, int nat, struct pt_regs *regs) { struct switch_stack *sw = (struct switch_stack *) regs - 1; -@@ -611,7 +615,11 @@ +@@ -522,7 +526,11 @@ + */ + if (regnum >= IA64_FIRST_ROTATING_FR) { + ia64_sync_fph(current); ++#ifdef XEN ++ current->arch._thread.fph[fph_index(regs, regnum)] = *fpval; ++#else + current->thread.fph[fph_index(regs, regnum)] = *fpval; ++#endif + } else { + /* + * pt_regs or switch_stack ? +@@ -581,7 +589,11 @@ + */ + if (regnum >= IA64_FIRST_ROTATING_FR) { + ia64_flush_fph(current); ++#ifdef XEN ++ *fpval = current->arch._thread.fph[fph_index(regs, regnum)]; ++#else + *fpval = current->thread.fph[fph_index(regs, regnum)]; ++#endif + } else { + /* + * f0 = 0.0, f1= 1.0. Those registers are constant and are thus +@@ -611,7 +623,11 @@ } @@ -24,7 +48,7 @@ getreg (unsigned long regnum, unsigned long *val, int *nat, struct pt_regs *regs) { struct switch_stack *sw = (struct switch_stack *) regs - 1; -@@ -1294,6 +1302,9 @@ +@@ -1294,6 +1310,9 @@ void ia64_handle_unaligned (unsigned long ifa, struct pt_regs *regs) { @@ -34,7 +58,7 @@ struct ia64_psr *ipsr = ia64_psr(regs); mm_segment_t old_fs = get_fs(); unsigned long bundle[2]; -@@ -1502,4 +1513,5 @@ +@@ -1502,4 +1521,5 @@ si.si_imm = 0; force_sig_info(SIGBUS, &si, current); goto done; diff --git a/xen/arch/ia64/process.c b/xen/arch/ia64/process.c index 1e0c10f53f..dd9e58071f 100644 --- a/xen/arch/ia64/process.c +++ b/xen/arch/ia64/process.c @@ -517,7 +517,7 @@ printf("ia64_fault, vector=0x%p, ifa=%p, iip=%p, ipsr=%p, isr=%p\n", case 32: /* fp fault */ case 33: /* fp trap */ //result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr); - if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) { + //if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) { //siginfo.si_signo = SIGFPE; //siginfo.si_errno = 0; //siginfo.si_code = FPE_FLTINV; @@ -526,7 +526,7 @@ printf("ia64_fault, vector=0x%p, ifa=%p, iip=%p, ipsr=%p, isr=%p\n", //siginfo.si_isr = isr; //siginfo.si_imm = 0; //force_sig_info(SIGFPE, &siginfo, current); - } + //} //return; sprintf(buf, "FP fault/trap"); break; diff --git a/xen/arch/ia64/xenmisc.c b/xen/arch/ia64/xenmisc.c index 09dfc2a7b9..189c30b908 100644 --- a/xen/arch/ia64/xenmisc.c +++ b/xen/arch/ia64/xenmisc.c @@ -79,6 +79,14 @@ void raise_actimer_softirq(void) raise_softirq(AC_TIMER_SOFTIRQ); } +unsigned long __hypercall_create_continuation( + unsigned int op, unsigned int nr_args, ...) +{ + printf("__hypercall_create_continuation: not implemented!!!\n"); +} + +/////////////////////////////// + /////////////////////////////// // from arch/x86/apic.c /////////////////////////////// diff --git a/xen/include/asm-ia64/config.h b/xen/include/asm-ia64/config.h index 0a3672b18e..52e42933bb 100644 --- a/xen/include/asm-ia64/config.h +++ b/xen/include/asm-ia64/config.h @@ -258,6 +258,14 @@ struct screen_info { }; #define seq_printf(a,b...) printf(b) #define CONFIG_BLK_DEV_INITRD // needed to reserve memory for domain0 +// +#define __smp_processor_id() (current->processor) + +// needed for newer ACPI code +#define asmlinkage + +#define FORCE_CRASH() asm("break 0;;"); + // these declarations got moved at some point, find a better place for them extern int opt_noht; extern int ht_per_core; diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h index 619d450a00..7b6758078e 100644 --- a/xen/include/asm-ia64/domain.h +++ b/xen/include/asm-ia64/domain.h @@ -60,7 +60,7 @@ struct arch_exec_domain { }; #define active_mm arch.active_mm -#define thread arch._thread +//#define thread arch._thread // FOLLOWING FROM linux-2.6.7/include/sched.h From 8efee444866b6320cb3aaaf185cafd35d4e73a4f Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Wed, 11 May 2005 08:05:14 +0000 Subject: [PATCH 52/54] bitkeeper revision 1.1389.15.8 (4281bcbaUAXd-mXY9bU_xjLtHjFVJg) Xen parses IOAPIC entries in the ACPI MADT. Signed-off-by: Keir Fraser --- xen/arch/x86/acpi/boot.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/xen/arch/x86/acpi/boot.c b/xen/arch/x86/acpi/boot.c index 7237d5e7e2..c8525bce64 100644 --- a/xen/arch/x86/acpi/boot.c +++ b/xen/arch/x86/acpi/boot.c @@ -37,7 +37,9 @@ #include #include -int sbf_port; /* XXX XEN */ +int sbf_port; +#define end_pfn_map max_page +#define CONFIG_ACPI_PCI #ifdef CONFIG_X86_64 @@ -109,7 +111,7 @@ char *__acpi_map_table(unsigned long phys_addr, unsigned long size) if (!phys_addr || !size) return NULL; - if (phys_addr < (max_page << PAGE_SHIFT)) + if (phys_addr < (end_pfn_map << PAGE_SHIFT)) return __va(phys_addr); return NULL; @@ -279,7 +281,7 @@ acpi_parse_lapic_nmi ( #endif /*CONFIG_X86_LOCAL_APIC*/ -#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_ACPI_INTERPRETER) +#if defined(CONFIG_X86_IO_APIC) /*&& defined(CONFIG_ACPI_INTERPRETER)*/ static int __init acpi_parse_ioapic ( @@ -302,6 +304,7 @@ acpi_parse_ioapic ( return 0; } +#ifdef CONFIG_ACPI_INTERPRETER /* * Parse Interrupt Source Override for the ACPI SCI */ @@ -335,6 +338,7 @@ acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger) acpi_sci_override_gsi = gsi; return; } +#endif static int __init acpi_parse_int_src_ovr ( @@ -349,11 +353,13 @@ acpi_parse_int_src_ovr ( acpi_table_print_madt_entry(header); +#ifdef CONFIG_ACPI_INTERPRETER if (intsrc->bus_irq == acpi_fadt.sci_int) { acpi_sci_ioapic_setup(intsrc->global_irq, intsrc->flags.polarity, intsrc->flags.trigger); return 0; } +#endif if (acpi_skip_timer_override && intsrc->bus_irq == 0 && intsrc->global_irq == 2) { @@ -698,7 +704,7 @@ acpi_parse_madt_lapic_entries(void) } #endif /* CONFIG_X86_LOCAL_APIC */ -#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_ACPI_INTERPRETER) +#if defined(CONFIG_X86_IO_APIC) /*&& defined(CONFIG_ACPI_INTERPRETER)*/ /* * Parse IOAPIC related entries in MADT * returns 0 on success, < 0 on error @@ -744,12 +750,14 @@ acpi_parse_madt_ioapic_entries(void) return count; } +#ifdef CONFIG_ACPI_INTERPRETER /* * If BIOS did not supply an INT_SRC_OVR for the SCI * pretend we got one so we can set the SCI flags. */ if (!acpi_sci_override_gsi) acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0); +#endif /* Fill in identity legacy mapings where no override */ mp_config_acpi_legacy_irqs(); @@ -856,10 +864,6 @@ acpi_boot_table_init(void) return error; } -#if 0 /*def __i386__*/ - check_acpi_pci(); -#endif - acpi_table_parse(ACPI_BOOT, acpi_parse_sbf); /* From 5d943913483ae4791aa2a7097414e9bc25fd0b90 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Wed, 11 May 2005 08:19:17 +0000 Subject: [PATCH 53/54] bitkeeper revision 1.1389.15.8 (4281c005VbqFpMOn_OwOw1JKlDQBiQ) added tag ia64-stable --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index f6001e15b5..dfe9bc1c82 100644 --- a/.hgtags +++ b/.hgtags @@ -5,6 +5,7 @@ dc2f08429f17e6614fd2f1ab88cc09ca0a850f32 RELEASE-2.0.2 fb875591fd72e15c31879c0e9034d99b80225595 RELEASE-2.0.4 1a522944f76540ea9d73fcc1b0d13d0f670183f0 RELEASE-2.0.5 487b2ee37d1cecb5f3e7a546b05ad097a0226f2f beta1 +1f84d0497a5901b9f8d1a051b87871d140b7e23f ia64-stable 3d330e41f41ce1bc118c02346e18949ad5d67f6b latest-semistable 30c521db4c71960b0cf1d9c9e1b658e77b535a3e latest-stable 9afec5bc14aeb197ef37ea54a57eacd427463fc3 semistable From e7e68bca44b95d9efe6b847e1d7755fec1b112a8 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Wed, 11 May 2005 08:31:59 +0000 Subject: [PATCH 54/54] bitkeeper revision 1.1389.15.9 (4281c2ffL85lCEE0o1Tvr8CCJWkhGw) Remove generic pci.h and ioport.h header files. Signed-off-by: Keir Fraser --- .rootkeys | 3 - xen/arch/x86/mtrr/main.c | 20 - xen/arch/x86/setup.c | 1 - xen/common/resource.c | 329 --------------- xen/include/xen/ioport.h | 117 ------ xen/include/xen/pci.h | 834 --------------------------------------- 6 files changed, 1304 deletions(-) delete mode 100644 xen/common/resource.c delete mode 100644 xen/include/xen/ioport.h delete mode 100644 xen/include/xen/pci.h diff --git a/.rootkeys b/.rootkeys index 7ebe26cf81..8ccf169cef 100644 --- a/.rootkeys +++ b/.rootkeys @@ -1264,7 +1264,6 @@ 41a61536SZbR6cj1ukWTb0DYU-vz9w xen/common/multicall.c 3ddb79bdD4SLmmdMD7yLW5HcUWucXw xen/common/page_alloc.c 3e54c38dkHAev597bPr71-hGzTdocg xen/common/perfc.c -3ddb79bdHqdQpATqC0rmUZNbsb6L6A xen/common/resource.c 40589968dD2D1aejwSOvrROg7fOvGQ xen/common/sched_bvt.c 41ebbfe9oF1BF3cH5v7yE3eOL9uPbA xen/common/sched_sedf.c 3e397e6619PgAfBbw2XFbXkewvUWgw xen/common/schedule.c @@ -1452,7 +1451,6 @@ 41262590CyJy4vd42dnqzsn8-eeGvw xen/include/xen/grant_table.h 3ddb79c0GurNF9tDWqQbAwJFH8ugfA xen/include/xen/init.h 428084e41zemtCAtYLcD9bUzwE35SA xen/include/xen/inttypes.h -3ddb79c1nzaWu8NoF4xCCMSFJR4MlA xen/include/xen/ioport.h 3ddb79c2qAxCOABlkKtD8Txohe-qEw xen/include/xen/irq.h 3ddb79c2b3qe-6Ann09FqZBF4IrJaQ xen/include/xen/irq_cpustat.h 3e4540ccPHqIIv2pvnQ1gV8LUnoHIg xen/include/xen/kernel.h @@ -1462,7 +1460,6 @@ 3ddb79c1gs2VbLbQlw0dcDUXYIepDA xen/include/xen/mm.h 3ddb79c1ieLZfGSFwfvvSQ2NK1BMSg xen/include/xen/multiboot.h 41a61536ii6j2lJ2rXwMOLaG1CHPvw xen/include/xen/multicall.h -3ddb79c2Fg44_PBPVxHSC0gTOMq4Ow xen/include/xen/pci.h 3ddb79c0MOVXq8qZDQRGb6z64_xAwg xen/include/xen/pci_ids.h 3e54c38dlSCVdyVM4PKcrSfzLLxWUQ xen/include/xen/perfc.h 3e54c38de9SUSYSAwxDf_DwkpAnQFA xen/include/xen/perfc_defn.h diff --git a/xen/arch/x86/mtrr/main.c b/xen/arch/x86/mtrr/main.c index b7c4713c69..b6122d9d02 100644 --- a/xen/arch/x86/mtrr/main.c +++ b/xen/arch/x86/mtrr/main.c @@ -33,7 +33,6 @@ #include #include -#include #include #include #include @@ -97,25 +96,6 @@ void set_mtrr_ops(struct mtrr_ops * ops) /* Returns non-zero if we have the write-combining memory type */ static int have_wrcomb(void) { - struct pci_dev *dev; - - if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) { - /* ServerWorks LE chipsets have problems with write-combining - Don't allow it and leave room for other chipsets to be tagged */ - if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS && - dev->device == PCI_DEVICE_ID_SERVERWORKS_LE) { - printk(KERN_INFO "mtrr: Serverworks LE detected. Write-combining disabled.\n"); - return 0; - } - /* Intel 450NX errata # 23. Non ascending cachline evictions to - write combining memory may resulting in data corruption */ - if (dev->vendor == PCI_VENDOR_ID_INTEL && - dev->device == PCI_DEVICE_ID_INTEL_82451NX) - { - printk(KERN_INFO "mtrr: Intel 450NX MMC detected. Write-combining disabled.\n"); - return 0; - } - } return (mtrr_if->have_wrcomb ? mtrr_if->have_wrcomb() : 0); } diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index ac659a52de..7310095f64 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include diff --git a/xen/common/resource.c b/xen/common/resource.c deleted file mode 100644 index 5f264c9806..0000000000 --- a/xen/common/resource.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * linux/kernel/resource.c - * - * Copyright (C) 1999 Linus Torvalds - * Copyright (C) 1999 Martin Mares - * - * Arbitrary resource management. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct resource ioport_resource = { "PCI IO", 0x0000, IO_SPACE_LIMIT, IORESOURCE_IO }; -struct resource iomem_resource = { "PCI mem", 0x00000000, 0xffffffff, IORESOURCE_MEM }; - -static rwlock_t resource_lock = RW_LOCK_UNLOCKED; - -/* - * This generates reports for /proc/ioports and /proc/iomem - */ -static char * do_resource_list(struct resource *entry, const char *fmt, int offset, char *buf, char *end) -{ - if (offset < 0) - offset = 0; - - while (entry) { - const char *name = entry->name; - unsigned long from, to; - - if ((int) (end-buf) < 80) - return buf; - - from = entry->start; - to = entry->end; - if (!name) - name = ""; - - buf += sprintf(buf, fmt + offset, from, to, name); - if (entry->child) - buf = do_resource_list(entry->child, fmt, offset-2, buf, end); - entry = entry->sibling; - } - - return buf; -} - -int get_resource_list(struct resource *root, char *buf, int size) -{ - char *fmt; - int retval; - - fmt = " %08lx-%08lx : %s\n"; - if (root->end < 0x10000) - fmt = " %04lx-%04lx : %s\n"; - read_lock(&resource_lock); - retval = do_resource_list(root->child, fmt, 8, buf, buf + size) - buf; - read_unlock(&resource_lock); - return retval; -} - -/* Return the conflict entry if you can't request it */ -static struct resource * __request_resource(struct resource *root, struct resource *new) -{ - unsigned long start = new->start; - unsigned long end = new->end; - struct resource *tmp, **p; - - if (end < start) - return root; - if (start < root->start) - return root; - if (end > root->end) - return root; - p = &root->child; - for (;;) { - tmp = *p; - if (!tmp || tmp->start > end) { - new->sibling = tmp; - *p = new; - new->parent = root; - return NULL; - } - p = &tmp->sibling; - if (tmp->end < start) - continue; - return tmp; - } -} - -static int __release_resource(struct resource *old) -{ - struct resource *tmp, **p; - - p = &old->parent->child; - for (;;) { - tmp = *p; - if (!tmp) - break; - if (tmp == old) { - *p = tmp->sibling; - old->parent = NULL; - return 0; - } - p = &tmp->sibling; - } - return -EINVAL; -} - -int request_resource(struct resource *root, struct resource *new) -{ - struct resource *conflict; - - write_lock(&resource_lock); - conflict = __request_resource(root, new); - write_unlock(&resource_lock); - return conflict ? -EBUSY : 0; -} - -int release_resource(struct resource *old) -{ - int retval; - - write_lock(&resource_lock); - retval = __release_resource(old); - write_unlock(&resource_lock); - return retval; -} - -int check_resource(struct resource *root, unsigned long start, unsigned long len) -{ - struct resource *conflict, tmp; - - tmp.start = start; - tmp.end = start + len - 1; - write_lock(&resource_lock); - conflict = __request_resource(root, &tmp); - if (!conflict) - __release_resource(&tmp); - write_unlock(&resource_lock); - return conflict ? -EBUSY : 0; -} - -/* - * Find empty slot in the resource tree given range and alignment. - */ -static int find_resource(struct resource *root, struct resource *new, - unsigned long size, - unsigned long min, unsigned long max, - unsigned long align, - void (*alignf)(void *, struct resource *, - unsigned long, unsigned long), - void *alignf_data) -{ - struct resource *this = root->child; - - new->start = root->start; - for(;;) { - if (this) - new->end = this->start; - else - new->end = root->end; - if (new->start < min) - new->start = min; - if (new->end > max) - new->end = max; - new->start = (new->start + align - 1) & ~(align - 1); - if (alignf) - alignf(alignf_data, new, size, align); - if (new->start < new->end && new->end - new->start + 1 >= size) { - new->end = new->start + size - 1; - return 0; - } - if (!this) - break; - new->start = this->end + 1; - this = this->sibling; - } - return -EBUSY; -} - -/* - * Allocate empty slot in the resource tree given range and alignment. - */ -int allocate_resource(struct resource *root, struct resource *new, - unsigned long size, - unsigned long min, unsigned long max, - unsigned long align, - void (*alignf)(void *, struct resource *, - unsigned long, unsigned long), - void *alignf_data) -{ - int err; - - write_lock(&resource_lock); - err = find_resource(root, new, size, min, max, align, alignf, alignf_data); - if (err >= 0 && __request_resource(root, new)) - err = -EBUSY; - write_unlock(&resource_lock); - return err; -} - -/* - * This is compatibility stuff for IO resources. - * - * Note how this, unlike the above, knows about - * the IO flag meanings (busy etc). - * - * Request-region creates a new busy region. - * - * Check-region returns non-zero if the area is already busy - * - * Release-region releases a matching busy region. - */ -struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name) -{ - struct resource *res = xmalloc(struct resource); - - if (res) { - memset(res, 0, sizeof(*res)); - res->name = name; - res->start = start; - res->end = start + n - 1; - res->flags = IORESOURCE_BUSY; - - write_lock(&resource_lock); - - for (;;) { - struct resource *conflict; - - conflict = __request_resource(parent, res); - if (!conflict) - break; - if (conflict != parent) { - parent = conflict; - if (!(conflict->flags & IORESOURCE_BUSY)) - continue; - } - - /* Uhhuh, that didn't work out.. */ - xfree(res); - res = NULL; - break; - } - write_unlock(&resource_lock); - } - return res; -} - -void __release_region(struct resource *parent, unsigned long start, unsigned long n) -{ - struct resource **p; - unsigned long end; - - p = &parent->child; - end = start + n - 1; - - for (;;) { - struct resource *res = *p; - - if (!res) - break; - if (res->start <= start && res->end >= end) { - if (!(res->flags & IORESOURCE_BUSY)) { - p = &res->child; - continue; - } - if (res->start != start || res->end != end) - break; - *p = res->sibling; - xfree(res); - return; - } - p = &res->sibling; - } - printk("Trying to free nonexistent resource <%08lx-%08lx>\n", start, end); -} - - -#if 0 -/* - * Called from init/main.c to reserve IO ports. - */ -#define MAXRESERVE 4 -static int __init reserve_setup(char *str) -{ - static int reserved = 0; - static struct resource reserve[MAXRESERVE]; - - for (;;) { - int io_start, io_num; - int x = reserved; - - if (get_option (&str, &io_start) != 2) - break; - if (get_option (&str, &io_num) == 0) - break; - if (x < MAXRESERVE) { - struct resource *res = reserve + x; - res->name = "reserved"; - res->start = io_start; - res->end = io_start + io_num - 1; - res->flags = IORESOURCE_BUSY; - res->child = NULL; - if (request_resource(res->start >= 0x10000 ? &iomem_resource : &ioport_resource, res) == 0) - reserved = x+1; - } - } - return 1; -} - -__setup("reserve=", reserve_setup); -#endif - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 8 - * tab-width: 8 - * indent-tabs-mode: t - * End: - */ diff --git a/xen/include/xen/ioport.h b/xen/include/xen/ioport.h deleted file mode 100644 index b39d07ae32..0000000000 --- a/xen/include/xen/ioport.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * ioport.h Definitions of routines for detecting, reserving and - * allocating system resources. - * - * Authors: Linus Torvalds - */ - -#ifndef _LINUX_IOPORT_H -#define _LINUX_IOPORT_H - -/* - * Resources are tree-like, allowing - * nesting etc.. - */ -struct resource { - const char *name; - unsigned long start, end; - unsigned long flags; - struct resource *parent, *sibling, *child; -}; - -struct resource_list { - struct resource_list *next; - struct resource *res; - struct pci_dev *dev; -}; - -/* - * IO resources have these defined flags. - */ -#define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */ - -#define IORESOURCE_IO 0x00000100 /* Resource type */ -#define IORESOURCE_MEM 0x00000200 -#define IORESOURCE_IRQ 0x00000400 -#define IORESOURCE_DMA 0x00000800 - -#define IORESOURCE_PREFETCH 0x00001000 /* No side effects */ -#define IORESOURCE_READONLY 0x00002000 -#define IORESOURCE_CACHEABLE 0x00004000 -#define IORESOURCE_RANGELENGTH 0x00008000 -#define IORESOURCE_SHADOWABLE 0x00010000 -#define IORESOURCE_BUS_HAS_VGA 0x00080000 - -#define IORESOURCE_UNSET 0x20000000 -#define IORESOURCE_AUTO 0x40000000 -#define IORESOURCE_BUSY 0x80000000 /* Driver has marked this resource busy */ - -/* ISA PnP IRQ specific bits (IORESOURCE_BITS) */ -#define IORESOURCE_IRQ_HIGHEDGE (1<<0) -#define IORESOURCE_IRQ_LOWEDGE (1<<1) -#define IORESOURCE_IRQ_HIGHLEVEL (1<<2) -#define IORESOURCE_IRQ_LOWLEVEL (1<<3) - -/* ISA PnP DMA specific bits (IORESOURCE_BITS) */ -#define IORESOURCE_DMA_TYPE_MASK (3<<0) -#define IORESOURCE_DMA_8BIT (0<<0) -#define IORESOURCE_DMA_8AND16BIT (1<<0) -#define IORESOURCE_DMA_16BIT (2<<0) - -#define IORESOURCE_DMA_MASTER (1<<2) -#define IORESOURCE_DMA_BYTE (1<<3) -#define IORESOURCE_DMA_WORD (1<<4) - -#define IORESOURCE_DMA_SPEED_MASK (3<<6) -#define IORESOURCE_DMA_COMPATIBLE (0<<6) -#define IORESOURCE_DMA_TYPEA (1<<6) -#define IORESOURCE_DMA_TYPEB (2<<6) -#define IORESOURCE_DMA_TYPEF (3<<6) - -/* ISA PnP memory I/O specific bits (IORESOURCE_BITS) */ -#define IORESOURCE_MEM_WRITEABLE (1<<0) /* dup: IORESOURCE_READONLY */ -#define IORESOURCE_MEM_CACHEABLE (1<<1) /* dup: IORESOURCE_CACHEABLE */ -#define IORESOURCE_MEM_RANGELENGTH (1<<2) /* dup: IORESOURCE_RANGELENGTH */ -#define IORESOURCE_MEM_TYPE_MASK (3<<3) -#define IORESOURCE_MEM_8BIT (0<<3) -#define IORESOURCE_MEM_16BIT (1<<3) -#define IORESOURCE_MEM_8AND16BIT (2<<3) -#define IORESOURCE_MEM_SHADOWABLE (1<<5) /* dup: IORESOURCE_SHADOWABLE */ -#define IORESOURCE_MEM_EXPANSIONROM (1<<6) - -/* PC/ISA/whatever - the normal PC address spaces: IO and memory */ -extern struct resource ioport_resource; -extern struct resource iomem_resource; - -extern int get_resource_list(struct resource *, char *buf, int size); - -extern int check_resource(struct resource *root, unsigned long, unsigned long); -extern int request_resource(struct resource *root, struct resource *new); -extern int release_resource(struct resource *new); -extern int allocate_resource(struct resource *root, struct resource *new, - unsigned long size, - unsigned long min, unsigned long max, - unsigned long align, - void (*alignf)(void *, struct resource *, - unsigned long, unsigned long), - void *alignf_data); - -/* Convenience shorthand with allocation */ -#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name)) -#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name)) - -#define release_region(start,n) __release_region(&ioport_resource, (start), (n)) -#define release_mem_region(start,n) __release_region(&iomem_resource, (start), (n)) - -extern void __release_region(struct resource *, unsigned long, unsigned long); - -extern struct resource * __request_region(struct resource *, unsigned long start, unsigned long n, const char *name); - -#define get_ioport_list(buf) get_resource_list(&ioport_resource, buf, PAGE_SIZE) -#define get_mem_list(buf) get_resource_list(&iomem_resource, buf, PAGE_SIZE) - -#define HAVE_AUTOIRQ -extern void autoirq_setup(int waittime); -extern int autoirq_report(int waittime); - -#endif /* _LINUX_IOPORT_H */ diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h deleted file mode 100644 index 046328d11e..0000000000 --- a/xen/include/xen/pci.h +++ /dev/null @@ -1,834 +0,0 @@ -/* - * $Id: pci.h,v 1.87 1998/10/11 15:13:12 mj Exp $ - * - * PCI defines and function prototypes - * Copyright 1994, Drew Eckhardt - * Copyright 1997--1999 Martin Mares - * - * For more information, please consult the following manuals (look at - * http://www.pcisig.com/ for how to get them): - * - * PCI BIOS Specification - * PCI Local Bus Specification - * PCI to PCI Bridge Specification - * PCI System Design Guide - */ - -#ifndef LINUX_PCI_H -#define LINUX_PCI_H - -/* - * Under PCI, each device has 256 bytes of configuration address space, - * of which the first 64 bytes are standardized as follows: - */ -#define PCI_VENDOR_ID 0x00 /* 16 bits */ -#define PCI_DEVICE_ID 0x02 /* 16 bits */ -#define PCI_COMMAND 0x04 /* 16 bits */ -#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ -#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ -#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ -#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */ -#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ -#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ -#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ -#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ -#define PCI_COMMAND_SERR 0x100 /* Enable SERR */ -#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ - -#define PCI_STATUS 0x06 /* 16 bits */ -#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ -#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ -#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ -#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ -#define PCI_STATUS_PARITY 0x100 /* Detected parity error */ -#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ -#define PCI_STATUS_DEVSEL_FAST 0x000 -#define PCI_STATUS_DEVSEL_MEDIUM 0x200 -#define PCI_STATUS_DEVSEL_SLOW 0x400 -#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */ -#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */ -#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */ -#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */ -#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */ - -#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 - revision */ -#define PCI_REVISION_ID 0x08 /* Revision ID */ -#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */ -#define PCI_CLASS_DEVICE 0x0a /* Device class */ - -#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */ -#define PCI_LATENCY_TIMER 0x0d /* 8 bits */ -#define PCI_HEADER_TYPE 0x0e /* 8 bits */ -#define PCI_HEADER_TYPE_NORMAL 0 -#define PCI_HEADER_TYPE_BRIDGE 1 -#define PCI_HEADER_TYPE_CARDBUS 2 - -#define PCI_BIST 0x0f /* 8 bits */ -#define PCI_BIST_CODE_MASK 0x0f /* Return result */ -#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */ -#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */ - -/* - * Base addresses specify locations in memory or I/O space. - * Decoded size can be determined by writing a value of - * 0xffffffff to the register, and reading it back. Only - * 1 bits are decoded. - */ -#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ -#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */ -#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */ -#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */ -#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */ -#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */ -#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */ -#define PCI_BASE_ADDRESS_SPACE_IO 0x01 -#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00 -#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06 -#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */ -#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */ -#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ -#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ -#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL) -#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL) -/* bit 1 is reserved if address_space = 1 */ - -/* Header type 0 (normal devices) */ -#define PCI_CARDBUS_CIS 0x28 -#define PCI_SUBSYSTEM_VENDOR_ID 0x2c -#define PCI_SUBSYSTEM_ID 0x2e -#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */ -#define PCI_ROM_ADDRESS_ENABLE 0x01 -#define PCI_ROM_ADDRESS_MASK (~0x7ffUL) - -#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ - -/* 0x35-0x3b are reserved */ -#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ -#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ -#define PCI_MIN_GNT 0x3e /* 8 bits */ -#define PCI_MAX_LAT 0x3f /* 8 bits */ - -/* Header type 1 (PCI-to-PCI bridges) */ -#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */ -#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ -#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */ -#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */ -#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */ -#define PCI_IO_LIMIT 0x1d -#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ -#define PCI_IO_RANGE_TYPE_16 0x00 -#define PCI_IO_RANGE_TYPE_32 0x01 -#define PCI_IO_RANGE_MASK (~0x0fUL) -#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */ -#define PCI_MEMORY_BASE 0x20 /* Memory range behind */ -#define PCI_MEMORY_LIMIT 0x22 -#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL -#define PCI_MEMORY_RANGE_MASK (~0x0fUL) -#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */ -#define PCI_PREF_MEMORY_LIMIT 0x26 -#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL -#define PCI_PREF_RANGE_TYPE_32 0x00 -#define PCI_PREF_RANGE_TYPE_64 0x01 -#define PCI_PREF_RANGE_MASK (~0x0fUL) -#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */ -#define PCI_PREF_LIMIT_UPPER32 0x2c -#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */ -#define PCI_IO_LIMIT_UPPER16 0x32 -/* 0x34 same as for htype 0 */ -/* 0x35-0x3b is reserved */ -#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */ -/* 0x3c-0x3d are same as for htype 0 */ -#define PCI_BRIDGE_CONTROL 0x3e -#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */ -#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */ -#define PCI_BRIDGE_CTL_NO_ISA 0x04 /* Disable bridging of ISA ports */ -#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */ -#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */ -#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */ -#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */ - -/* Header type 2 (CardBus bridges) */ -#define PCI_CB_CAPABILITY_LIST 0x14 -/* 0x15 reserved */ -#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */ -#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */ -#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */ -#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */ -#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */ -#define PCI_CB_MEMORY_BASE_0 0x1c -#define PCI_CB_MEMORY_LIMIT_0 0x20 -#define PCI_CB_MEMORY_BASE_1 0x24 -#define PCI_CB_MEMORY_LIMIT_1 0x28 -#define PCI_CB_IO_BASE_0 0x2c -#define PCI_CB_IO_BASE_0_HI 0x2e -#define PCI_CB_IO_LIMIT_0 0x30 -#define PCI_CB_IO_LIMIT_0_HI 0x32 -#define PCI_CB_IO_BASE_1 0x34 -#define PCI_CB_IO_BASE_1_HI 0x36 -#define PCI_CB_IO_LIMIT_1 0x38 -#define PCI_CB_IO_LIMIT_1_HI 0x3a -#define PCI_CB_IO_RANGE_MASK (~0x03UL) -/* 0x3c-0x3d are same as for htype 0 */ -#define PCI_CB_BRIDGE_CONTROL 0x3e -#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */ -#define PCI_CB_BRIDGE_CTL_SERR 0x02 -#define PCI_CB_BRIDGE_CTL_ISA 0x04 -#define PCI_CB_BRIDGE_CTL_VGA 0x08 -#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20 -#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */ -#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */ -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */ -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200 -#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400 -#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40 -#define PCI_CB_SUBSYSTEM_ID 0x42 -#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */ -/* 0x48-0x7f reserved */ - -/* Capability lists */ - -#define PCI_CAP_LIST_ID 0 /* Capability ID */ -#define PCI_CAP_ID_PM 0x01 /* Power Management */ -#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ -#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ -#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ -#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ -#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ -#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ -#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ -#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ -#define PCI_CAP_SIZEOF 4 - -/* Power Management Registers */ - -#define PCI_PM_PMC 2 /* PM Capabilities Register */ -#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */ -#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */ -#define PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */ -#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */ -#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxilliary power support mask */ -#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */ -#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */ -#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */ -#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */ -#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */ -#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */ -#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */ -#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */ -#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */ -#define PCI_PM_CTRL 4 /* PM control and status register */ -#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */ -#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */ -#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */ -#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */ -#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */ -#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */ -#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */ -#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable (??) */ -#define PCI_PM_DATA_REGISTER 7 /* (??) */ -#define PCI_PM_SIZEOF 8 - -/* AGP registers */ - -#define PCI_AGP_VERSION 2 /* BCD version number */ -#define PCI_AGP_RFU 3 /* Rest of capability flags */ -#define PCI_AGP_STATUS 4 /* Status register */ -#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */ -#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */ -#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */ -#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */ -#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */ -#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */ -#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */ -#define PCI_AGP_COMMAND 8 /* Control register */ -#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */ -#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */ -#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */ -#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */ -#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */ -#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */ -#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */ -#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */ -#define PCI_AGP_SIZEOF 12 - -/* Slot Identification */ - -#define PCI_SID_ESR 2 /* Expansion Slot Register */ -#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */ -#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */ -#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */ - -/* Message Signalled Interrupts registers */ - -#define PCI_MSI_FLAGS 2 /* Various flags */ -#define PCI_MSI_FLAGS_64BIT 0x80 /* 64-bit addresses allowed */ -#define PCI_MSI_FLAGS_QSIZE 0x70 /* Message queue size configured */ -#define PCI_MSI_FLAGS_QMASK 0x0e /* Maximum queue size available */ -#define PCI_MSI_FLAGS_ENABLE 0x01 /* MSI feature enabled */ -#define PCI_MSI_RFU 3 /* Rest of capability flags */ -#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */ -#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ -#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */ -#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ - -/* CompactPCI Hotswap Register */ - -#define PCI_CHSWP_CSR 2 /* Control and Status Register */ -#define PCI_CHSWP_DHA 0x01 /* Device Hiding Arm */ -#define PCI_CHSWP_EIM 0x02 /* ENUM# Signal Mask */ -#define PCI_CHSWP_PIE 0x04 /* Pending Insert or Extract */ -#define PCI_CHSWP_LOO 0x08 /* LED On / Off */ -#define PCI_CHSWP_PI 0x30 /* Programming Interface */ -#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */ -#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */ - -/* PCI-X registers */ - -#define PCI_X_CMD 2 /* Modes & Features */ -#define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */ -#define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */ -#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ -#define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions */ -#define PCI_X_DEVFN 4 /* A copy of devfn. */ -#define PCI_X_BUSNR 5 /* Bus segment number */ -#define PCI_X_STATUS 6 /* PCI-X capabilities */ -#define PCI_X_STATUS_64BIT 0x0001 /* 64-bit device */ -#define PCI_X_STATUS_133MHZ 0x0002 /* 133 MHz capable */ -#define PCI_X_STATUS_SPL_DISC 0x0004 /* Split Completion Discarded */ -#define PCI_X_STATUS_UNX_SPL 0x0008 /* Unexpected Split Completion */ -#define PCI_X_STATUS_COMPLEX 0x0010 /* Device Complexity */ -#define PCI_X_STATUS_MAX_READ 0x0060 /* Designed Maximum Memory Read Count */ -#define PCI_X_STATUS_MAX_SPLIT 0x0380 /* Design Max Outstanding Split Trans */ -#define PCI_X_STATUS_MAX_CUM 0x1c00 /* Designed Max Cumulative Read Size */ -#define PCI_X_STATUS_SPL_ERR 0x2000 /* Rcvd Split Completion Error Msg */ - -/* Include the ID list */ - -#include - -/* - * The PCI interface treats multi-function devices as independent - * devices. The slot/function address of each device is encoded - * in a single byte as follows: - * - * 7:3 = slot - * 2:0 = function - */ -#define PCI_DEVFN(slot,func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) -#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) -#define PCI_FUNC(devfn) ((devfn) & 0x07) - -/* Ioctls for /proc/bus/pci/X/Y nodes. */ -#define PCIIOC_BASE ('P' << 24 | 'C' << 16 | 'I' << 8) -#define PCIIOC_CONTROLLER (PCIIOC_BASE | 0x00) /* Get controller for PCI device. */ -#define PCIIOC_MMAP_IS_IO (PCIIOC_BASE | 0x01) /* Set mmap state to I/O space. */ -#define PCIIOC_MMAP_IS_MEM (PCIIOC_BASE | 0x02) /* Set mmap state to MEM space. */ -#define PCIIOC_WRITE_COMBINE (PCIIOC_BASE | 0x03) /* Enable/disable write-combining. */ - -#include -#include -#include -#include -#include - -/* File state for mmap()s on /proc/bus/pci/X/Y */ -enum pci_mmap_state { - pci_mmap_io, - pci_mmap_mem -}; - -/* This defines the direction arg to the DMA mapping routines. */ -#define PCI_DMA_BIDIRECTIONAL 0 -#define PCI_DMA_TODEVICE 1 -#define PCI_DMA_FROMDEVICE 2 -#define PCI_DMA_NONE 3 - -#define DEVICE_COUNT_COMPATIBLE 4 -#define DEVICE_COUNT_IRQ 2 -#define DEVICE_COUNT_DMA 2 -#define DEVICE_COUNT_RESOURCE 12 - -#define PCI_ANY_ID (~0) - -#define pci_present pcibios_present - - -#define pci_for_each_dev_reverse(dev) \ - for(dev = pci_dev_g(pci_devices.prev); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.prev)) - -#define pci_for_each_bus(bus) \ - list_for_each_entry(bus, &pci_root_buses, node) - -/* - * The pci_dev structure is used to describe both PCI and ISAPnP devices. - */ -struct pci_dev { - struct list_head global_list; /* node in list of all PCI devices */ - struct list_head bus_list; /* node in per-bus list */ - struct pci_bus *bus; /* bus this device is on */ - struct pci_bus *subordinate; /* bus this device bridges to */ - - void *sysdata; /* hook for sys-specific extension */ - struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */ - - unsigned int devfn; /* encoded device & function index */ - unsigned short vendor; - unsigned short device; - unsigned short subsystem_vendor; - unsigned short subsystem_device; - unsigned int class; /* 3 bytes: (base,sub,prog-if) */ - u8 hdr_type; /* PCI header type (`multi' flag masked out) */ - u8 rom_base_reg; /* which config register controls the ROM */ - - struct pci_driver *driver; /* which driver has allocated this device */ - void *driver_data; /* data private to the driver */ - u64 dma_mask; /* Mask of the bits of bus address this - device implements. Normally this is - 0xffffffff. You only need to change - this if your device has broken DMA - or supports 64-bit transfers. */ - - u32 current_state; /* Current operating state. In ACPI-speak, - this is D0-D3, D0 being fully functional, - and D3 being off. */ - -#ifdef LINUX_2_6 - struct device dev; /* Generic device interface */ -#endif - - /* device is compatible with these IDs */ - unsigned short vendor_compatible[DEVICE_COUNT_COMPATIBLE]; - unsigned short device_compatible[DEVICE_COUNT_COMPATIBLE]; - - /* - * Instead of touching interrupt line and base address registers - * directly, use the values stored here. They might be different! - */ - unsigned int irq; - struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */ - struct resource dma_resource[DEVICE_COUNT_DMA]; - struct resource irq_resource[DEVICE_COUNT_IRQ]; - - char name[90]; /* device name */ - char slot_name[8]; /* slot name */ - int active; /* ISAPnP: device is active */ - int ro; /* ISAPnP: read only */ - unsigned short regs; /* ISAPnP: supported registers */ - - /* These fields are used by common fixups */ - unsigned short transparent:1; /* Transparent PCI bridge */ - - int (*prepare)(struct pci_dev *dev); /* ISAPnP hooks */ - int (*activate)(struct pci_dev *dev); - int (*deactivate)(struct pci_dev *dev); -}; - -#define pci_dev_g(n) list_entry(n, struct pci_dev, global_list) -#define pci_dev_b(n) list_entry(n, struct pci_dev, bus_list) - -/* - * For PCI devices, the region numbers are assigned this way: - * - * 0-5 standard PCI regions - * 6 expansion ROM - * 7-10 bridges: address space assigned to buses behind the bridge - */ - -#define PCI_ROM_RESOURCE 6 -#define PCI_BRIDGE_RESOURCES 7 -#define PCI_NUM_RESOURCES 11 - -#define PCI_REGION_FLAG_MASK 0x0fU /* These bits of resource flags tell us the PCI region flags */ - -struct pci_bus { - struct list_head node; /* node in list of buses */ - struct pci_bus *parent; /* parent bus this bridge is on */ - struct list_head children; /* list of child buses */ - struct list_head devices; /* list of devices on this bus */ - struct pci_dev *self; /* bridge device as seen by parent */ - struct resource *resource[4]; /* address space routed to this bus */ - - struct pci_ops *ops; /* configuration access functions */ - void *sysdata; /* hook for sys-specific extension */ - struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */ - - unsigned char number; /* bus number */ - unsigned char primary; /* number of primary bridge */ - unsigned char secondary; /* number of secondary bridge */ - unsigned char subordinate; /* max number of subordinate buses */ - - char name[48]; - unsigned short vendor; - unsigned short device; - unsigned int serial; /* serial number */ - unsigned char pnpver; /* Plug & Play version */ - unsigned char productver; /* product version */ - unsigned char checksum; /* if zero - checksum passed */ - unsigned char pad1; -}; - -#define pci_bus_b(n) list_entry(n, struct pci_bus, node) - -extern struct list_head pci_root_buses; /* list of all known PCI buses */ -extern struct list_head pci_devices; /* list of all devices */ - -extern struct proc_dir_entry *proc_bus_pci_dir; -/* - * Error values that may be returned by PCI functions. - */ -#define PCIBIOS_SUCCESSFUL 0x00 -#define PCIBIOS_FUNC_NOT_SUPPORTED 0x81 -#define PCIBIOS_BAD_VENDOR_ID 0x83 -#define PCIBIOS_DEVICE_NOT_FOUND 0x86 -#define PCIBIOS_BAD_REGISTER_NUMBER 0x87 -#define PCIBIOS_SET_FAILED 0x88 -#define PCIBIOS_BUFFER_TOO_SMALL 0x89 - -/* Low-level architecture-dependent routines */ - -struct pci_ops { - int (*read_byte)(struct pci_dev *, int where, u8 *val); - int (*read_word)(struct pci_dev *, int where, u16 *val); - int (*read_dword)(struct pci_dev *, int where, u32 *val); - int (*write_byte)(struct pci_dev *, int where, u8 val); - int (*write_word)(struct pci_dev *, int where, u16 val); - int (*write_dword)(struct pci_dev *, int where, u32 val); -}; - -struct pbus_set_ranges_data -{ - unsigned long io_start, io_end; - unsigned long mem_start, mem_end; - unsigned long prefetch_start, prefetch_end; -}; - -struct pci_device_id { - unsigned int vendor, device; /* Vendor and device ID or PCI_ANY_ID */ - unsigned int subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ - unsigned int class, class_mask; /* (class,subclass,prog-if) triplet */ - unsigned long driver_data; /* Data private to the driver */ -}; - -struct pci_driver { - struct list_head node; - char *name; - const struct pci_device_id *id_table; /* NULL if wants all devices */ - int (*probe) (struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */ - void (*remove) (struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */ - int (*save_state) (struct pci_dev *dev, u32 state); /* Save Device Context */ - int (*suspend) (struct pci_dev *dev, u32 state); /* Device suspended */ - int (*resume) (struct pci_dev *dev); /* Device woken up */ - int (*enable_wake) (struct pci_dev *dev, u32 state, int enable); /* Enable wake event */ -}; - -/** - * PCI_DEVICE - macro used to describe a specific pci device - * @vend: the 16 bit PCI Vendor ID - * @dev: the 16 bit PCI Device ID - * - * This macro is used to create a struct pci_device_id that matches a - * specific device. The subvendor and subdevice fields will be set to - * PCI_ANY_ID. - */ -#define PCI_DEVICE(vend,dev) \ - .vendor = (vend), .device = (dev), \ - .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID - -/** - * PCI_DEVICE_CLASS - macro used to describe a specific pci device class - * @dev_class: the class, subclass, prog-if triple for this device - * @dev_class_mask: the class mask for this device - * - * This macro is used to create a struct pci_device_id that matches a - * specific PCI class. The vendor, device, subvendor, and subdevice - * fields will be set to PCI_ANY_ID. - */ -#define PCI_DEVICE_CLASS(dev_class,dev_class_mask) \ - .class = (dev_class), .class_mask = (dev_class_mask), \ - .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \ - .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID - -/* these external functions are only available when PCI support is enabled */ -#ifdef CONFIG_PCI - -#define pci_for_each_dev(dev) \ - for(dev = pci_dev_g(pci_devices.next); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.next)) - -void pcibios_init(void); -void pcibios_fixup_bus(struct pci_bus *); -int pcibios_enable_device(struct pci_dev *, int mask); -char *pcibios_setup (char *str); - -/* Used only when drivers/pci/setup.c is used */ -void pcibios_align_resource(void *, struct resource *, - unsigned long, unsigned long); -void pcibios_update_resource(struct pci_dev *, struct resource *, - struct resource *, int); -void pcibios_update_irq(struct pci_dev *, int irq); -void pcibios_fixup_pbus_ranges(struct pci_bus *, struct pbus_set_ranges_data *); - -/* Backward compatibility, don't use in new code! */ - -int pcibios_present(void); -int pcibios_read_config_byte (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned char *val); -int pcibios_read_config_word (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned short *val); -int pcibios_read_config_dword (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned int *val); -int pcibios_write_config_byte (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned char val); -int pcibios_write_config_word (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned short val); -int pcibios_write_config_dword (unsigned char bus, unsigned char dev_fn, - unsigned char where, unsigned int val); -int pcibios_find_class (unsigned int class_code, unsigned short index, unsigned char *bus, unsigned char *dev_fn); -int pcibios_find_device (unsigned short vendor, unsigned short dev_id, - unsigned short index, unsigned char *bus, - unsigned char *dev_fn); - -/* Generic PCI functions used internally */ - -void pci_init(void); -int pci_bus_exists(const struct list_head *list, int nr); -struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata); -struct pci_bus *pci_alloc_primary_bus(int bus); -struct pci_dev *pci_scan_slot(struct pci_dev *temp); -int pci_proc_attach_device(struct pci_dev *dev); -int pci_proc_detach_device(struct pci_dev *dev); -int pci_proc_attach_bus(struct pci_bus *bus); -int pci_proc_detach_bus(struct pci_bus *bus); -void pci_name_device(struct pci_dev *dev); -char *pci_class_name(u32 class); -void pci_read_bridge_bases(struct pci_bus *child); -struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res); -int pci_setup_device(struct pci_dev *dev); -int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge); - -/* Generic PCI functions exported to card drivers */ - -struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from); -struct pci_dev *pci_find_subsys (unsigned int vendor, unsigned int device, - unsigned int ss_vendor, unsigned int ss_device, - const struct pci_dev *from); -struct pci_dev *pci_find_class (unsigned int class, const struct pci_dev *from); -struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); -int pci_find_capability (struct pci_dev *dev, int cap); - -int pci_read_config_byte(struct pci_dev *dev, int where, u8 *val); -int pci_read_config_word(struct pci_dev *dev, int where, u16 *val); -int pci_read_config_dword(struct pci_dev *dev, int where, u32 *val); -int pci_write_config_byte(struct pci_dev *dev, int where, u8 val); -int pci_write_config_word(struct pci_dev *dev, int where, u16 val); -int pci_write_config_dword(struct pci_dev *dev, int where, u32 val); - -int pci_enable_device(struct pci_dev *dev); -int pci_enable_device_bars(struct pci_dev *dev, int mask); -void pci_disable_device(struct pci_dev *dev); -void pci_set_master(struct pci_dev *dev); -#define HAVE_PCI_SET_MWI -int pci_set_mwi(struct pci_dev *dev); -void pci_clear_mwi(struct pci_dev *dev); -int pci_set_dma_mask(struct pci_dev *dev, u64 mask); -int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask); -int pci_assign_resource(struct pci_dev *dev, int i); - -/* Power management related routines */ -int pci_save_state(struct pci_dev *dev, u32 *buffer); -int pci_restore_state(struct pci_dev *dev, u32 *buffer); -int pci_set_power_state(struct pci_dev *dev, int state); -int pci_enable_wake(struct pci_dev *dev, u32 state, int enable); - -/* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */ - -int pci_claim_resource(struct pci_dev *, int); -void pci_assign_unassigned_resources(void); -void pdev_enable_device(struct pci_dev *); -void pdev_sort_resources(struct pci_dev *, struct resource_list *); -unsigned long pci_bridge_check_io(struct pci_dev *); -void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *), - int (*)(struct pci_dev *, u8, u8)); -#define HAVE_PCI_REQ_REGIONS 2 -int pci_request_regions(struct pci_dev *, char *); -void pci_release_regions(struct pci_dev *); -int pci_request_region(struct pci_dev *, int, char *); -void pci_release_region(struct pci_dev *, int); - -/* New-style probing supporting hot-pluggable devices */ -int pci_register_driver(struct pci_driver *); -void pci_unregister_driver(struct pci_driver *); -void pci_insert_device(struct pci_dev *, struct pci_bus *); -void pci_remove_device(struct pci_dev *); -struct pci_driver *pci_dev_driver(const struct pci_dev *); -const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev); -void pci_announce_device_to_drivers(struct pci_dev *); -unsigned int pci_do_scan_bus(struct pci_bus *bus); -struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr); - -#if 0 -/* xmem_cache style wrapper around pci_alloc_consistent() */ -struct pci_pool *pci_pool_create (const char *name, struct pci_dev *dev, - size_t size, size_t align, size_t allocation, int flags); -void pci_pool_destroy (struct pci_pool *pool); - -void *pci_pool_alloc (struct pci_pool *pool, int flags, dma_addr_t *handle); -void pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t addr); -#endif - -#endif /* CONFIG_PCI */ - -/* - * If the system does not have PCI, clearly these return errors. Define - * these as simple inline functions to avoid hair in drivers. - */ - -#ifndef CONFIG_PCI -static inline int pcibios_present(void) { return 0; } -static inline int pcibios_find_class (unsigned int class_code, unsigned short index, unsigned char *bus, unsigned char *dev_fn) -{ return PCIBIOS_DEVICE_NOT_FOUND; } - -#define _PCI_NOP(o,s,t) \ - static inline int pcibios_##o##_config_##s (u8 bus, u8 dfn, u8 where, t val) \ - { return PCIBIOS_FUNC_NOT_SUPPORTED; } \ - static inline int pci_##o##_config_##s (struct pci_dev *dev, int where, t val) \ - { return PCIBIOS_FUNC_NOT_SUPPORTED; } -#define _PCI_NOP_ALL(o,x) _PCI_NOP(o,byte,u8 x) \ - _PCI_NOP(o,word,u16 x) \ - _PCI_NOP(o,dword,u32 x) -_PCI_NOP_ALL(read, *) -_PCI_NOP_ALL(write,) - -static inline struct pci_dev *pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from) -{ return NULL; } - -static inline struct pci_dev *pci_find_class(unsigned int class, const struct pci_dev *from) -{ return NULL; } - -static inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn) -{ return NULL; } - -static inline struct pci_dev *pci_find_subsys(unsigned int vendor, unsigned int device, -unsigned int ss_vendor, unsigned int ss_device, const struct pci_dev *from) -{ return NULL; } - -static inline void pci_set_master(struct pci_dev *dev) { } -static inline int pci_enable_device_bars(struct pci_dev *dev, int mask) { return -EBUSY; } -static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; } -static inline void pci_disable_device(struct pci_dev *dev) { } -static inline int pci_module_init(struct pci_driver *drv) { return -ENODEV; } -static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; } -static inline int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask) { return -EIO; } -static inline int pci_assign_resource(struct pci_dev *dev, int i) { return -EBUSY;} -static inline int pci_register_driver(struct pci_driver *drv) { return 0;} -static inline void pci_unregister_driver(struct pci_driver *drv) { } -static inline int scsi_to_pci_dma_dir(unsigned char scsi_dir) { return scsi_dir; } -static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; } -static inline const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) { return NULL; } - -/* Power management related routines */ -static inline int pci_save_state(struct pci_dev *dev, u32 *buffer) { return 0; } -static inline int pci_restore_state(struct pci_dev *dev, u32 *buffer) { return 0; } -static inline int pci_set_power_state(struct pci_dev *dev, int state) { return 0; } -static inline int pci_enable_wake(struct pci_dev *dev, u32 state, int enable) { return 0; } - -#define pci_for_each_dev(dev) \ - for(dev = NULL; 0; ) - -#else - -/* - * a helper function which helps ensure correct pci_driver - * setup and cleanup for commonly-encountered hotplug/modular cases - * - * This MUST stay in a header, as it checks for -DMODULE - */ -static inline int pci_module_init(struct pci_driver *drv) -{ - int rc = pci_register_driver (drv); - - if (rc > 0) - return 0; - - /* iff CONFIG_HOTPLUG and built into kernel, we should - * leave the driver around for future hotplug events. - * For the module case, a hotplug daemon of some sort - * should load a module in response to an insert event. */ -#if defined(CONFIG_HOTPLUG) && !defined(MODULE) - if (rc == 0) - return 0; -#else - if (rc == 0) - rc = -ENODEV; -#endif - - /* if we get here, we need to clean up pci driver instance - * and return some sort of error */ - pci_unregister_driver (drv); - - return rc; -} - -#endif /* !CONFIG_PCI */ - -/* these helpers provide future and backwards compatibility - * for accessing popular PCI BAR info */ -#define pci_resource_start(dev,bar) ((dev)->resource[(bar)].start) -#define pci_resource_end(dev,bar) ((dev)->resource[(bar)].end) -#define pci_resource_flags(dev,bar) ((dev)->resource[(bar)].flags) -#define pci_resource_len(dev,bar) \ - ((pci_resource_start((dev),(bar)) == 0 && \ - pci_resource_end((dev),(bar)) == \ - pci_resource_start((dev),(bar))) ? 0 : \ - \ - (pci_resource_end((dev),(bar)) - \ - pci_resource_start((dev),(bar)) + 1)) - -/* Similar to the helpers above, these manipulate per-pci_dev - * driver-specific data. Currently stored as pci_dev::driver_data, - * a void pointer, but it is not present on older kernels. - */ -static inline void *pci_get_drvdata (struct pci_dev *pdev) -{ - return pdev->driver_data; -} - -static inline void pci_set_drvdata (struct pci_dev *pdev, void *data) -{ - pdev->driver_data = data; -} - -static inline char *pci_name(struct pci_dev *pdev) -{ - return pdev->slot_name; -} - -/* - * The world is not perfect and supplies us with broken PCI devices. - * For at least a part of these bugs we need a work-around, so both - * generic (drivers/pci/quirks.c) and per-architecture code can define - * fixup hooks to be called for particular buggy devices. - */ - -struct pci_fixup { - int pass; - u16 vendor, device; /* You can use PCI_ANY_ID here of course */ - void (*hook)(struct pci_dev *dev); -}; - -extern struct pci_fixup pcibios_fixups[]; - -#define PCI_FIXUP_HEADER 1 /* Called immediately after reading configuration header */ -#define PCI_FIXUP_FINAL 2 /* Final phase of device fixups */ - -void pci_fixup_device(int pass, struct pci_dev *dev); - -extern int pci_pci_problems; -#define PCIPCI_FAIL 1 -#define PCIPCI_TRITON 2 -#define PCIPCI_NATOMA 4 -#define PCIPCI_VIAETBF 8 -#define PCIPCI_VSFX 16 -#define PCIPCI_ALIMAGIK 32 - -#endif /* LINUX_PCI_H */