-
Notifications
You must be signed in to change notification settings - Fork 137
/
Copy pathbus.c
159 lines (133 loc) · 3.61 KB
/
bus.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2020-2022 Intel Corporation. All rights reserved. */
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <util/log.h>
#include <cxl/libcxl.h>
#include <util/parse-options.h>
#include <ccan/minmax/minmax.h>
#include <ccan/array_size/array_size.h>
#include "filter.h"
static struct parameters {
bool debug;
bool force;
} param;
static struct log_ctx bl;
#define BASE_OPTIONS() \
OPT_BOOLEAN(0, "debug", ¶m.debug, "turn on debug")
#define DISABLE_OPTIONS() \
OPT_BOOLEAN('f', "force", ¶m.force, \
"DANGEROUS: override active memdev safety checks")
static const struct option disable_options[] = {
BASE_OPTIONS(),
DISABLE_OPTIONS(),
OPT_END(),
};
static int action_disable(struct cxl_bus *bus)
{
const char *devname = cxl_bus_get_devname(bus);
struct cxl_ctx *ctx = cxl_bus_get_ctx(bus);
struct cxl_memdev *memdev;
int active_memdevs = 0;
cxl_memdev_foreach(ctx, memdev)
if (bus == cxl_memdev_get_bus(memdev))
active_memdevs++;
if (active_memdevs && !param.force) {
/*
* TODO: actually detect rather than assume active just
* because the memdev is enabled
*/
log_err(&bl,
"%s hosts %d memdev%s which %s part of an active region\n",
devname, active_memdevs, active_memdevs > 1 ? "s" : "",
active_memdevs > 1 ? "are" : "is");
log_err(&bl,
"See 'cxl list -M -b %s' to see impacted device%s\n",
devname, active_memdevs > 1 ? "s" : "");
return -EBUSY;
}
return cxl_bus_disable_invalidate(bus);
}
static struct cxl_bus *find_cxl_bus(struct cxl_ctx *ctx, const char *ident)
{
struct cxl_bus *bus;
cxl_bus_foreach(ctx, bus)
if (util_cxl_bus_filter(bus, ident))
return bus;
return NULL;
}
static int bus_action(int argc, const char **argv, struct cxl_ctx *ctx,
int (*action)(struct cxl_bus *bus),
const struct option *options, const char *usage)
{
int i, rc = 0, count = 0, err = 0;
const char * const u[] = {
usage,
NULL
};
unsigned long id;
log_init(&bl, "cxl bus", "CXL_PORT_LOG");
argc = parse_options(argc, argv, options, u, 0);
if (argc == 0)
usage_with_options(u, options);
for (i = 0; i < argc; i++) {
if (strcmp(argv[i], "all") == 0) {
argv[0] = "all";
argc = 1;
break;
}
if (sscanf(argv[i], "root%lu", &id) == 1)
continue;
if (sscanf(argv[i], "%lu", &id) == 1)
continue;
log_err(&bl, "'%s' is not a valid bus identifer\n", argv[i]);
err++;
}
if (err == argc) {
usage_with_options(u, options);
return -EINVAL;
}
if (param.debug) {
cxl_set_log_priority(ctx, LOG_DEBUG);
bl.log_priority = LOG_DEBUG;
} else
bl.log_priority = LOG_INFO;
rc = 0;
err = 0;
count = 0;
for (i = 0; i < argc; i++) {
struct cxl_bus *bus;
bus = find_cxl_bus(ctx, argv[i]);
if (!bus) {
log_dbg(&bl, "bus: %s not found\n", argv[i]);
continue;
}
log_dbg(&bl, "run action on bus: %s\n",
cxl_bus_get_devname(bus));
rc = action(bus);
if (rc == 0)
count++;
else if (rc && !err)
err = rc;
}
rc = err;
/*
* count if some actions succeeded, 0 if none were attempted,
* negative error code otherwise.
*/
if (count > 0)
return count;
return rc;
}
int cmd_disable_bus(int argc, const char **argv, struct cxl_ctx *ctx)
{
int count = bus_action(
argc, argv, ctx, action_disable, disable_options,
"cxl disable-bus <bus0> [<bus1>..<busN>] [<options>]");
log_info(&bl, "disabled %d bus%s\n", count >= 0 ? count : 0,
count > 1 ? "s" : "");
return count >= 0 ? 0 : EXIT_FAILURE;
}