Rev 698 |
Blame |
Compare with Previous |
Last modification |
View Log
| RSS feed
/*
* Project: S.Ha.R.K.
*
* Coordinators:
* Giorgio Buttazzo <giorgio@sssup.it>
* Paolo Gai <pj@gandalf.sssup.it>
*
* Authors :
* Giacomo Guidi <giacomo@gandalf.sssup.it>
* (see the web pages for full authors list)
*
* ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
*
* http://www.sssup.it
* http://retis.sssup.it
* http://shark.sssup.it
*/
/*
* Copyright (C) 2000,2002 Paolo Gai
*
* 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
*
*/
/* Interrupt Driver Module */
#include <modules/intdrive.h>
#include <kernel/model.h>
#include <kernel/descr.h>
#include <kernel/var.h>
#include <kernel/func.h>
#include <ll/i386/64bit.h>
/*+ Status used in the level +*/
#define INTDRIVE_READY MODULE_STATUS_BASE /*+ - Ready status +*/
#define INTDRIVE_WCET_VIOLATED MODULE_STATUS_BASE+2 /*+ when wcet is finished +*/
#define INTDRIVE_IDLE MODULE_STATUS_BASE+3 /*+ to wait the replenish +*/
#define INTDRIVE_WAIT MODULE_STATUS_BASE+4 /*+ to wait the activation */
//#define INTDRIVE_DEBUG
/*+ the level redefinition for the IntDrive +*/
typedef struct {
level_des l
; /*+ the standard level descriptor +*/
TIME replenish_period
;
TIME capacity
;
struct timespec act_time
;
int avail
;
struct timespec replenish_expires
;
int replenish_timer
;
int wcet_timer
;
int act_number
; /*+ the activation number +*/
int flags
; /*+ the init flags... +*/
bandwidth_t U
; /*+ the used bandwidth +*/
} INTDRIVE_level_des
;
PID INTDRIVE_task
= NIL
;
/* Replenish the capacity */
static void INTDRIVE_timer
(void *arg
)
{
INTDRIVE_level_des
*lev
= (INTDRIVE_level_des
*)(arg
);
lev
->replenish_timer
= NIL
;
#ifdef INTDRIVE_DEBUG
kern_printf
("(INTD:TIMER)");
#endif
if (INTDRIVE_task
== NIL
) return;
lev
->avail
= lev
->capacity
;
switch (proc_table
[INTDRIVE_task
].
status) {
case INTDRIVE_IDLE
:
if (lev
->act_number
) {
proc_table
[INTDRIVE_task
].
status = INTDRIVE_READY
;
event_need_reschedule
();
} else {
proc_table
[INTDRIVE_task
].
status = INTDRIVE_WAIT
;
}
break;
}
}
static void INTDRIVE_wcet_timer
(void *arg
)
{
INTDRIVE_level_des
*lev
= (INTDRIVE_level_des
*)(arg
);
lev
->wcet_timer
= NIL
;
kern_raise
(XWCET_VIOLATION
,INTDRIVE_task
);
}
static PID INTDRIVE_public_scheduler
(LEVEL l
)
{
if (proc_table
[INTDRIVE_task
].
status == INTDRIVE_READY
||
proc_table
[INTDRIVE_task
].
status == EXE
)
return INTDRIVE_task
;
else
return NIL
;
}
static int INTDRIVE_public_create
(LEVEL l
, PID p
, TASK_MODEL
*m
)
{
HARD_TASK_MODEL
*h
;
if (m
->pclass
!= HARD_PCLASS
) return -1;
if (m
->level
!= 0 && m
->level
!= l
) return -1;
h
= (HARD_TASK_MODEL
*)m
;
if (!h
->wcet
&& h
->periodicity
!= INTDRIVE
) return -1;
if (INTDRIVE_task
!= NIL
) return -1;
INTDRIVE_task
= p
;
proc_table
[INTDRIVE_task
].
wcet = h
->wcet
;
proc_table
[INTDRIVE_task
].
status = INTDRIVE_WAIT
;
proc_table
[INTDRIVE_task
].
control &= ~CONTROL_CAP
;
return 0;
}
static void INTDRIVE_public_dispatch
(LEVEL l
, PID p
, int nostop
)
{
INTDRIVE_level_des
*lev
= (INTDRIVE_level_des
*)(level_table
[l
]);
struct timespec
time;
kern_gettime
(&(lev
->act_time
));
TIMESPEC_ASSIGN
(&time,&(lev
->act_time
));
ADDUSEC2TIMESPEC
(proc_table
[INTDRIVE_task
].
wcet,&time);
if (lev
->flags
== INTDRIVE_CHECK_WCET
)
lev
->wcet_timer
= kern_event_post
(&time,INTDRIVE_wcet_timer
,(void *)lev
);
}
static void INTDRIVE_public_epilogue
(LEVEL l
, PID p
)
{
struct timespec
time;
INTDRIVE_level_des
*lev
= (INTDRIVE_level_des
*)(level_table
[l
]);
if (lev
->wcet_timer
!= NIL
)
kern_event_delete
(lev
->wcet_timer
);
SUBTIMESPEC
(&schedule_time
, &(lev
->act_time
), &time);
lev
->avail
-= TIMESPEC2USEC
(&time);
}
static void INTDRIVE_public_activate
(LEVEL l
, PID p
, struct timespec
*t
)
{
INTDRIVE_level_des
*lev
= (INTDRIVE_level_des
*)(level_table
[l
]);
if (proc_table
[INTDRIVE_task
].
status == INTDRIVE_WAIT
) {
proc_table
[INTDRIVE_task
].
status = INTDRIVE_READY
;
lev
->act_number
++;
} else {
if (proc_table
[INTDRIVE_task
].
status == INTDRIVE_IDLE
||
proc_table
[INTDRIVE_task
].
status == INTDRIVE_READY
||
proc_table
[INTDRIVE_task
].
status == EXE
) {
#ifdef INTDRIVE_DEBUG
kern_printf
("(INTD:WAIT_REC)");
#endif
lev
->act_number
++;
}
}
if (lev
->replenish_timer
== NIL
) {
kern_gettime
(&(lev
->replenish_expires
));
ADDUSEC2TIMESPEC
(lev
->replenish_period
,&(lev
->replenish_expires
));
lev
->replenish_timer
= kern_event_post
(&(lev
->replenish_expires
),INTDRIVE_timer
,(void *)lev
);
}
}
static void INTDRIVE_public_unblock
(LEVEL l
, PID p
)
{
/* Insert task in the correct position */
proc_table
[INTDRIVE_task
].
status = INTDRIVE_READY
;
}
static void INTDRIVE_public_block
(LEVEL l
, PID p
)
{
}
static int INTDRIVE_public_message
(LEVEL l
, PID p
, void *m
)
{
INTDRIVE_level_des
*lev
= (INTDRIVE_level_des
*)(level_table
[l
]);
struct timespec
time, acttime
;
int temp
,delta_time
;;
lev
->act_number
--;
if (lev
->wcet_timer
!= NIL
)
kern_event_delete
(lev
->wcet_timer
);
kern_gettime
(&acttime
);
SUBTIMESPEC
(&acttime
, &(lev
->act_time
), &time);
lev
->avail
-= TIMESPEC2USEC
(&time);
#ifdef INTDRIVE_DEBUG
kern_printf
("(INTD:AV:%d)",(int)(lev
->avail
));
#endif
if (lev
->avail
< 0) {
proc_table
[INTDRIVE_task
].
status = INTDRIVE_IDLE
;
temp
= -lev
->avail
;
mul32div32to32
(temp
,lev
->replenish_period
,lev
->capacity
,delta_time
);
if (lev
->replenish_timer
!= NIL
)
kern_event_delete
(lev
->replenish_timer
);
ADDUSEC2TIMESPEC
(delta_time
,&(lev
->replenish_expires
)); lev
->replenish_timer
= kern_event_post
(&(lev
->replenish_expires
),INTDRIVE_timer
,(void *)lev
);
#ifdef INTDRIVE_DEBUG
kern_printf
("(INTD:IDLE:%d)",delta_time
);
#endif
} else {
if (lev
->act_number
) {
proc_table
[INTDRIVE_task
].
status = INTDRIVE_READY
;
#ifdef INTDRIVE_DEBUG
kern_printf
("(INTD:NEXT_ACT)");
#endif
} else {
#ifdef INTDRIVE_DEBUG
kern_printf
("(INTD:WAIT_ACT)");
#endif
proc_table
[INTDRIVE_task
].
status = INTDRIVE_WAIT
;
}
}
return 0;
}
static void INTDRIVE_public_end
(LEVEL l
, PID p
)
{
INTDRIVE_level_des
*lev
= (INTDRIVE_level_des
*)(level_table
[l
]);
if (lev
->replenish_timer
!= NIL
)
kern_event_delete
(lev
->replenish_timer
);
if (lev
->wcet_timer
!= NIL
)
kern_event_delete
(lev
->wcet_timer
);
proc_table
[INTDRIVE_task
].
status = INTDRIVE_IDLE
;
}
/* Registration functions */
/*+ Registration function: +*/
LEVEL INTDRIVE_register_level
(TIME capacity
, TIME replenish_period
, int flags
)
{
LEVEL l
; /* the level that we register */
INTDRIVE_level_des
*lev
;
printk
("INTDRIVE_register_level\n");
/* request an entry in the level_table */
l
= level_alloc_descriptor
(sizeof(INTDRIVE_level_des
));
lev
= (INTDRIVE_level_des
*)level_table
[l
];
lev
->l.
public_scheduler = INTDRIVE_public_scheduler
;
lev
->l.
public_guarantee = NULL
;
lev
->l.
public_create = INTDRIVE_public_create
;
lev
->l.
public_end = INTDRIVE_public_end
;
lev
->l.
public_dispatch = INTDRIVE_public_dispatch
;
lev
->l.
public_epilogue = INTDRIVE_public_epilogue
;
lev
->l.
public_activate = INTDRIVE_public_activate
;
lev
->l.
public_unblock = INTDRIVE_public_unblock
;
lev
->l.
public_block = INTDRIVE_public_block
;
lev
->l.
public_message = INTDRIVE_public_message
;
NULL_TIMESPEC
(&(lev
->act_time
));
lev
->capacity
= capacity
;
lev
->replenish_period
= replenish_period
;
lev
->replenish_timer
= NIL
;
lev
->wcet_timer
= NIL
;
lev
->flags
= flags
;
lev
->act_number
= 0;
lev
->avail
= capacity
;
mul32div32to32
(MAX_BANDWIDTH
,lev
->capacity
,lev
->replenish_period
,lev
->U
);
return l
;
}
bandwidth_t INTDRIVE_usedbandwidth
(LEVEL l
)
{
INTDRIVE_level_des
*lev
= (INTDRIVE_level_des
*)(level_table
[l
]);
return lev
->U
;
}