1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright IBM Corp. 2007, 2012 |
4 | * Author(s): Peter Oberparleiter <peter.oberparleiter@de.ibm.com> |
5 | */ |
6 | |
7 | #include <linux/vmalloc.h> |
8 | #include <linux/bitmap.h> |
9 | #include <linux/bitops.h> |
10 | #include "idset.h" |
11 | #include "css.h" |
12 | |
13 | struct idset { |
14 | int num_ssid; |
15 | int num_id; |
16 | unsigned long bitmap[]; |
17 | }; |
18 | |
19 | static inline unsigned long bitmap_size(int num_ssid, int num_id) |
20 | { |
21 | return BITS_TO_LONGS(num_ssid * num_id) * sizeof(unsigned long); |
22 | } |
23 | |
24 | static struct idset *idset_new(int num_ssid, int num_id) |
25 | { |
26 | struct idset *set; |
27 | |
28 | set = vmalloc(size: sizeof(struct idset) + bitmap_size(num_ssid, num_id)); |
29 | if (set) { |
30 | set->num_ssid = num_ssid; |
31 | set->num_id = num_id; |
32 | memset(set->bitmap, 0, bitmap_size(num_ssid, num_id)); |
33 | } |
34 | return set; |
35 | } |
36 | |
37 | void idset_free(struct idset *set) |
38 | { |
39 | vfree(addr: set); |
40 | } |
41 | |
42 | void idset_fill(struct idset *set) |
43 | { |
44 | memset(set->bitmap, 0xff, bitmap_size(set->num_ssid, set->num_id)); |
45 | } |
46 | |
47 | static inline void idset_add(struct idset *set, int ssid, int id) |
48 | { |
49 | set_bit(nr: ssid * set->num_id + id, addr: set->bitmap); |
50 | } |
51 | |
52 | static inline void idset_del(struct idset *set, int ssid, int id) |
53 | { |
54 | clear_bit(nr: ssid * set->num_id + id, addr: set->bitmap); |
55 | } |
56 | |
57 | static inline int idset_contains(struct idset *set, int ssid, int id) |
58 | { |
59 | return test_bit(ssid * set->num_id + id, set->bitmap); |
60 | } |
61 | |
62 | struct idset *idset_sch_new(void) |
63 | { |
64 | return idset_new(num_ssid: max_ssid + 1, num_id: __MAX_SUBCHANNEL + 1); |
65 | } |
66 | |
67 | void idset_sch_add(struct idset *set, struct subchannel_id schid) |
68 | { |
69 | idset_add(set, ssid: schid.ssid, id: schid.sch_no); |
70 | } |
71 | |
72 | void idset_sch_del(struct idset *set, struct subchannel_id schid) |
73 | { |
74 | idset_del(set, ssid: schid.ssid, id: schid.sch_no); |
75 | } |
76 | |
77 | /* Clear ids starting from @schid up to end of subchannel set. */ |
78 | void idset_sch_del_subseq(struct idset *set, struct subchannel_id schid) |
79 | { |
80 | int pos = schid.ssid * set->num_id + schid.sch_no; |
81 | |
82 | bitmap_clear(map: set->bitmap, start: pos, nbits: set->num_id - schid.sch_no); |
83 | } |
84 | |
85 | int idset_sch_contains(struct idset *set, struct subchannel_id schid) |
86 | { |
87 | return idset_contains(set, ssid: schid.ssid, id: schid.sch_no); |
88 | } |
89 | |
90 | int idset_is_empty(struct idset *set) |
91 | { |
92 | return bitmap_empty(src: set->bitmap, nbits: set->num_ssid * set->num_id); |
93 | } |
94 | |
95 | void idset_add_set(struct idset *to, struct idset *from) |
96 | { |
97 | int len = min(to->num_ssid * to->num_id, from->num_ssid * from->num_id); |
98 | |
99 | bitmap_or(dst: to->bitmap, src1: to->bitmap, src2: from->bitmap, nbits: len); |
100 | } |
101 | |