diff options
Diffstat (limited to 'litmus/sched_pfp.c')
-rw-r--r-- | litmus/sched_pfp.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/litmus/sched_pfp.c b/litmus/sched_pfp.c index d5dd78d941c6..42d17b0c08fd 100644 --- a/litmus/sched_pfp.c +++ b/litmus/sched_pfp.c | |||
@@ -950,6 +950,8 @@ static struct litmus_lock* pfp_new_mpcp(int vspin) | |||
950 | 950 | ||
951 | 951 | ||
952 | struct pcp_semaphore { | 952 | struct pcp_semaphore { |
953 | struct litmus_lock litmus_lock; | ||
954 | |||
953 | struct list_head ceiling; | 955 | struct list_head ceiling; |
954 | 956 | ||
955 | /* current resource holder */ | 957 | /* current resource holder */ |
@@ -962,6 +964,12 @@ struct pcp_semaphore { | |||
962 | int on_cpu; | 964 | int on_cpu; |
963 | }; | 965 | }; |
964 | 966 | ||
967 | static inline struct pcp_semaphore* pcp_from_lock(struct litmus_lock* lock) | ||
968 | { | ||
969 | return container_of(lock, struct pcp_semaphore, litmus_lock); | ||
970 | } | ||
971 | |||
972 | |||
965 | struct pcp_state { | 973 | struct pcp_state { |
966 | struct list_head system_ceiling; | 974 | struct list_head system_ceiling; |
967 | 975 | ||
@@ -1203,6 +1211,123 @@ static void pcp_init_semaphore(struct pcp_semaphore* sem, int cpu) | |||
1203 | sem->on_cpu = cpu; | 1211 | sem->on_cpu = cpu; |
1204 | } | 1212 | } |
1205 | 1213 | ||
1214 | int pfp_pcp_lock(struct litmus_lock* l) | ||
1215 | { | ||
1216 | struct task_struct* t = current; | ||
1217 | struct pcp_semaphore *sem = pcp_from_lock(l); | ||
1218 | |||
1219 | int eprio = effective_agent_priority(get_priority(t)); | ||
1220 | int from = get_partition(t); | ||
1221 | int to = sem->on_cpu; | ||
1222 | |||
1223 | if (!is_realtime(t) || from != to) | ||
1224 | return -EPERM; | ||
1225 | |||
1226 | preempt_disable(); | ||
1227 | |||
1228 | pcp_raise_ceiling(sem, eprio); | ||
1229 | |||
1230 | preempt_enable(); | ||
1231 | |||
1232 | return 0; | ||
1233 | } | ||
1234 | |||
1235 | int pfp_pcp_unlock(struct litmus_lock* l) | ||
1236 | { | ||
1237 | struct task_struct *t = current; | ||
1238 | struct pcp_semaphore *sem = pcp_from_lock(l); | ||
1239 | |||
1240 | int err = 0; | ||
1241 | |||
1242 | preempt_disable(); | ||
1243 | |||
1244 | if (sem->on_cpu != smp_processor_id() || sem->owner != t) { | ||
1245 | err = -EINVAL; | ||
1246 | goto out; | ||
1247 | } | ||
1248 | |||
1249 | /* give it back */ | ||
1250 | pcp_lower_ceiling(sem); | ||
1251 | |||
1252 | out: | ||
1253 | preempt_enable(); | ||
1254 | |||
1255 | return err; | ||
1256 | } | ||
1257 | |||
1258 | int pfp_pcp_open(struct litmus_lock* l, void* __user config) | ||
1259 | { | ||
1260 | struct task_struct *t = current; | ||
1261 | struct pcp_semaphore *sem = pcp_from_lock(l); | ||
1262 | |||
1263 | int cpu, eprio; | ||
1264 | |||
1265 | if (!is_realtime(t)) | ||
1266 | /* we need to know the real-time priority */ | ||
1267 | return -EPERM; | ||
1268 | |||
1269 | if (get_user(cpu, (int*) config)) | ||
1270 | return -EFAULT; | ||
1271 | |||
1272 | /* make sure the resource location matches */ | ||
1273 | if (cpu != sem->on_cpu) | ||
1274 | return -EINVAL; | ||
1275 | |||
1276 | eprio = effective_agent_priority(get_priority(t)); | ||
1277 | |||
1278 | pcp_update_prio_ceiling(sem, eprio); | ||
1279 | |||
1280 | return 0; | ||
1281 | } | ||
1282 | |||
1283 | int pfp_pcp_close(struct litmus_lock* l) | ||
1284 | { | ||
1285 | struct task_struct *t = current; | ||
1286 | struct pcp_semaphore *sem = pcp_from_lock(l); | ||
1287 | |||
1288 | int owner = 0; | ||
1289 | |||
1290 | preempt_disable(); | ||
1291 | |||
1292 | if (sem->on_cpu == smp_processor_id()) | ||
1293 | owner = sem->owner == t; | ||
1294 | |||
1295 | preempt_enable(); | ||
1296 | |||
1297 | if (owner) | ||
1298 | pfp_pcp_unlock(l); | ||
1299 | |||
1300 | return 0; | ||
1301 | } | ||
1302 | |||
1303 | void pfp_pcp_free(struct litmus_lock* lock) | ||
1304 | { | ||
1305 | kfree(pcp_from_lock(lock)); | ||
1306 | } | ||
1307 | |||
1308 | |||
1309 | static struct litmus_lock_ops pfp_pcp_lock_ops = { | ||
1310 | .close = pfp_pcp_close, | ||
1311 | .lock = pfp_pcp_lock, | ||
1312 | .open = pfp_pcp_open, | ||
1313 | .unlock = pfp_pcp_unlock, | ||
1314 | .deallocate = pfp_pcp_free, | ||
1315 | }; | ||
1316 | |||
1317 | |||
1318 | static struct litmus_lock* pfp_new_pcp(int on_cpu) | ||
1319 | { | ||
1320 | struct pcp_semaphore* sem; | ||
1321 | |||
1322 | sem = kmalloc(sizeof(*sem), GFP_KERNEL); | ||
1323 | if (!sem) | ||
1324 | return NULL; | ||
1325 | |||
1326 | sem->litmus_lock.ops = &pfp_pcp_lock_ops; | ||
1327 | pcp_init_semaphore(sem, on_cpu); | ||
1328 | |||
1329 | return &sem->litmus_lock; | ||
1330 | } | ||
1206 | 1331 | ||
1207 | /* ******************** DPCP support ********************** */ | 1332 | /* ******************** DPCP support ********************** */ |
1208 | 1333 | ||
@@ -1459,6 +1584,21 @@ static long pfp_allocate_lock(struct litmus_lock **lock, int type, | |||
1459 | } else | 1584 | } else |
1460 | err = -ENOMEM; | 1585 | err = -ENOMEM; |
1461 | break; | 1586 | break; |
1587 | |||
1588 | case PCP_SEM: | ||
1589 | /* Priority Ceiling Protocol */ | ||
1590 | if (get_user(cpu, (int*) config)) | ||
1591 | return -EFAULT; | ||
1592 | |||
1593 | if (!cpu_online(cpu)) | ||
1594 | return -EINVAL; | ||
1595 | |||
1596 | *lock = pfp_new_pcp(cpu); | ||
1597 | if (*lock) | ||
1598 | err = 0; | ||
1599 | else | ||
1600 | err = -ENOMEM; | ||
1601 | break; | ||
1462 | }; | 1602 | }; |
1463 | 1603 | ||
1464 | return err; | 1604 | return err; |