1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/module.h>
19#include <linux/slab.h>
20#include <asm/cpu_device_id.h>
21#include "internal.h"
22
23struct rmid_entry {
24 u32 rmid;
25 int busy;
26 struct list_head list;
27};
28
29
30
31
32
33
34static LIST_HEAD(rmid_free_lru);
35
36
37
38
39
40
41
42
43static unsigned int rmid_limbo_count;
44
45
46
47
48static struct rmid_entry *rmid_ptrs;
49
50
51
52
53
54bool rdt_mon_capable;
55
56
57
58
59unsigned int rdt_mon_features;
60
61
62
63
64
65unsigned int resctrl_cqm_threshold;
66
67static inline struct rmid_entry *__rmid_entry(u32 rmid)
68{
69 struct rmid_entry *entry;
70
71 entry = &rmid_ptrs[rmid];
72 WARN_ON(entry->rmid != rmid);
73
74 return entry;
75}
76
77static u64 __rmid_read(u32 rmid, u32 eventid)
78{
79 u64 val;
80
81
82
83
84
85
86
87
88
89 wrmsr(MSR_IA32_QM_EVTSEL, eventid, rmid);
90 rdmsrl(MSR_IA32_QM_CTR, val);
91
92 return val;
93}
94
95static bool rmid_dirty(struct rmid_entry *entry)
96{
97 u64 val = __rmid_read(entry->rmid, QOS_L3_OCCUP_EVENT_ID);
98
99 return val >= resctrl_cqm_threshold;
100}
101
102
103
104
105
106
107
108void __check_limbo(struct rdt_domain *d, bool force_free)
109{
110 struct rmid_entry *entry;
111 struct rdt_resource *r;
112 u32 crmid = 1, nrmid;
113
114 r = &rdt_resources_all[RDT_RESOURCE_L3];
115
116
117
118
119
120
121
122 for (;;) {
123 nrmid = find_next_bit(d->rmid_busy_llc, r->num_rmid, crmid);
124 if (nrmid >= r->num_rmid)
125 break;
126
127 entry = __rmid_entry(nrmid);
128 if (force_free || !rmid_dirty(entry)) {
129 clear_bit(entry->rmid, d->rmid_busy_llc);
130 if (!--entry->busy) {
131 rmid_limbo_count--;
132 list_add_tail(&entry->list, &rmid_free_lru);
133 }
134 }
135 crmid = nrmid + 1;
136 }
137}
138
139bool has_busy_rmid(struct rdt_resource *r, struct rdt_domain *d)
140{
141 return find_first_bit(d->rmid_busy_llc, r->num_rmid) != r->num_rmid;
142}
143
144
145
146
147
148
149int alloc_rmid(void)
150{
151 struct rmid_entry *entry;
152
153 lockdep_assert_held(&rdtgroup_mutex);
154
155 if (list_empty(&rmid_free_lru))
156 return rmid_limbo_count ? -EBUSY : -ENOSPC;
157
158 entry = list_first_entry(&rmid_free_lru,
159 struct rmid_entry, list);
160 list_del(&entry->list);
161
162 return entry->rmid;
163}
164
165static void add_rmid_to_limbo(struct rmid_entry *entry)
166{
167 struct rdt_resource *r;
168 struct rdt_domain *d;
169 int cpu;
170 u64 val;
171
172 r = &rdt_resources_all[RDT_RESOURCE_L3];
173
174 entry->busy = 0;
175 cpu = get_cpu();
176 list_for_each_entry(d, &r->domains, list) {
177 if (cpumask_test_cpu(cpu, &d->cpu_mask)) {
178 val = __rmid_read(entry->rmid, QOS_L3_OCCUP_EVENT_ID);
179 if (val <= resctrl_cqm_threshold)
180 continue;
181 }
182
183
184
185
186
187 if (!has_busy_rmid(r, d))
188 cqm_setup_limbo_handler(d, CQM_LIMBOCHECK_INTERVAL);
189 set_bit(entry->rmid, d->rmid_busy_llc);
190 entry->busy++;
191 }
192 put_cpu();
193
194 if (entry->busy)
195 rmid_limbo_count++;
196 else
197 list_add_tail(&entry->list, &rmid_free_lru);
198}
199
200void free_rmid(u32 rmid)
201{
202 struct rmid_entry *entry;
203
204 if (!rmid)
205 return;
206
207 lockdep_assert_held(&rdtgroup_mutex);
208
209 entry = __rmid_entry(rmid);
210
211 if (is_llc_occupancy_enabled())
212 add_rmid_to_limbo(entry);
213 else
214 list_add_tail(&entry->list, &rmid_free_lru);
215}
216
217static u64 mbm_overflow_count(u64 prev_msr, u64 cur_msr)
218{
219 u64 shift = 64 - MBM_CNTR_WIDTH, chunks;
220
221 chunks = (cur_msr << shift) - (prev_msr << shift);
222 return chunks >>= shift;
223}
224
225static int __mon_event_count(u32 rmid, struct rmid_read *rr)
226{
227 struct mbm_state *m;
228 u64 chunks, tval;
229
230 tval = __rmid_read(rmid, rr->evtid);
231 if (tval & (RMID_VAL_ERROR | RMID_VAL_UNAVAIL)) {
232 rr->val = tval;
233 return -EINVAL;
234 }
235 switch (rr->evtid) {
236 case QOS_L3_OCCUP_EVENT_ID:
237 rr->val += tval;
238 return 0;
239 case QOS_L3_MBM_TOTAL_EVENT_ID:
240 m = &rr->d->mbm_total[rmid];
241 break;
242 case QOS_L3_MBM_LOCAL_EVENT_ID:
243 m = &rr->d->mbm_local[rmid];
244 break;
245 default:
246
247
248
249
250 return -EINVAL;
251 }
252
253 if (rr->first) {
254 memset(m, 0, sizeof(struct mbm_state));
255 m->prev_bw_msr = m->prev_msr = tval;
256 return 0;
257 }
258
259 chunks = mbm_overflow_count(m->prev_msr, tval);
260 m->chunks += chunks;
261 m->prev_msr = tval;
262
263 rr->val += m->chunks;
264 return 0;
265}
266
267
268
269
270
271static void mbm_bw_count(u32 rmid, struct rmid_read *rr)
272{
273 struct rdt_resource *r = &rdt_resources_all[RDT_RESOURCE_L3];
274 struct mbm_state *m = &rr->d->mbm_local[rmid];
275 u64 tval, cur_bw, chunks;
276
277 tval = __rmid_read(rmid, rr->evtid);
278 if (tval & (RMID_VAL_ERROR | RMID_VAL_UNAVAIL))
279 return;
280
281 chunks = mbm_overflow_count(m->prev_bw_msr, tval);
282 m->chunks_bw += chunks;
283 m->chunks = m->chunks_bw;
284 cur_bw = (chunks * r->mon_scale) >> 20;
285
286 if (m->delta_comp)
287 m->delta_bw = abs(cur_bw - m->prev_bw);
288 m->delta_comp = false;
289 m->prev_bw = cur_bw;
290 m->prev_bw_msr = tval;
291}
292
293
294
295
296
297void mon_event_count(void *info)
298{
299 struct rdtgroup *rdtgrp, *entry;
300 struct rmid_read *rr = info;
301 struct list_head *head;
302
303 rdtgrp = rr->rgrp;
304
305 if (__mon_event_count(rdtgrp->mon.rmid, rr))
306 return;
307
308
309
310
311 head = &rdtgrp->mon.crdtgrp_list;
312
313 if (rdtgrp->type == RDTCTRL_GROUP) {
314 list_for_each_entry(entry, head, mon.crdtgrp_list) {
315 if (__mon_event_count(entry->mon.rmid, rr))
316 return;
317 }
318 }
319}
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353static void update_mba_bw(struct rdtgroup *rgrp, struct rdt_domain *dom_mbm)
354{
355 u32 closid, rmid, cur_msr, cur_msr_val, new_msr_val;
356 struct mbm_state *pmbm_data, *cmbm_data;
357 u32 cur_bw, delta_bw, user_bw;
358 struct rdt_resource *r_mba;
359 struct rdt_domain *dom_mba;
360 struct list_head *head;
361 struct rdtgroup *entry;
362
363 if (!is_mbm_local_enabled())
364 return;
365
366 r_mba = &rdt_resources_all[RDT_RESOURCE_MBA];
367 closid = rgrp->closid;
368 rmid = rgrp->mon.rmid;
369 pmbm_data = &dom_mbm->mbm_local[rmid];
370
371 dom_mba = get_domain_from_cpu(smp_processor_id(), r_mba);
372 if (!dom_mba) {
373 pr_warn_once("Failure to get domain for MBA update\n");
374 return;
375 }
376
377 cur_bw = pmbm_data->prev_bw;
378 user_bw = dom_mba->mbps_val[closid];
379 delta_bw = pmbm_data->delta_bw;
380 cur_msr_val = dom_mba->ctrl_val[closid];
381
382
383
384
385 head = &rgrp->mon.crdtgrp_list;
386 list_for_each_entry(entry, head, mon.crdtgrp_list) {
387 cmbm_data = &dom_mbm->mbm_local[entry->mon.rmid];
388 cur_bw += cmbm_data->prev_bw;
389 delta_bw += cmbm_data->delta_bw;
390 }
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406 if (cur_msr_val > r_mba->membw.min_bw && user_bw < cur_bw) {
407 new_msr_val = cur_msr_val - r_mba->membw.bw_gran;
408 } else if (cur_msr_val < MAX_MBA_BW &&
409 (user_bw > (cur_bw + delta_bw))) {
410 new_msr_val = cur_msr_val + r_mba->membw.bw_gran;
411 } else {
412 return;
413 }
414
415 cur_msr = r_mba->msr_base + closid;
416 wrmsrl(cur_msr, delay_bw_map(new_msr_val, r_mba));
417 dom_mba->ctrl_val[closid] = new_msr_val;
418
419
420
421
422
423
424
425
426
427
428
429 pmbm_data->delta_comp = true;
430 list_for_each_entry(entry, head, mon.crdtgrp_list) {
431 cmbm_data = &dom_mbm->mbm_local[entry->mon.rmid];
432 cmbm_data->delta_comp = true;
433 }
434}
435
436static void mbm_update(struct rdt_domain *d, int rmid)
437{
438 struct rmid_read rr;
439
440 rr.first = false;
441 rr.d = d;
442
443
444
445
446
447 if (is_mbm_total_enabled()) {
448 rr.evtid = QOS_L3_MBM_TOTAL_EVENT_ID;
449 __mon_event_count(rmid, &rr);
450 }
451 if (is_mbm_local_enabled()) {
452 rr.evtid = QOS_L3_MBM_LOCAL_EVENT_ID;
453
454
455
456
457
458
459 if (!is_mba_sc(NULL))
460 __mon_event_count(rmid, &rr);
461 else
462 mbm_bw_count(rmid, &rr);
463 }
464}
465
466
467
468
469
470void cqm_handle_limbo(struct work_struct *work)
471{
472 unsigned long delay = msecs_to_jiffies(CQM_LIMBOCHECK_INTERVAL);
473 int cpu = smp_processor_id();
474 struct rdt_resource *r;
475 struct rdt_domain *d;
476
477 mutex_lock(&rdtgroup_mutex);
478
479 r = &rdt_resources_all[RDT_RESOURCE_L3];
480 d = get_domain_from_cpu(cpu, r);
481
482 if (!d) {
483 pr_warn_once("Failure to get domain for limbo worker\n");
484 goto out_unlock;
485 }
486
487 __check_limbo(d, false);
488
489 if (has_busy_rmid(r, d))
490 schedule_delayed_work_on(cpu, &d->cqm_limbo, delay);
491
492out_unlock:
493 mutex_unlock(&rdtgroup_mutex);
494}
495
496void cqm_setup_limbo_handler(struct rdt_domain *dom, unsigned long delay_ms)
497{
498 unsigned long delay = msecs_to_jiffies(delay_ms);
499 int cpu;
500
501 cpu = cpumask_any(&dom->cpu_mask);
502 dom->cqm_work_cpu = cpu;
503
504 schedule_delayed_work_on(cpu, &dom->cqm_limbo, delay);
505}
506
507void mbm_handle_overflow(struct work_struct *work)
508{
509 unsigned long delay = msecs_to_jiffies(MBM_OVERFLOW_INTERVAL);
510 struct rdtgroup *prgrp, *crgrp;
511 int cpu = smp_processor_id();
512 struct list_head *head;
513 struct rdt_domain *d;
514
515 mutex_lock(&rdtgroup_mutex);
516
517 if (!static_branch_likely(&rdt_enable_key))
518 goto out_unlock;
519
520 d = get_domain_from_cpu(cpu, &rdt_resources_all[RDT_RESOURCE_L3]);
521 if (!d)
522 goto out_unlock;
523
524 list_for_each_entry(prgrp, &rdt_all_groups, rdtgroup_list) {
525 mbm_update(d, prgrp->mon.rmid);
526
527 head = &prgrp->mon.crdtgrp_list;
528 list_for_each_entry(crgrp, head, mon.crdtgrp_list)
529 mbm_update(d, crgrp->mon.rmid);
530
531 if (is_mba_sc(NULL))
532 update_mba_bw(prgrp, d);
533 }
534
535 schedule_delayed_work_on(cpu, &d->mbm_over, delay);
536
537out_unlock:
538 mutex_unlock(&rdtgroup_mutex);
539}
540
541void mbm_setup_overflow_handler(struct rdt_domain *dom, unsigned long delay_ms)
542{
543 unsigned long delay = msecs_to_jiffies(delay_ms);
544 int cpu;
545
546 if (!static_branch_likely(&rdt_enable_key))
547 return;
548 cpu = cpumask_any(&dom->cpu_mask);
549 dom->mbm_work_cpu = cpu;
550 schedule_delayed_work_on(cpu, &dom->mbm_over, delay);
551}
552
553static int dom_data_init(struct rdt_resource *r)
554{
555 struct rmid_entry *entry = NULL;
556 int i, nr_rmids;
557
558 nr_rmids = r->num_rmid;
559 rmid_ptrs = kcalloc(nr_rmids, sizeof(struct rmid_entry), GFP_KERNEL);
560 if (!rmid_ptrs)
561 return -ENOMEM;
562
563 for (i = 0; i < nr_rmids; i++) {
564 entry = &rmid_ptrs[i];
565 INIT_LIST_HEAD(&entry->list);
566
567 entry->rmid = i;
568 list_add_tail(&entry->list, &rmid_free_lru);
569 }
570
571
572
573
574
575 entry = __rmid_entry(0);
576 list_del(&entry->list);
577
578 return 0;
579}
580
581static struct mon_evt llc_occupancy_event = {
582 .name = "llc_occupancy",
583 .evtid = QOS_L3_OCCUP_EVENT_ID,
584};
585
586static struct mon_evt mbm_total_event = {
587 .name = "mbm_total_bytes",
588 .evtid = QOS_L3_MBM_TOTAL_EVENT_ID,
589};
590
591static struct mon_evt mbm_local_event = {
592 .name = "mbm_local_bytes",
593 .evtid = QOS_L3_MBM_LOCAL_EVENT_ID,
594};
595
596
597
598
599
600
601
602
603static void l3_mon_evt_init(struct rdt_resource *r)
604{
605 INIT_LIST_HEAD(&r->evt_list);
606
607 if (is_llc_occupancy_enabled())
608 list_add_tail(&llc_occupancy_event.list, &r->evt_list);
609 if (is_mbm_total_enabled())
610 list_add_tail(&mbm_total_event.list, &r->evt_list);
611 if (is_mbm_local_enabled())
612 list_add_tail(&mbm_local_event.list, &r->evt_list);
613}
614
615int rdt_get_mon_l3_config(struct rdt_resource *r)
616{
617 unsigned int cl_size = boot_cpu_data.x86_cache_size;
618 int ret;
619
620 r->mon_scale = boot_cpu_data.x86_cache_occ_scale;
621 r->num_rmid = boot_cpu_data.x86_cache_max_rmid + 1;
622
623
624
625
626
627
628
629
630 resctrl_cqm_threshold = cl_size * 1024 / r->num_rmid;
631
632
633 resctrl_cqm_threshold /= r->mon_scale;
634
635 ret = dom_data_init(r);
636 if (ret)
637 return ret;
638
639 l3_mon_evt_init(r);
640
641 r->mon_capable = true;
642 r->mon_enabled = true;
643
644 return 0;
645}
646