1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright IBM Corp. 2016 |
4 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> |
5 | * |
6 | * Adjunct processor bus, card related code. |
7 | */ |
8 | |
9 | #define KMSG_COMPONENT "ap" |
10 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
11 | |
12 | #include <linux/init.h> |
13 | #include <linux/slab.h> |
14 | #include <asm/facility.h> |
15 | #include <asm/sclp.h> |
16 | |
17 | #include "ap_bus.h" |
18 | |
19 | /* |
20 | * AP card related attributes. |
21 | */ |
22 | static ssize_t hwtype_show(struct device *dev, |
23 | struct device_attribute *attr, char *buf) |
24 | { |
25 | struct ap_card *ac = to_ap_card(dev); |
26 | |
27 | return sysfs_emit(buf, fmt: "%d\n" , ac->ap_dev.device_type); |
28 | } |
29 | |
30 | static DEVICE_ATTR_RO(hwtype); |
31 | |
32 | static ssize_t raw_hwtype_show(struct device *dev, |
33 | struct device_attribute *attr, char *buf) |
34 | { |
35 | struct ap_card *ac = to_ap_card(dev); |
36 | |
37 | return sysfs_emit(buf, fmt: "%d\n" , ac->raw_hwtype); |
38 | } |
39 | |
40 | static DEVICE_ATTR_RO(raw_hwtype); |
41 | |
42 | static ssize_t depth_show(struct device *dev, struct device_attribute *attr, |
43 | char *buf) |
44 | { |
45 | struct ap_card *ac = to_ap_card(dev); |
46 | |
47 | return sysfs_emit(buf, fmt: "%d\n" , ac->queue_depth); |
48 | } |
49 | |
50 | static DEVICE_ATTR_RO(depth); |
51 | |
52 | static ssize_t ap_functions_show(struct device *dev, |
53 | struct device_attribute *attr, char *buf) |
54 | { |
55 | struct ap_card *ac = to_ap_card(dev); |
56 | |
57 | return sysfs_emit(buf, fmt: "0x%08X\n" , ac->functions); |
58 | } |
59 | |
60 | static DEVICE_ATTR_RO(ap_functions); |
61 | |
62 | static ssize_t request_count_show(struct device *dev, |
63 | struct device_attribute *attr, |
64 | char *buf) |
65 | { |
66 | struct ap_card *ac = to_ap_card(dev); |
67 | u64 req_cnt; |
68 | |
69 | req_cnt = 0; |
70 | spin_lock_bh(lock: &ap_queues_lock); |
71 | req_cnt = atomic64_read(v: &ac->total_request_count); |
72 | spin_unlock_bh(lock: &ap_queues_lock); |
73 | return sysfs_emit(buf, fmt: "%llu\n" , req_cnt); |
74 | } |
75 | |
76 | static ssize_t request_count_store(struct device *dev, |
77 | struct device_attribute *attr, |
78 | const char *buf, size_t count) |
79 | { |
80 | int bkt; |
81 | struct ap_queue *aq; |
82 | struct ap_card *ac = to_ap_card(dev); |
83 | |
84 | spin_lock_bh(lock: &ap_queues_lock); |
85 | hash_for_each(ap_queues, bkt, aq, hnode) |
86 | if (ac == aq->card) |
87 | aq->total_request_count = 0; |
88 | spin_unlock_bh(lock: &ap_queues_lock); |
89 | atomic64_set(v: &ac->total_request_count, i: 0); |
90 | |
91 | return count; |
92 | } |
93 | |
94 | static DEVICE_ATTR_RW(request_count); |
95 | |
96 | static ssize_t requestq_count_show(struct device *dev, |
97 | struct device_attribute *attr, char *buf) |
98 | { |
99 | int bkt; |
100 | struct ap_queue *aq; |
101 | unsigned int reqq_cnt; |
102 | struct ap_card *ac = to_ap_card(dev); |
103 | |
104 | reqq_cnt = 0; |
105 | spin_lock_bh(lock: &ap_queues_lock); |
106 | hash_for_each(ap_queues, bkt, aq, hnode) |
107 | if (ac == aq->card) |
108 | reqq_cnt += aq->requestq_count; |
109 | spin_unlock_bh(lock: &ap_queues_lock); |
110 | return sysfs_emit(buf, fmt: "%d\n" , reqq_cnt); |
111 | } |
112 | |
113 | static DEVICE_ATTR_RO(requestq_count); |
114 | |
115 | static ssize_t pendingq_count_show(struct device *dev, |
116 | struct device_attribute *attr, char *buf) |
117 | { |
118 | int bkt; |
119 | struct ap_queue *aq; |
120 | unsigned int penq_cnt; |
121 | struct ap_card *ac = to_ap_card(dev); |
122 | |
123 | penq_cnt = 0; |
124 | spin_lock_bh(lock: &ap_queues_lock); |
125 | hash_for_each(ap_queues, bkt, aq, hnode) |
126 | if (ac == aq->card) |
127 | penq_cnt += aq->pendingq_count; |
128 | spin_unlock_bh(lock: &ap_queues_lock); |
129 | return sysfs_emit(buf, fmt: "%d\n" , penq_cnt); |
130 | } |
131 | |
132 | static DEVICE_ATTR_RO(pendingq_count); |
133 | |
134 | static ssize_t modalias_show(struct device *dev, |
135 | struct device_attribute *attr, char *buf) |
136 | { |
137 | return sysfs_emit(buf, fmt: "ap:t%02X\n" , to_ap_dev(dev)->device_type); |
138 | } |
139 | |
140 | static DEVICE_ATTR_RO(modalias); |
141 | |
142 | static ssize_t config_show(struct device *dev, |
143 | struct device_attribute *attr, char *buf) |
144 | { |
145 | struct ap_card *ac = to_ap_card(dev); |
146 | |
147 | return sysfs_emit(buf, fmt: "%d\n" , ac->config ? 1 : 0); |
148 | } |
149 | |
150 | static ssize_t config_store(struct device *dev, |
151 | struct device_attribute *attr, |
152 | const char *buf, size_t count) |
153 | { |
154 | int rc = 0, cfg; |
155 | struct ap_card *ac = to_ap_card(dev); |
156 | |
157 | if (sscanf(buf, "%d\n" , &cfg) != 1 || cfg < 0 || cfg > 1) |
158 | return -EINVAL; |
159 | |
160 | if (cfg && !ac->config) |
161 | rc = sclp_ap_configure(ac->id); |
162 | else if (!cfg && ac->config) |
163 | rc = sclp_ap_deconfigure(ac->id); |
164 | if (rc) |
165 | return rc; |
166 | |
167 | ac->config = cfg ? true : false; |
168 | |
169 | ap_send_config_uevent(ap_dev: &ac->ap_dev, cfg: ac->config); |
170 | |
171 | return count; |
172 | } |
173 | |
174 | static DEVICE_ATTR_RW(config); |
175 | |
176 | static ssize_t chkstop_show(struct device *dev, |
177 | struct device_attribute *attr, char *buf) |
178 | { |
179 | struct ap_card *ac = to_ap_card(dev); |
180 | |
181 | return sysfs_emit(buf, fmt: "%d\n" , ac->chkstop ? 1 : 0); |
182 | } |
183 | |
184 | static DEVICE_ATTR_RO(chkstop); |
185 | |
186 | static ssize_t max_msg_size_show(struct device *dev, |
187 | struct device_attribute *attr, char *buf) |
188 | { |
189 | struct ap_card *ac = to_ap_card(dev); |
190 | |
191 | return sysfs_emit(buf, fmt: "%u\n" , ac->maxmsgsize); |
192 | } |
193 | |
194 | static DEVICE_ATTR_RO(max_msg_size); |
195 | |
196 | static struct attribute *ap_card_dev_attrs[] = { |
197 | &dev_attr_hwtype.attr, |
198 | &dev_attr_raw_hwtype.attr, |
199 | &dev_attr_depth.attr, |
200 | &dev_attr_ap_functions.attr, |
201 | &dev_attr_request_count.attr, |
202 | &dev_attr_requestq_count.attr, |
203 | &dev_attr_pendingq_count.attr, |
204 | &dev_attr_modalias.attr, |
205 | &dev_attr_config.attr, |
206 | &dev_attr_chkstop.attr, |
207 | &dev_attr_max_msg_size.attr, |
208 | NULL |
209 | }; |
210 | |
211 | static struct attribute_group ap_card_dev_attr_group = { |
212 | .attrs = ap_card_dev_attrs |
213 | }; |
214 | |
215 | static const struct attribute_group *ap_card_dev_attr_groups[] = { |
216 | &ap_card_dev_attr_group, |
217 | NULL |
218 | }; |
219 | |
220 | static struct device_type ap_card_type = { |
221 | .name = "ap_card" , |
222 | .groups = ap_card_dev_attr_groups, |
223 | }; |
224 | |
225 | static void ap_card_device_release(struct device *dev) |
226 | { |
227 | struct ap_card *ac = to_ap_card(dev); |
228 | |
229 | kfree(objp: ac); |
230 | } |
231 | |
232 | struct ap_card *ap_card_create(int id, int queue_depth, int raw_type, |
233 | int comp_type, unsigned int functions, int ml) |
234 | { |
235 | struct ap_card *ac; |
236 | |
237 | ac = kzalloc(size: sizeof(*ac), GFP_KERNEL); |
238 | if (!ac) |
239 | return NULL; |
240 | ac->ap_dev.device.release = ap_card_device_release; |
241 | ac->ap_dev.device.type = &ap_card_type; |
242 | ac->ap_dev.device_type = comp_type; |
243 | ac->raw_hwtype = raw_type; |
244 | ac->queue_depth = queue_depth; |
245 | ac->functions = functions; |
246 | ac->id = id; |
247 | ac->maxmsgsize = ml > 0 ? |
248 | ml * AP_TAPQ_ML_FIELD_CHUNK_SIZE : AP_DEFAULT_MAX_MSG_SIZE; |
249 | |
250 | return ac; |
251 | } |
252 | |