|
@@ -32,6 +32,7 @@
|
|
|
#include <linux/device.h>
|
|
|
#include <linux/io.h>
|
|
|
#include <linux/uaccess.h>
|
|
|
+#include <linux/security.h>
|
|
|
#include <asm/pgtable.h>
|
|
|
#include "gru.h"
|
|
|
#include "grutables.h"
|
|
@@ -575,6 +576,38 @@ int gru_get_exception_detail(unsigned long arg)
|
|
|
/*
|
|
|
* User request to unload a context. Content is saved for possible reload.
|
|
|
*/
|
|
|
+static int gru_unload_all_contexts(void)
|
|
|
+{
|
|
|
+ struct gru_thread_state *gts;
|
|
|
+ struct gru_state *gru;
|
|
|
+ int maxgid, gid, ctxnum;
|
|
|
+ int nodesperblade;
|
|
|
+
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+ if (num_online_nodes() > 1 &&
|
|
|
+ (uv_node_to_blade_id(1) == uv_node_to_blade_id(0)))
|
|
|
+ nodesperblade = 2;
|
|
|
+ else
|
|
|
+ nodesperblade = 1;
|
|
|
+ maxgid = GRU_CHIPLETS_PER_BLADE * num_online_nodes() / nodesperblade;
|
|
|
+ for (gid = 0; gid < maxgid; gid++) {
|
|
|
+ gru = GID_TO_GRU(gid);
|
|
|
+ spin_lock(&gru->gs_lock);
|
|
|
+ for (ctxnum = 0; ctxnum < GRU_NUM_CCH; ctxnum++) {
|
|
|
+ gts = gru->gs_gts[ctxnum];
|
|
|
+ if (gts && mutex_trylock(>s->ts_ctxlock)) {
|
|
|
+ spin_unlock(&gru->gs_lock);
|
|
|
+ gru_unload_context(gts, 1);
|
|
|
+ gru_unlock_gts(gts);
|
|
|
+ spin_lock(&gru->gs_lock);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ spin_unlock(&gru->gs_lock);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
int gru_user_unload_context(unsigned long arg)
|
|
|
{
|
|
|
struct gru_thread_state *gts;
|
|
@@ -586,6 +619,9 @@ int gru_user_unload_context(unsigned long arg)
|
|
|
|
|
|
gru_dbg(grudev, "gseg 0x%lx\n", req.gseg);
|
|
|
|
|
|
+ if (!req.gseg)
|
|
|
+ return gru_unload_all_contexts();
|
|
|
+
|
|
|
gts = gru_find_lock_gts(req.gseg);
|
|
|
if (!gts)
|
|
|
return -EINVAL;
|