diff options
author | David Vrabel <david.vrabel@csr.com> | 2008-09-17 11:34:09 -0400 |
---|---|---|
committer | David Vrabel <dv02@dv02pc01.europe.root.pri> | 2008-09-17 11:54:24 -0400 |
commit | 8cc13a09474bb30d15dbf449767bb6d0198a8bf8 (patch) | |
tree | 2423388e0a7e9bca0c6e6f7edd5f492887d38160 | |
parent | 22d203ecef9b0cc1fa8d8f64c935b451ca7d1022 (diff) |
uwb: add the UWB stack (reservation manager)
DRP and reservation management.
Signed-off-by: David Vrabel <david.vrabel@csr.com>
-rw-r--r-- | drivers/uwb/drp-avail.c | 288 | ||||
-rw-r--r-- | drivers/uwb/drp-ie.c | 232 | ||||
-rw-r--r-- | drivers/uwb/drp.c | 461 | ||||
-rw-r--r-- | drivers/uwb/rsv.c | 680 |
4 files changed, 1661 insertions, 0 deletions
diff --git a/drivers/uwb/drp-avail.c b/drivers/uwb/drp-avail.c new file mode 100644 index 000000000000..3febd8552808 --- /dev/null +++ b/drivers/uwb/drp-avail.c | |||
@@ -0,0 +1,288 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * DRP availability management | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Reinette Chatre <reinette.chatre@intel.com> | ||
7 | * Copyright (C) 2008 Cambridge Silicon Radio Ltd. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | * | ||
21 | * | ||
22 | * Manage DRP Availability (the MAS available for DRP | ||
23 | * reservations). Thus: | ||
24 | * | ||
25 | * - Handle DRP Availability Change notifications | ||
26 | * | ||
27 | * - Allow the reservation manager to indicate MAS reserved/released | ||
28 | * by local (owned by/targeted at the radio controller) | ||
29 | * reservations. | ||
30 | * | ||
31 | * - Based on the two sources above, generate a DRP Availability IE to | ||
32 | * be included in the beacon. | ||
33 | * | ||
34 | * See also the documentation for struct uwb_drp_avail. | ||
35 | */ | ||
36 | |||
37 | #include <linux/errno.h> | ||
38 | #include <linux/module.h> | ||
39 | #include <linux/device.h> | ||
40 | #include <linux/bitmap.h> | ||
41 | #include "uwb-internal.h" | ||
42 | |||
43 | /** | ||
44 | * uwb_drp_avail_init - initialize an RC's MAS availability | ||
45 | * | ||
46 | * All MAS are available initially. The RC will inform use which | ||
47 | * slots are used for the BP (it may change in size). | ||
48 | */ | ||
49 | void uwb_drp_avail_init(struct uwb_rc *rc) | ||
50 | { | ||
51 | bitmap_fill(rc->drp_avail.global, UWB_NUM_MAS); | ||
52 | bitmap_fill(rc->drp_avail.local, UWB_NUM_MAS); | ||
53 | bitmap_fill(rc->drp_avail.pending, UWB_NUM_MAS); | ||
54 | } | ||
55 | |||
56 | /* | ||
57 | * Determine MAS available for new local reservations. | ||
58 | * | ||
59 | * avail = global & local & pending | ||
60 | */ | ||
61 | static void uwb_drp_available(struct uwb_rc *rc, struct uwb_mas_bm *avail) | ||
62 | { | ||
63 | bitmap_and(avail->bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS); | ||
64 | bitmap_and(avail->bm, avail->bm, rc->drp_avail.pending, UWB_NUM_MAS); | ||
65 | } | ||
66 | |||
67 | /** | ||
68 | * uwb_drp_avail_reserve_pending - reserve MAS for a new reservation | ||
69 | * @rc: the radio controller | ||
70 | * @mas: the MAS to reserve | ||
71 | * | ||
72 | * Returns 0 on success, or -EBUSY if the MAS requested aren't available. | ||
73 | */ | ||
74 | int uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas) | ||
75 | { | ||
76 | struct uwb_mas_bm avail; | ||
77 | |||
78 | uwb_drp_available(rc, &avail); | ||
79 | if (!bitmap_subset(mas->bm, avail.bm, UWB_NUM_MAS)) | ||
80 | return -EBUSY; | ||
81 | |||
82 | bitmap_andnot(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS); | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | /** | ||
87 | * uwb_drp_avail_reserve - reserve MAS for an established reservation | ||
88 | * @rc: the radio controller | ||
89 | * @mas: the MAS to reserve | ||
90 | */ | ||
91 | void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas) | ||
92 | { | ||
93 | bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS); | ||
94 | bitmap_andnot(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS); | ||
95 | rc->drp_avail.ie_valid = false; | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * uwb_drp_avail_release - release MAS from a pending or established reservation | ||
100 | * @rc: the radio controller | ||
101 | * @mas: the MAS to release | ||
102 | */ | ||
103 | void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas) | ||
104 | { | ||
105 | bitmap_or(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS); | ||
106 | bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS); | ||
107 | rc->drp_avail.ie_valid = false; | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * uwb_drp_avail_ie_update - update the DRP Availability IE | ||
112 | * @rc: the radio controller | ||
113 | * | ||
114 | * avail = global & local | ||
115 | */ | ||
116 | void uwb_drp_avail_ie_update(struct uwb_rc *rc) | ||
117 | { | ||
118 | struct uwb_mas_bm avail; | ||
119 | |||
120 | bitmap_and(avail.bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS); | ||
121 | |||
122 | rc->drp_avail.ie.hdr.element_id = UWB_IE_DRP_AVAILABILITY; | ||
123 | rc->drp_avail.ie.hdr.length = UWB_NUM_MAS / 8; | ||
124 | uwb_mas_bm_copy_le(rc->drp_avail.ie.bmp, &avail); | ||
125 | rc->drp_avail.ie_valid = true; | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * Create an unsigned long from a buffer containing a byte stream. | ||
130 | * | ||
131 | * @array: pointer to buffer | ||
132 | * @itr: index of buffer from where we start | ||
133 | * @len: the buffer's remaining size may not be exact multiple of | ||
134 | * sizeof(unsigned long), @len is the length of buffer that needs | ||
135 | * to be converted. This will be sizeof(unsigned long) or smaller | ||
136 | * (BUG if not). If it is smaller then we will pad the remaining | ||
137 | * space of the result with zeroes. | ||
138 | */ | ||
139 | static | ||
140 | unsigned long get_val(u8 *array, size_t itr, size_t len) | ||
141 | { | ||
142 | unsigned long val = 0; | ||
143 | size_t top = itr + len; | ||
144 | |||
145 | BUG_ON(len > sizeof(val)); | ||
146 | |||
147 | while (itr < top) { | ||
148 | val <<= 8; | ||
149 | val |= array[top - 1]; | ||
150 | top--; | ||
151 | } | ||
152 | val <<= 8 * (sizeof(val) - len); /* padding */ | ||
153 | return val; | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * Initialize bitmap from data buffer. | ||
158 | * | ||
159 | * The bitmap to be converted could come from a IE, for example a | ||
160 | * DRP Availability IE. | ||
161 | * From ECMA-368 1.0 [16.8.7]: " | ||
162 | * octets: 1 1 N * (0 to 32) | ||
163 | * Element ID Length (=N) DRP Availability Bitmap | ||
164 | * | ||
165 | * The DRP Availability Bitmap field is up to 256 bits long, one | ||
166 | * bit for each MAS in the superframe, where the least-significant | ||
167 | * bit of the field corresponds to the first MAS in the superframe | ||
168 | * and successive bits correspond to successive MASs." | ||
169 | * | ||
170 | * The DRP Availability bitmap is in octets from 0 to 32, so octet | ||
171 | * 32 contains bits for MAS 1-8, etc. If the bitmap is smaller than 32 | ||
172 | * octets, the bits in octets not included at the end of the bitmap are | ||
173 | * treated as zero. In this case (when the bitmap is smaller than 32 | ||
174 | * octets) the MAS represented range from MAS 1 to MAS (size of bitmap) | ||
175 | * with the last octet still containing bits for MAS 1-8, etc. | ||
176 | * | ||
177 | * For example: | ||
178 | * F00F0102 03040506 0708090A 0B0C0D0E 0F010203 | ||
179 | * ^^^^ | ||
180 | * |||| | ||
181 | * |||| | ||
182 | * |||\LSB of byte is MAS 9 | ||
183 | * ||\MSB of byte is MAS 16 | ||
184 | * |\LSB of first byte is MAS 1 | ||
185 | * \ MSB of byte is MAS 8 | ||
186 | * | ||
187 | * An example of this encoding can be found in ECMA-368 Annex-D [Table D.11] | ||
188 | * | ||
189 | * The resulting bitmap will have the following mapping: | ||
190 | * bit position 0 == MAS 1 | ||
191 | * bit position 1 == MAS 2 | ||
192 | * ... | ||
193 | * bit position (UWB_NUM_MAS - 1) == MAS UWB_NUM_MAS | ||
194 | * | ||
195 | * @bmp_itr: pointer to bitmap (can be declared with DECLARE_BITMAP) | ||
196 | * @buffer: pointer to buffer containing bitmap data in big endian | ||
197 | * format (MSB first) | ||
198 | * @buffer_size:number of bytes with which bitmap should be initialized | ||
199 | */ | ||
200 | static | ||
201 | void buffer_to_bmp(unsigned long *bmp_itr, void *_buffer, | ||
202 | size_t buffer_size) | ||
203 | { | ||
204 | u8 *buffer = _buffer; | ||
205 | size_t itr, len; | ||
206 | unsigned long val; | ||
207 | |||
208 | itr = 0; | ||
209 | while (itr < buffer_size) { | ||
210 | len = buffer_size - itr >= sizeof(val) ? | ||
211 | sizeof(val) : buffer_size - itr; | ||
212 | val = get_val(buffer, itr, len); | ||
213 | bmp_itr[itr / sizeof(val)] = val; | ||
214 | itr += sizeof(val); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | |||
219 | /** | ||
220 | * Extract DRP Availability bitmap from the notification. | ||
221 | * | ||
222 | * The notification that comes in contains a bitmap of (UWB_NUM_MAS / 8) bytes | ||
223 | * We convert that to our internal representation. | ||
224 | */ | ||
225 | static | ||
226 | int uwbd_evt_get_drp_avail(struct uwb_event *evt, unsigned long *bmp) | ||
227 | { | ||
228 | struct device *dev = &evt->rc->uwb_dev.dev; | ||
229 | struct uwb_rc_evt_drp_avail *drp_evt; | ||
230 | int result = -EINVAL; | ||
231 | |||
232 | /* Is there enough data to decode the event? */ | ||
233 | if (evt->notif.size < sizeof(*drp_evt)) { | ||
234 | dev_err(dev, "DRP Availability Change: Not enough " | ||
235 | "data to decode event [%zu bytes, %zu " | ||
236 | "needed]\n", evt->notif.size, sizeof(*drp_evt)); | ||
237 | goto error; | ||
238 | } | ||
239 | drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp_avail, rceb); | ||
240 | buffer_to_bmp(bmp, drp_evt->bmp, UWB_NUM_MAS/8); | ||
241 | result = 0; | ||
242 | error: | ||
243 | return result; | ||
244 | } | ||
245 | |||
246 | |||
247 | /** | ||
248 | * Process an incoming DRP Availability notification. | ||
249 | * | ||
250 | * @evt: Event information (packs the actual event data, which | ||
251 | * radio controller it came to, etc). | ||
252 | * | ||
253 | * @returns: 0 on success (so uwbd() frees the event buffer), < 0 | ||
254 | * on error. | ||
255 | * | ||
256 | * According to ECMA-368 1.0 [16.8.7], bits set to ONE indicate that | ||
257 | * the MAS slot is available, bits set to ZERO indicate that the slot | ||
258 | * is busy. | ||
259 | * | ||
260 | * So we clear available slots, we set used slots :) | ||
261 | * | ||
262 | * The notification only marks non-availability based on the BP and | ||
263 | * received DRP IEs that are not for this radio controller. A copy of | ||
264 | * this bitmap is needed to generate the real availability (which | ||
265 | * includes local and pending reservations). | ||
266 | * | ||
267 | * The DRP Availability IE that this radio controller emits will need | ||
268 | * to be updated. | ||
269 | */ | ||
270 | int uwbd_evt_handle_rc_drp_avail(struct uwb_event *evt) | ||
271 | { | ||
272 | int result; | ||
273 | struct uwb_rc *rc = evt->rc; | ||
274 | DECLARE_BITMAP(bmp, UWB_NUM_MAS); | ||
275 | |||
276 | result = uwbd_evt_get_drp_avail(evt, bmp); | ||
277 | if (result < 0) | ||
278 | return result; | ||
279 | |||
280 | mutex_lock(&rc->rsvs_mutex); | ||
281 | bitmap_copy(rc->drp_avail.global, bmp, UWB_NUM_MAS); | ||
282 | rc->drp_avail.ie_valid = false; | ||
283 | mutex_unlock(&rc->rsvs_mutex); | ||
284 | |||
285 | uwb_rsv_sched_update(rc); | ||
286 | |||
287 | return 0; | ||
288 | } | ||
diff --git a/drivers/uwb/drp-ie.c b/drivers/uwb/drp-ie.c new file mode 100644 index 000000000000..882724c5f126 --- /dev/null +++ b/drivers/uwb/drp-ie.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * UWB DRP IE management. | ||
3 | * | ||
4 | * Copyright (C) 2005-2006 Intel Corporation | ||
5 | * Copyright (C) 2008 Cambridge Silicon Radio Ltd. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | #include <linux/version.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/random.h> | ||
22 | #include <linux/uwb.h> | ||
23 | |||
24 | #include "uwb-internal.h" | ||
25 | |||
26 | /* | ||
27 | * Allocate a DRP IE. | ||
28 | * | ||
29 | * To save having to free/allocate a DRP IE when its MAS changes, | ||
30 | * enough memory is allocated for the maxiumum number of DRP | ||
31 | * allocation fields. This gives an overhead per reservation of up to | ||
32 | * (UWB_NUM_ZONES - 1) * 4 = 60 octets. | ||
33 | */ | ||
34 | static struct uwb_ie_drp *uwb_drp_ie_alloc(void) | ||
35 | { | ||
36 | struct uwb_ie_drp *drp_ie; | ||
37 | unsigned tiebreaker; | ||
38 | |||
39 | drp_ie = kzalloc(sizeof(struct uwb_ie_drp) + | ||
40 | UWB_NUM_ZONES * sizeof(struct uwb_drp_alloc), | ||
41 | GFP_KERNEL); | ||
42 | if (drp_ie) { | ||
43 | drp_ie->hdr.element_id = UWB_IE_DRP; | ||
44 | |||
45 | get_random_bytes(&tiebreaker, sizeof(unsigned)); | ||
46 | uwb_ie_drp_set_tiebreaker(drp_ie, tiebreaker & 1); | ||
47 | } | ||
48 | return drp_ie; | ||
49 | } | ||
50 | |||
51 | |||
52 | /* | ||
53 | * Fill a DRP IE's allocation fields from a MAS bitmap. | ||
54 | */ | ||
55 | static void uwb_drp_ie_from_bm(struct uwb_ie_drp *drp_ie, | ||
56 | struct uwb_mas_bm *mas) | ||
57 | { | ||
58 | int z, i, num_fields = 0, next = 0; | ||
59 | struct uwb_drp_alloc *zones; | ||
60 | __le16 current_bmp; | ||
61 | DECLARE_BITMAP(tmp_bmp, UWB_NUM_MAS); | ||
62 | DECLARE_BITMAP(tmp_mas_bm, UWB_MAS_PER_ZONE); | ||
63 | |||
64 | zones = drp_ie->allocs; | ||
65 | |||
66 | bitmap_copy(tmp_bmp, mas->bm, UWB_NUM_MAS); | ||
67 | |||
68 | /* Determine unique MAS bitmaps in zones from bitmap. */ | ||
69 | for (z = 0; z < UWB_NUM_ZONES; z++) { | ||
70 | bitmap_copy(tmp_mas_bm, tmp_bmp, UWB_MAS_PER_ZONE); | ||
71 | if (bitmap_weight(tmp_mas_bm, UWB_MAS_PER_ZONE) > 0) { | ||
72 | bool found = false; | ||
73 | current_bmp = (__le16) *tmp_mas_bm; | ||
74 | for (i = 0; i < next; i++) { | ||
75 | if (current_bmp == zones[i].mas_bm) { | ||
76 | zones[i].zone_bm |= 1 << z; | ||
77 | found = true; | ||
78 | break; | ||
79 | } | ||
80 | } | ||
81 | if (!found) { | ||
82 | num_fields++; | ||
83 | zones[next].zone_bm = 1 << z; | ||
84 | zones[next].mas_bm = current_bmp; | ||
85 | next++; | ||
86 | } | ||
87 | } | ||
88 | bitmap_shift_right(tmp_bmp, tmp_bmp, UWB_MAS_PER_ZONE, UWB_NUM_MAS); | ||
89 | } | ||
90 | |||
91 | /* Store in format ready for transmission (le16). */ | ||
92 | for (i = 0; i < num_fields; i++) { | ||
93 | drp_ie->allocs[i].zone_bm = cpu_to_le16(zones[i].zone_bm); | ||
94 | drp_ie->allocs[i].mas_bm = cpu_to_le16(zones[i].mas_bm); | ||
95 | } | ||
96 | |||
97 | drp_ie->hdr.length = sizeof(struct uwb_ie_drp) - sizeof(struct uwb_ie_hdr) | ||
98 | + num_fields * sizeof(struct uwb_drp_alloc); | ||
99 | } | ||
100 | |||
101 | /** | ||
102 | * uwb_drp_ie_update - update a reservation's DRP IE | ||
103 | * @rsv: the reservation | ||
104 | */ | ||
105 | int uwb_drp_ie_update(struct uwb_rsv *rsv) | ||
106 | { | ||
107 | struct device *dev = &rsv->rc->uwb_dev.dev; | ||
108 | struct uwb_ie_drp *drp_ie; | ||
109 | int reason_code, status; | ||
110 | |||
111 | switch (rsv->state) { | ||
112 | case UWB_RSV_STATE_NONE: | ||
113 | kfree(rsv->drp_ie); | ||
114 | rsv->drp_ie = NULL; | ||
115 | return 0; | ||
116 | case UWB_RSV_STATE_O_INITIATED: | ||
117 | reason_code = UWB_DRP_REASON_ACCEPTED; | ||
118 | status = 0; | ||
119 | break; | ||
120 | case UWB_RSV_STATE_O_PENDING: | ||
121 | reason_code = UWB_DRP_REASON_ACCEPTED; | ||
122 | status = 0; | ||
123 | break; | ||
124 | case UWB_RSV_STATE_O_MODIFIED: | ||
125 | reason_code = UWB_DRP_REASON_MODIFIED; | ||
126 | status = 1; | ||
127 | break; | ||
128 | case UWB_RSV_STATE_O_ESTABLISHED: | ||
129 | reason_code = UWB_DRP_REASON_ACCEPTED; | ||
130 | status = 1; | ||
131 | break; | ||
132 | case UWB_RSV_STATE_T_ACCEPTED: | ||
133 | reason_code = UWB_DRP_REASON_ACCEPTED; | ||
134 | status = 1; | ||
135 | break; | ||
136 | case UWB_RSV_STATE_T_DENIED: | ||
137 | reason_code = UWB_DRP_REASON_DENIED; | ||
138 | status = 0; | ||
139 | break; | ||
140 | default: | ||
141 | dev_dbg(dev, "rsv with unhandled state (%d)\n", rsv->state); | ||
142 | return -EINVAL; | ||
143 | } | ||
144 | |||
145 | if (rsv->drp_ie == NULL) { | ||
146 | rsv->drp_ie = uwb_drp_ie_alloc(); | ||
147 | if (rsv->drp_ie == NULL) | ||
148 | return -ENOMEM; | ||
149 | } | ||
150 | drp_ie = rsv->drp_ie; | ||
151 | |||
152 | uwb_ie_drp_set_owner(drp_ie, uwb_rsv_is_owner(rsv)); | ||
153 | uwb_ie_drp_set_status(drp_ie, status); | ||
154 | uwb_ie_drp_set_reason_code(drp_ie, reason_code); | ||
155 | uwb_ie_drp_set_stream_index(drp_ie, rsv->stream); | ||
156 | uwb_ie_drp_set_type(drp_ie, rsv->type); | ||
157 | |||
158 | if (uwb_rsv_is_owner(rsv)) { | ||
159 | switch (rsv->target.type) { | ||
160 | case UWB_RSV_TARGET_DEV: | ||
161 | drp_ie->dev_addr = rsv->target.dev->dev_addr; | ||
162 | break; | ||
163 | case UWB_RSV_TARGET_DEVADDR: | ||
164 | drp_ie->dev_addr = rsv->target.devaddr; | ||
165 | break; | ||
166 | } | ||
167 | } else | ||
168 | drp_ie->dev_addr = rsv->owner->dev_addr; | ||
169 | |||
170 | uwb_drp_ie_from_bm(drp_ie, &rsv->mas); | ||
171 | |||
172 | rsv->ie_valid = true; | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * Set MAS bits from given MAS bitmap in a single zone of large bitmap. | ||
178 | * | ||
179 | * We are given a zone id and the MAS bitmap of bits that need to be set in | ||
180 | * this zone. Note that this zone may already have bits set and this only | ||
181 | * adds settings - we cannot simply assign the MAS bitmap contents to the | ||
182 | * zone contents. We iterate over the the bits (MAS) in the zone and set the | ||
183 | * bits that are set in the given MAS bitmap. | ||
184 | */ | ||
185 | static | ||
186 | void uwb_drp_ie_single_zone_to_bm(struct uwb_mas_bm *bm, u8 zone, u16 mas_bm) | ||
187 | { | ||
188 | int mas; | ||
189 | u16 mas_mask; | ||
190 | |||
191 | for (mas = 0; mas < UWB_MAS_PER_ZONE; mas++) { | ||
192 | mas_mask = 1 << mas; | ||
193 | if (mas_bm & mas_mask) | ||
194 | set_bit(zone * UWB_NUM_ZONES + mas, bm->bm); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * uwb_drp_ie_zones_to_bm - convert DRP allocation fields to a bitmap | ||
200 | * @mas: MAS bitmap that will be populated to correspond to the | ||
201 | * allocation fields in the DRP IE | ||
202 | * @drp_ie: the DRP IE that contains the allocation fields. | ||
203 | * | ||
204 | * The input format is an array of MAS allocation fields (16 bit Zone | ||
205 | * bitmap, 16 bit MAS bitmap) as described in [ECMA-368] section | ||
206 | * 16.8.6. The output is a full 256 bit MAS bitmap. | ||
207 | * | ||
208 | * We go over all the allocation fields, for each allocation field we | ||
209 | * know which zones are impacted. We iterate over all the zones | ||
210 | * impacted and call a function that will set the correct MAS bits in | ||
211 | * each zone. | ||
212 | */ | ||
213 | void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie) | ||
214 | { | ||
215 | int numallocs = (drp_ie->hdr.length - 4) / 4; | ||
216 | const struct uwb_drp_alloc *alloc; | ||
217 | int cnt; | ||
218 | u16 zone_bm, mas_bm; | ||
219 | u8 zone; | ||
220 | u16 zone_mask; | ||
221 | |||
222 | for (cnt = 0; cnt < numallocs; cnt++) { | ||
223 | alloc = &drp_ie->allocs[cnt]; | ||
224 | zone_bm = le16_to_cpu(alloc->zone_bm); | ||
225 | mas_bm = le16_to_cpu(alloc->mas_bm); | ||
226 | for (zone = 0; zone < UWB_NUM_ZONES; zone++) { | ||
227 | zone_mask = 1 << zone; | ||
228 | if (zone_bm & zone_mask) | ||
229 | uwb_drp_ie_single_zone_to_bm(bm, zone, mas_bm); | ||
230 | } | ||
231 | } | ||
232 | } | ||
diff --git a/drivers/uwb/drp.c b/drivers/uwb/drp.c new file mode 100644 index 000000000000..c0b1e5e2bd08 --- /dev/null +++ b/drivers/uwb/drp.c | |||
@@ -0,0 +1,461 @@ | |||
1 | /* | ||
2 | * Ultra Wide Band | ||
3 | * Dynamic Reservation Protocol handling | ||
4 | * | ||
5 | * Copyright (C) 2005-2006 Intel Corporation | ||
6 | * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | ||
7 | * Copyright (C) 2008 Cambridge Silicon Radio Ltd. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | ||
21 | #include <linux/kthread.h> | ||
22 | #include <linux/freezer.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include "uwb-internal.h" | ||
25 | |||
26 | /** | ||
27 | * Construct and send the SET DRP IE | ||
28 | * | ||
29 | * @rc: UWB Host controller | ||
30 | * @returns: >= 0 number of bytes still available in the beacon | ||
31 | * < 0 errno code on error. | ||
32 | * | ||
33 | * See WUSB[8.6.2.7]: The host must set all the DRP IEs that it wants the | ||
34 | * device to include in its beacon at the same time. We thus have to | ||
35 | * traverse all reservations and include the DRP IEs of all PENDING | ||
36 | * and NEGOTIATED reservations in a SET DRP command for transmission. | ||
37 | * | ||
38 | * A DRP Availability IE is appended. | ||
39 | * | ||
40 | * rc->uwb_dev.mutex is held | ||
41 | * | ||
42 | * FIXME We currently ignore the returned value indicating the remaining space | ||
43 | * in beacon. This could be used to deny reservation requests earlier if | ||
44 | * determined that they would cause the beacon space to be exceeded. | ||
45 | */ | ||
46 | static | ||
47 | int uwb_rc_gen_send_drp_ie(struct uwb_rc *rc) | ||
48 | { | ||
49 | int result; | ||
50 | struct device *dev = &rc->uwb_dev.dev; | ||
51 | struct uwb_rc_cmd_set_drp_ie *cmd; | ||
52 | struct uwb_rc_evt_set_drp_ie reply; | ||
53 | struct uwb_rsv *rsv; | ||
54 | int num_bytes = 0; | ||
55 | u8 *IEDataptr; | ||
56 | |||
57 | result = -ENOMEM; | ||
58 | /* First traverse all reservations to determine memory needed. */ | ||
59 | list_for_each_entry(rsv, &rc->reservations, rc_node) { | ||
60 | if (rsv->drp_ie != NULL) | ||
61 | num_bytes += rsv->drp_ie->hdr.length + 2; | ||
62 | } | ||
63 | num_bytes += sizeof(rc->drp_avail.ie); | ||
64 | cmd = kzalloc(sizeof(*cmd) + num_bytes, GFP_KERNEL); | ||
65 | if (cmd == NULL) | ||
66 | goto error; | ||
67 | cmd->rccb.bCommandType = UWB_RC_CET_GENERAL; | ||
68 | cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_DRP_IE); | ||
69 | cmd->wIELength = num_bytes; | ||
70 | IEDataptr = (u8 *)&cmd->IEData[0]; | ||
71 | |||
72 | /* Next traverse all reservations to place IEs in allocated memory. */ | ||
73 | list_for_each_entry(rsv, &rc->reservations, rc_node) { | ||
74 | if (rsv->drp_ie != NULL) { | ||
75 | memcpy(IEDataptr, rsv->drp_ie, | ||
76 | rsv->drp_ie->hdr.length + 2); | ||
77 | IEDataptr += rsv->drp_ie->hdr.length + 2; | ||
78 | } | ||
79 | } | ||
80 | memcpy(IEDataptr, &rc->drp_avail.ie, sizeof(rc->drp_avail.ie)); | ||
81 | |||
82 | reply.rceb.bEventType = UWB_RC_CET_GENERAL; | ||
83 | reply.rceb.wEvent = UWB_RC_CMD_SET_DRP_IE; | ||
84 | result = uwb_rc_cmd(rc, "SET-DRP-IE", &cmd->rccb, | ||
85 | sizeof(*cmd) + num_bytes, &reply.rceb, | ||
86 | sizeof(reply)); | ||
87 | if (result < 0) | ||
88 | goto error_cmd; | ||
89 | result = le16_to_cpu(reply.wRemainingSpace); | ||
90 | if (reply.bResultCode != UWB_RC_RES_SUCCESS) { | ||
91 | dev_err(&rc->uwb_dev.dev, "SET-DRP-IE: command execution " | ||
92 | "failed: %s (%d). RemainingSpace in beacon " | ||
93 | "= %d\n", uwb_rc_strerror(reply.bResultCode), | ||
94 | reply.bResultCode, result); | ||
95 | result = -EIO; | ||
96 | } else { | ||
97 | dev_dbg(dev, "SET-DRP-IE sent. RemainingSpace in beacon " | ||
98 | "= %d.\n", result); | ||
99 | result = 0; | ||
100 | } | ||
101 | error_cmd: | ||
102 | kfree(cmd); | ||
103 | error: | ||
104 | return result; | ||
105 | |||
106 | } | ||
107 | /** | ||
108 | * Send all DRP IEs associated with this host | ||
109 | * | ||
110 | * @returns: >= 0 number of bytes still available in the beacon | ||
111 | * < 0 errno code on error. | ||
112 | * | ||
113 | * As per the protocol we obtain the host controller device lock to access | ||
114 | * bandwidth structures. | ||
115 | */ | ||
116 | int uwb_rc_send_all_drp_ie(struct uwb_rc *rc) | ||
117 | { | ||
118 | int result; | ||
119 | |||
120 | mutex_lock(&rc->uwb_dev.mutex); | ||
121 | result = uwb_rc_gen_send_drp_ie(rc); | ||
122 | mutex_unlock(&rc->uwb_dev.mutex); | ||
123 | return result; | ||
124 | } | ||
125 | |||
126 | void uwb_drp_handle_timeout(struct uwb_rsv *rsv) | ||
127 | { | ||
128 | struct device *dev = &rsv->rc->uwb_dev.dev; | ||
129 | |||
130 | dev_dbg(dev, "reservation timeout in state %s (%d)\n", | ||
131 | uwb_rsv_state_str(rsv->state), rsv->state); | ||
132 | |||
133 | switch (rsv->state) { | ||
134 | case UWB_RSV_STATE_O_INITIATED: | ||
135 | if (rsv->is_multicast) { | ||
136 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); | ||
137 | return; | ||
138 | } | ||
139 | break; | ||
140 | case UWB_RSV_STATE_O_ESTABLISHED: | ||
141 | if (rsv->is_multicast) | ||
142 | return; | ||
143 | break; | ||
144 | default: | ||
145 | break; | ||
146 | } | ||
147 | uwb_rsv_remove(rsv); | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * Based on the DRP IE, transition a target reservation to a new | ||
152 | * state. | ||
153 | */ | ||
154 | static void uwb_drp_process_target(struct uwb_rc *rc, struct uwb_rsv *rsv, | ||
155 | struct uwb_ie_drp *drp_ie) | ||
156 | { | ||
157 | struct device *dev = &rc->uwb_dev.dev; | ||
158 | int status; | ||
159 | enum uwb_drp_reason reason_code; | ||
160 | |||
161 | status = uwb_ie_drp_status(drp_ie); | ||
162 | reason_code = uwb_ie_drp_reason_code(drp_ie); | ||
163 | |||
164 | if (status) { | ||
165 | switch (reason_code) { | ||
166 | case UWB_DRP_REASON_ACCEPTED: | ||
167 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED); | ||
168 | break; | ||
169 | case UWB_DRP_REASON_MODIFIED: | ||
170 | dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n", | ||
171 | reason_code, status); | ||
172 | break; | ||
173 | default: | ||
174 | dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n", | ||
175 | reason_code, status); | ||
176 | } | ||
177 | } else { | ||
178 | switch (reason_code) { | ||
179 | case UWB_DRP_REASON_ACCEPTED: | ||
180 | /* New reservations are handled in uwb_rsv_find(). */ | ||
181 | break; | ||
182 | case UWB_DRP_REASON_DENIED: | ||
183 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); | ||
184 | break; | ||
185 | case UWB_DRP_REASON_CONFLICT: | ||
186 | case UWB_DRP_REASON_MODIFIED: | ||
187 | dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n", | ||
188 | reason_code, status); | ||
189 | break; | ||
190 | default: | ||
191 | dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n", | ||
192 | reason_code, status); | ||
193 | } | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * Based on the DRP IE, transition an owner reservation to a new | ||
199 | * state. | ||
200 | */ | ||
201 | static void uwb_drp_process_owner(struct uwb_rc *rc, struct uwb_rsv *rsv, | ||
202 | struct uwb_ie_drp *drp_ie) | ||
203 | { | ||
204 | struct device *dev = &rc->uwb_dev.dev; | ||
205 | int status; | ||
206 | enum uwb_drp_reason reason_code; | ||
207 | |||
208 | status = uwb_ie_drp_status(drp_ie); | ||
209 | reason_code = uwb_ie_drp_reason_code(drp_ie); | ||
210 | |||
211 | if (status) { | ||
212 | switch (reason_code) { | ||
213 | case UWB_DRP_REASON_ACCEPTED: | ||
214 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); | ||
215 | break; | ||
216 | case UWB_DRP_REASON_MODIFIED: | ||
217 | dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n", | ||
218 | reason_code, status); | ||
219 | break; | ||
220 | default: | ||
221 | dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n", | ||
222 | reason_code, status); | ||
223 | } | ||
224 | } else { | ||
225 | switch (reason_code) { | ||
226 | case UWB_DRP_REASON_PENDING: | ||
227 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_PENDING); | ||
228 | break; | ||
229 | case UWB_DRP_REASON_DENIED: | ||
230 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); | ||
231 | break; | ||
232 | case UWB_DRP_REASON_CONFLICT: | ||
233 | case UWB_DRP_REASON_MODIFIED: | ||
234 | dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n", | ||
235 | reason_code, status); | ||
236 | break; | ||
237 | default: | ||
238 | dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n", | ||
239 | reason_code, status); | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | |||
244 | /* | ||
245 | * Process a received DRP IE, it's either for a reservation owned by | ||
246 | * the RC or targeted at it (or it's for a WUSB cluster reservation). | ||
247 | */ | ||
248 | static void uwb_drp_process(struct uwb_rc *rc, struct uwb_dev *src, | ||
249 | struct uwb_ie_drp *drp_ie) | ||
250 | { | ||
251 | struct uwb_rsv *rsv; | ||
252 | |||
253 | rsv = uwb_rsv_find(rc, src, drp_ie); | ||
254 | if (!rsv) { | ||
255 | /* | ||
256 | * No reservation? It's either for a recently | ||
257 | * terminated reservation; or the DRP IE couldn't be | ||
258 | * processed (e.g., an invalid IE or out of memory). | ||
259 | */ | ||
260 | return; | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * Do nothing with DRP IEs for reservations that have been | ||
265 | * terminated. | ||
266 | */ | ||
267 | if (rsv->state == UWB_RSV_STATE_NONE) { | ||
268 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); | ||
269 | return; | ||
270 | } | ||
271 | |||
272 | if (uwb_ie_drp_owner(drp_ie)) | ||
273 | uwb_drp_process_target(rc, rsv, drp_ie); | ||
274 | else | ||
275 | uwb_drp_process_owner(rc, rsv, drp_ie); | ||
276 | } | ||
277 | |||
278 | |||
279 | /* | ||
280 | * Process all the DRP IEs (both DRP IEs and the DRP Availability IE) | ||
281 | * from a device. | ||
282 | */ | ||
283 | static | ||
284 | void uwb_drp_process_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt, | ||
285 | size_t ielen, struct uwb_dev *src_dev) | ||
286 | { | ||
287 | struct device *dev = &rc->uwb_dev.dev; | ||
288 | struct uwb_ie_hdr *ie_hdr; | ||
289 | void *ptr; | ||
290 | |||
291 | ptr = drp_evt->ie_data; | ||
292 | for (;;) { | ||
293 | ie_hdr = uwb_ie_next(&ptr, &ielen); | ||
294 | if (!ie_hdr) | ||
295 | break; | ||
296 | |||
297 | switch (ie_hdr->element_id) { | ||
298 | case UWB_IE_DRP_AVAILABILITY: | ||
299 | /* FIXME: does something need to be done with this? */ | ||
300 | break; | ||
301 | case UWB_IE_DRP: | ||
302 | uwb_drp_process(rc, src_dev, (struct uwb_ie_drp *)ie_hdr); | ||
303 | break; | ||
304 | default: | ||
305 | dev_warn(dev, "unexpected IE in DRP notification\n"); | ||
306 | break; | ||
307 | } | ||
308 | } | ||
309 | |||
310 | if (ielen > 0) | ||
311 | dev_warn(dev, "%d octets remaining in DRP notification\n", | ||
312 | (int)ielen); | ||
313 | } | ||
314 | |||
315 | |||
316 | /* | ||
317 | * Go through all the DRP IEs and find the ones that conflict with our | ||
318 | * reservations. | ||
319 | * | ||
320 | * FIXME: must resolve the conflict according the the rules in | ||
321 | * [ECMA-368]. | ||
322 | */ | ||
323 | static | ||
324 | void uwb_drp_process_conflict_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt, | ||
325 | size_t ielen, struct uwb_dev *src_dev) | ||
326 | { | ||
327 | struct device *dev = &rc->uwb_dev.dev; | ||
328 | struct uwb_ie_hdr *ie_hdr; | ||
329 | struct uwb_ie_drp *drp_ie; | ||
330 | void *ptr; | ||
331 | |||
332 | ptr = drp_evt->ie_data; | ||
333 | for (;;) { | ||
334 | ie_hdr = uwb_ie_next(&ptr, &ielen); | ||
335 | if (!ie_hdr) | ||
336 | break; | ||
337 | |||
338 | drp_ie = container_of(ie_hdr, struct uwb_ie_drp, hdr); | ||
339 | |||
340 | /* FIXME: check if this DRP IE conflicts. */ | ||
341 | } | ||
342 | |||
343 | if (ielen > 0) | ||
344 | dev_warn(dev, "%d octets remaining in DRP notification\n", | ||
345 | (int)ielen); | ||
346 | } | ||
347 | |||
348 | |||
349 | /* | ||
350 | * Terminate all reservations owned by, or targeted at, 'uwb_dev'. | ||
351 | */ | ||
352 | static void uwb_drp_terminate_all(struct uwb_rc *rc, struct uwb_dev *uwb_dev) | ||
353 | { | ||
354 | struct uwb_rsv *rsv; | ||
355 | |||
356 | list_for_each_entry(rsv, &rc->reservations, rc_node) { | ||
357 | if (rsv->owner == uwb_dev | ||
358 | || (rsv->target.type == UWB_RSV_TARGET_DEV && rsv->target.dev == uwb_dev)) | ||
359 | uwb_rsv_remove(rsv); | ||
360 | } | ||
361 | } | ||
362 | |||
363 | |||
364 | /** | ||
365 | * uwbd_evt_handle_rc_drp - handle a DRP_IE event | ||
366 | * @evt: the DRP_IE event from the radio controller | ||
367 | * | ||
368 | * This processes DRP notifications from the radio controller, either | ||
369 | * initiating a new reservation or transitioning an existing | ||
370 | * reservation into a different state. | ||
371 | * | ||
372 | * DRP notifications can occur for three different reasons: | ||
373 | * | ||
374 | * - UWB_DRP_NOTIF_DRP_IE_RECVD: one or more DRP IEs with the RC as | ||
375 | * the target or source have been recieved. | ||
376 | * | ||
377 | * These DRP IEs could be new or for an existing reservation. | ||
378 | * | ||
379 | * If the DRP IE for an existing reservation ceases to be to | ||
380 | * recieved for at least mMaxLostBeacons, the reservation should be | ||
381 | * considered to be terminated. Note that the TERMINATE reason (see | ||
382 | * below) may not always be signalled (e.g., the remote device has | ||
383 | * two or more reservations established with the RC). | ||
384 | * | ||
385 | * - UWB_DRP_NOTIF_CONFLICT: DRP IEs from any device in the beacon | ||
386 | * group conflict with the RC's reservations. | ||
387 | * | ||
388 | * - UWB_DRP_NOTIF_TERMINATE: DRP IEs are no longer being received | ||
389 | * from a device (i.e., it's terminated all reservations). | ||
390 | * | ||
391 | * Only the software state of the reservations is changed; the setting | ||
392 | * of the radio controller's DRP IEs is done after all the events in | ||
393 | * an event buffer are processed. This saves waiting multiple times | ||
394 | * for the SET_DRP_IE command to complete. | ||
395 | */ | ||
396 | int uwbd_evt_handle_rc_drp(struct uwb_event *evt) | ||
397 | { | ||
398 | struct device *dev = &evt->rc->uwb_dev.dev; | ||
399 | struct uwb_rc *rc = evt->rc; | ||
400 | struct uwb_rc_evt_drp *drp_evt; | ||
401 | size_t ielength, bytes_left; | ||
402 | struct uwb_dev_addr src_addr; | ||
403 | struct uwb_dev *src_dev; | ||
404 | int reason; | ||
405 | |||
406 | /* Is there enough data to decode the event (and any IEs in | ||
407 | its payload)? */ | ||
408 | if (evt->notif.size < sizeof(*drp_evt)) { | ||
409 | dev_err(dev, "DRP event: Not enough data to decode event " | ||
410 | "[%zu bytes left, %zu needed]\n", | ||
411 | evt->notif.size, sizeof(*drp_evt)); | ||
412 | return 0; | ||
413 | } | ||
414 | bytes_left = evt->notif.size - sizeof(*drp_evt); | ||
415 | drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp, rceb); | ||
416 | ielength = le16_to_cpu(drp_evt->ie_length); | ||
417 | if (bytes_left != ielength) { | ||
418 | dev_err(dev, "DRP event: Not enough data in payload [%zu" | ||
419 | "bytes left, %zu declared in the event]\n", | ||
420 | bytes_left, ielength); | ||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | memcpy(src_addr.data, &drp_evt->src_addr, sizeof(src_addr)); | ||
425 | src_dev = uwb_dev_get_by_devaddr(rc, &src_addr); | ||
426 | if (!src_dev) { | ||
427 | /* | ||
428 | * A DRP notification from an unrecognized device. | ||
429 | * | ||
430 | * This is probably from a WUSB device that doesn't | ||
431 | * have an EUI-48 and therefore doesn't show up in the | ||
432 | * UWB device database. It's safe to simply ignore | ||
433 | * these. | ||
434 | */ | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | mutex_lock(&rc->rsvs_mutex); | ||
439 | |||
440 | reason = uwb_rc_evt_drp_reason(drp_evt); | ||
441 | |||
442 | switch (reason) { | ||
443 | case UWB_DRP_NOTIF_DRP_IE_RCVD: | ||
444 | uwb_drp_process_all(rc, drp_evt, ielength, src_dev); | ||
445 | break; | ||
446 | case UWB_DRP_NOTIF_CONFLICT: | ||
447 | uwb_drp_process_conflict_all(rc, drp_evt, ielength, src_dev); | ||
448 | break; | ||
449 | case UWB_DRP_NOTIF_TERMINATE: | ||
450 | uwb_drp_terminate_all(rc, src_dev); | ||
451 | break; | ||
452 | default: | ||
453 | dev_warn(dev, "ignored DRP event with reason code: %d\n", reason); | ||
454 | break; | ||
455 | } | ||
456 | |||
457 | mutex_unlock(&rc->rsvs_mutex); | ||
458 | |||
459 | uwb_dev_put(src_dev); | ||
460 | return 0; | ||
461 | } | ||
diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c new file mode 100644 index 000000000000..bae16204576d --- /dev/null +++ b/drivers/uwb/rsv.c | |||
@@ -0,0 +1,680 @@ | |||
1 | /* | ||
2 | * UWB reservation management. | ||
3 | * | ||
4 | * Copyright (C) 2008 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/version.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/uwb.h> | ||
21 | |||
22 | #include "uwb-internal.h" | ||
23 | |||
24 | static void uwb_rsv_timer(unsigned long arg); | ||
25 | |||
26 | static const char *rsv_states[] = { | ||
27 | [UWB_RSV_STATE_NONE] = "none", | ||
28 | [UWB_RSV_STATE_O_INITIATED] = "initiated", | ||
29 | [UWB_RSV_STATE_O_PENDING] = "pending", | ||
30 | [UWB_RSV_STATE_O_MODIFIED] = "modified", | ||
31 | [UWB_RSV_STATE_O_ESTABLISHED] = "established", | ||
32 | [UWB_RSV_STATE_T_ACCEPTED] = "accepted", | ||
33 | [UWB_RSV_STATE_T_DENIED] = "denied", | ||
34 | [UWB_RSV_STATE_T_PENDING] = "pending", | ||
35 | }; | ||
36 | |||
37 | static const char *rsv_types[] = { | ||
38 | [UWB_DRP_TYPE_ALIEN_BP] = "alien-bp", | ||
39 | [UWB_DRP_TYPE_HARD] = "hard", | ||
40 | [UWB_DRP_TYPE_SOFT] = "soft", | ||
41 | [UWB_DRP_TYPE_PRIVATE] = "private", | ||
42 | [UWB_DRP_TYPE_PCA] = "pca", | ||
43 | }; | ||
44 | |||
45 | /** | ||
46 | * uwb_rsv_state_str - return a string for a reservation state | ||
47 | * @state: the reservation state. | ||
48 | */ | ||
49 | const char *uwb_rsv_state_str(enum uwb_rsv_state state) | ||
50 | { | ||
51 | if (state < UWB_RSV_STATE_NONE || state >= UWB_RSV_STATE_LAST) | ||
52 | return "unknown"; | ||
53 | return rsv_states[state]; | ||
54 | } | ||
55 | EXPORT_SYMBOL_GPL(uwb_rsv_state_str); | ||
56 | |||
57 | /** | ||
58 | * uwb_rsv_type_str - return a string for a reservation type | ||
59 | * @type: the reservation type | ||
60 | */ | ||
61 | const char *uwb_rsv_type_str(enum uwb_drp_type type) | ||
62 | { | ||
63 | if (type < UWB_DRP_TYPE_ALIEN_BP || type > UWB_DRP_TYPE_PCA) | ||
64 | return "invalid"; | ||
65 | return rsv_types[type]; | ||
66 | } | ||
67 | EXPORT_SYMBOL_GPL(uwb_rsv_type_str); | ||
68 | |||
69 | static void uwb_rsv_dump(struct uwb_rsv *rsv) | ||
70 | { | ||
71 | struct device *dev = &rsv->rc->uwb_dev.dev; | ||
72 | struct uwb_dev_addr devaddr; | ||
73 | char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE]; | ||
74 | |||
75 | uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr); | ||
76 | if (rsv->target.type == UWB_RSV_TARGET_DEV) | ||
77 | devaddr = rsv->target.dev->dev_addr; | ||
78 | else | ||
79 | devaddr = rsv->target.devaddr; | ||
80 | uwb_dev_addr_print(target, sizeof(target), &devaddr); | ||
81 | |||
82 | dev_dbg(dev, "rsv %s -> %s: %s\n", owner, target, uwb_rsv_state_str(rsv->state)); | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * Get a free stream index for a reservation. | ||
87 | * | ||
88 | * If the target is a DevAddr (e.g., a WUSB cluster reservation) then | ||
89 | * the stream is allocated from a pool of per-RC stream indexes, | ||
90 | * otherwise a unique stream index for the target is selected. | ||
91 | */ | ||
92 | static int uwb_rsv_get_stream(struct uwb_rsv *rsv) | ||
93 | { | ||
94 | struct uwb_rc *rc = rsv->rc; | ||
95 | unsigned long *streams_bm; | ||
96 | int stream; | ||
97 | |||
98 | switch (rsv->target.type) { | ||
99 | case UWB_RSV_TARGET_DEV: | ||
100 | streams_bm = rsv->target.dev->streams; | ||
101 | break; | ||
102 | case UWB_RSV_TARGET_DEVADDR: | ||
103 | streams_bm = rc->uwb_dev.streams; | ||
104 | break; | ||
105 | default: | ||
106 | return -EINVAL; | ||
107 | } | ||
108 | |||
109 | stream = find_first_zero_bit(streams_bm, UWB_NUM_STREAMS); | ||
110 | if (stream >= UWB_NUM_STREAMS) | ||
111 | return -EBUSY; | ||
112 | |||
113 | rsv->stream = stream; | ||
114 | set_bit(stream, streams_bm); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static void uwb_rsv_put_stream(struct uwb_rsv *rsv) | ||
120 | { | ||
121 | struct uwb_rc *rc = rsv->rc; | ||
122 | unsigned long *streams_bm; | ||
123 | |||
124 | switch (rsv->target.type) { | ||
125 | case UWB_RSV_TARGET_DEV: | ||
126 | streams_bm = rsv->target.dev->streams; | ||
127 | break; | ||
128 | case UWB_RSV_TARGET_DEVADDR: | ||
129 | streams_bm = rc->uwb_dev.streams; | ||
130 | break; | ||
131 | default: | ||
132 | return; | ||
133 | } | ||
134 | |||
135 | clear_bit(rsv->stream, streams_bm); | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * Generate a MAS allocation with a single row component. | ||
140 | */ | ||
141 | static void uwb_rsv_gen_alloc_row(struct uwb_mas_bm *mas, | ||
142 | int first_mas, int mas_per_zone, | ||
143 | int zs, int ze) | ||
144 | { | ||
145 | struct uwb_mas_bm col; | ||
146 | int z; | ||
147 | |||
148 | bitmap_zero(mas->bm, UWB_NUM_MAS); | ||
149 | bitmap_zero(col.bm, UWB_NUM_MAS); | ||
150 | bitmap_fill(col.bm, mas_per_zone); | ||
151 | bitmap_shift_left(col.bm, col.bm, first_mas + zs * UWB_MAS_PER_ZONE, UWB_NUM_MAS); | ||
152 | |||
153 | for (z = zs; z <= ze; z++) { | ||
154 | bitmap_or(mas->bm, mas->bm, col.bm, UWB_NUM_MAS); | ||
155 | bitmap_shift_left(col.bm, col.bm, UWB_MAS_PER_ZONE, UWB_NUM_MAS); | ||
156 | } | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | * Allocate some MAS for this reservation based on current local | ||
161 | * availability, the reservation parameters (max_mas, min_mas, | ||
162 | * sparsity), and the WiMedia rules for MAS allocations. | ||
163 | * | ||
164 | * Returns -EBUSY is insufficient free MAS are available. | ||
165 | * | ||
166 | * FIXME: to simplify this, only safe reservations with a single row | ||
167 | * component in zones 1 to 15 are tried (zone 0 is skipped to avoid | ||
168 | * problems with the MAS reserved for the BP). | ||
169 | * | ||
170 | * [ECMA-368] section B.2. | ||
171 | */ | ||
172 | static int uwb_rsv_alloc_mas(struct uwb_rsv *rsv) | ||
173 | { | ||
174 | static const int safe_mas_in_row[UWB_NUM_ZONES] = { | ||
175 | 8, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, | ||
176 | }; | ||
177 | int n, r; | ||
178 | struct uwb_mas_bm mas; | ||
179 | bool found = false; | ||
180 | |||
181 | /* | ||
182 | * Search all valid safe allocations until either: too few MAS | ||
183 | * are available; or the smallest allocation with sufficient | ||
184 | * MAS is found. | ||
185 | * | ||
186 | * The top of the zones are preferred, so space for larger | ||
187 | * allocations is available in the bottom of the zone (e.g., a | ||
188 | * 15 MAS allocation should start in row 14 leaving space for | ||
189 | * a 120 MAS allocation at row 0). | ||
190 | */ | ||
191 | for (n = safe_mas_in_row[0]; n >= 1; n--) { | ||
192 | int num_mas; | ||
193 | |||
194 | num_mas = n * (UWB_NUM_ZONES - 1); | ||
195 | if (num_mas < rsv->min_mas) | ||
196 | break; | ||
197 | if (found && num_mas < rsv->max_mas) | ||
198 | break; | ||
199 | |||
200 | for (r = UWB_MAS_PER_ZONE-1; r >= 0; r--) { | ||
201 | if (safe_mas_in_row[r] < n) | ||
202 | continue; | ||
203 | uwb_rsv_gen_alloc_row(&mas, r, n, 1, UWB_NUM_ZONES); | ||
204 | if (uwb_drp_avail_reserve_pending(rsv->rc, &mas) == 0) { | ||
205 | found = true; | ||
206 | break; | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | |||
211 | if (!found) | ||
212 | return -EBUSY; | ||
213 | |||
214 | bitmap_copy(rsv->mas.bm, mas.bm, UWB_NUM_MAS); | ||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static void uwb_rsv_stroke_timer(struct uwb_rsv *rsv) | ||
219 | { | ||
220 | int sframes = UWB_MAX_LOST_BEACONS; | ||
221 | |||
222 | /* | ||
223 | * Multicast reservations can become established within 1 | ||
224 | * super frame and should not be terminated if no response is | ||
225 | * received. | ||
226 | */ | ||
227 | if (rsv->is_multicast) { | ||
228 | if (rsv->state == UWB_RSV_STATE_O_INITIATED) | ||
229 | sframes = 1; | ||
230 | if (rsv->state == UWB_RSV_STATE_O_ESTABLISHED) | ||
231 | sframes = 0; | ||
232 | } | ||
233 | |||
234 | rsv->expired = false; | ||
235 | if (sframes > 0) { | ||
236 | /* | ||
237 | * Add an additional 2 superframes to account for the | ||
238 | * time to send the SET DRP IE command. | ||
239 | */ | ||
240 | unsigned timeout_us = (sframes + 2) * UWB_SUPERFRAME_LENGTH_US; | ||
241 | mod_timer(&rsv->timer, jiffies + usecs_to_jiffies(timeout_us)); | ||
242 | } else | ||
243 | del_timer(&rsv->timer); | ||
244 | } | ||
245 | |||
246 | /* | ||
247 | * Update a reservations state, and schedule an update of the | ||
248 | * transmitted DRP IEs. | ||
249 | */ | ||
250 | static void uwb_rsv_state_update(struct uwb_rsv *rsv, | ||
251 | enum uwb_rsv_state new_state) | ||
252 | { | ||
253 | rsv->state = new_state; | ||
254 | rsv->ie_valid = false; | ||
255 | |||
256 | uwb_rsv_dump(rsv); | ||
257 | |||
258 | uwb_rsv_stroke_timer(rsv); | ||
259 | uwb_rsv_sched_update(rsv->rc); | ||
260 | } | ||
261 | |||
262 | static void uwb_rsv_callback(struct uwb_rsv *rsv) | ||
263 | { | ||
264 | if (rsv->callback) | ||
265 | rsv->callback(rsv); | ||
266 | } | ||
267 | |||
268 | void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state) | ||
269 | { | ||
270 | if (rsv->state == new_state) { | ||
271 | switch (rsv->state) { | ||
272 | case UWB_RSV_STATE_O_ESTABLISHED: | ||
273 | case UWB_RSV_STATE_T_ACCEPTED: | ||
274 | case UWB_RSV_STATE_NONE: | ||
275 | uwb_rsv_stroke_timer(rsv); | ||
276 | break; | ||
277 | default: | ||
278 | /* Expecting a state transition so leave timer | ||
279 | as-is. */ | ||
280 | break; | ||
281 | } | ||
282 | return; | ||
283 | } | ||
284 | |||
285 | switch (new_state) { | ||
286 | case UWB_RSV_STATE_NONE: | ||
287 | uwb_drp_avail_release(rsv->rc, &rsv->mas); | ||
288 | uwb_rsv_put_stream(rsv); | ||
289 | uwb_rsv_state_update(rsv, UWB_RSV_STATE_NONE); | ||
290 | uwb_rsv_callback(rsv); | ||
291 | break; | ||
292 | case UWB_RSV_STATE_O_INITIATED: | ||
293 | uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_INITIATED); | ||
294 | break; | ||
295 | case UWB_RSV_STATE_O_PENDING: | ||
296 | uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_PENDING); | ||
297 | break; | ||
298 | case UWB_RSV_STATE_O_ESTABLISHED: | ||
299 | uwb_drp_avail_reserve(rsv->rc, &rsv->mas); | ||
300 | uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_ESTABLISHED); | ||
301 | uwb_rsv_callback(rsv); | ||
302 | break; | ||
303 | case UWB_RSV_STATE_T_ACCEPTED: | ||
304 | uwb_drp_avail_reserve(rsv->rc, &rsv->mas); | ||
305 | uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_ACCEPTED); | ||
306 | uwb_rsv_callback(rsv); | ||
307 | break; | ||
308 | case UWB_RSV_STATE_T_DENIED: | ||
309 | uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_DENIED); | ||
310 | break; | ||
311 | default: | ||
312 | dev_err(&rsv->rc->uwb_dev.dev, "unhandled state: %s (%d)\n", | ||
313 | uwb_rsv_state_str(new_state), new_state); | ||
314 | } | ||
315 | } | ||
316 | |||
317 | static struct uwb_rsv *uwb_rsv_alloc(struct uwb_rc *rc) | ||
318 | { | ||
319 | struct uwb_rsv *rsv; | ||
320 | |||
321 | rsv = kzalloc(sizeof(struct uwb_rsv), GFP_KERNEL); | ||
322 | if (!rsv) | ||
323 | return NULL; | ||
324 | |||
325 | INIT_LIST_HEAD(&rsv->rc_node); | ||
326 | INIT_LIST_HEAD(&rsv->pal_node); | ||
327 | init_timer(&rsv->timer); | ||
328 | rsv->timer.function = uwb_rsv_timer; | ||
329 | rsv->timer.data = (unsigned long)rsv; | ||
330 | |||
331 | rsv->rc = rc; | ||
332 | |||
333 | return rsv; | ||
334 | } | ||
335 | |||
336 | static void uwb_rsv_free(struct uwb_rsv *rsv) | ||
337 | { | ||
338 | uwb_dev_put(rsv->owner); | ||
339 | if (rsv->target.type == UWB_RSV_TARGET_DEV) | ||
340 | uwb_dev_put(rsv->target.dev); | ||
341 | kfree(rsv); | ||
342 | } | ||
343 | |||
344 | /** | ||
345 | * uwb_rsv_create - allocate and initialize a UWB reservation structure | ||
346 | * @rc: the radio controller | ||
347 | * @cb: callback to use when the reservation completes or terminates | ||
348 | * @pal_priv: data private to the PAL to be passed in the callback | ||
349 | * | ||
350 | * The callback is called when the state of the reservation changes from: | ||
351 | * | ||
352 | * - pending to accepted | ||
353 | * - pending to denined | ||
354 | * - accepted to terminated | ||
355 | * - pending to terminated | ||
356 | */ | ||
357 | struct uwb_rsv *uwb_rsv_create(struct uwb_rc *rc, uwb_rsv_cb_f cb, void *pal_priv) | ||
358 | { | ||
359 | struct uwb_rsv *rsv; | ||
360 | |||
361 | rsv = uwb_rsv_alloc(rc); | ||
362 | if (!rsv) | ||
363 | return NULL; | ||
364 | |||
365 | rsv->callback = cb; | ||
366 | rsv->pal_priv = pal_priv; | ||
367 | |||
368 | return rsv; | ||
369 | } | ||
370 | EXPORT_SYMBOL_GPL(uwb_rsv_create); | ||
371 | |||
372 | void uwb_rsv_remove(struct uwb_rsv *rsv) | ||
373 | { | ||
374 | if (rsv->state != UWB_RSV_STATE_NONE) | ||
375 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); | ||
376 | del_timer_sync(&rsv->timer); | ||
377 | list_del(&rsv->rc_node); | ||
378 | uwb_rsv_free(rsv); | ||
379 | } | ||
380 | |||
381 | /** | ||
382 | * uwb_rsv_destroy - free a UWB reservation structure | ||
383 | * @rsv: the reservation to free | ||
384 | * | ||
385 | * The reservation will be terminated if it is pending or established. | ||
386 | */ | ||
387 | void uwb_rsv_destroy(struct uwb_rsv *rsv) | ||
388 | { | ||
389 | struct uwb_rc *rc = rsv->rc; | ||
390 | |||
391 | mutex_lock(&rc->rsvs_mutex); | ||
392 | uwb_rsv_remove(rsv); | ||
393 | mutex_unlock(&rc->rsvs_mutex); | ||
394 | } | ||
395 | EXPORT_SYMBOL_GPL(uwb_rsv_destroy); | ||
396 | |||
397 | /** | ||
398 | * usb_rsv_establish - start a reservation establishment | ||
399 | * @rsv: the reservation | ||
400 | * | ||
401 | * The PAL should fill in @rsv's owner, target, type, max_mas, | ||
402 | * min_mas, sparsity and is_multicast fields. If the target is a | ||
403 | * uwb_dev it must be referenced. | ||
404 | * | ||
405 | * The reservation's callback will be called when the reservation is | ||
406 | * accepted, denied or times out. | ||
407 | */ | ||
408 | int uwb_rsv_establish(struct uwb_rsv *rsv) | ||
409 | { | ||
410 | struct uwb_rc *rc = rsv->rc; | ||
411 | int ret; | ||
412 | |||
413 | mutex_lock(&rc->rsvs_mutex); | ||
414 | |||
415 | ret = uwb_rsv_get_stream(rsv); | ||
416 | if (ret) | ||
417 | goto out; | ||
418 | |||
419 | ret = uwb_rsv_alloc_mas(rsv); | ||
420 | if (ret) { | ||
421 | uwb_rsv_put_stream(rsv); | ||
422 | goto out; | ||
423 | } | ||
424 | |||
425 | list_add_tail(&rsv->rc_node, &rc->reservations); | ||
426 | rsv->owner = &rc->uwb_dev; | ||
427 | uwb_dev_get(rsv->owner); | ||
428 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_INITIATED); | ||
429 | out: | ||
430 | mutex_unlock(&rc->rsvs_mutex); | ||
431 | return ret; | ||
432 | } | ||
433 | EXPORT_SYMBOL_GPL(uwb_rsv_establish); | ||
434 | |||
435 | /** | ||
436 | * uwb_rsv_modify - modify an already established reservation | ||
437 | * @rsv: the reservation to modify | ||
438 | * @max_mas: new maximum MAS to reserve | ||
439 | * @min_mas: new minimum MAS to reserve | ||
440 | * @sparsity: new sparsity to use | ||
441 | * | ||
442 | * FIXME: implement this once there are PALs that use it. | ||
443 | */ | ||
444 | int uwb_rsv_modify(struct uwb_rsv *rsv, int max_mas, int min_mas, int sparsity) | ||
445 | { | ||
446 | return -ENOSYS; | ||
447 | } | ||
448 | EXPORT_SYMBOL_GPL(uwb_rsv_modify); | ||
449 | |||
450 | /** | ||
451 | * uwb_rsv_terminate - terminate an established reservation | ||
452 | * @rsv: the reservation to terminate | ||
453 | * | ||
454 | * A reservation is terminated by removing the DRP IE from the beacon, | ||
455 | * the other end will consider the reservation to be terminated when | ||
456 | * it does not see the DRP IE for at least mMaxLostBeacons. | ||
457 | * | ||
458 | * If applicable, the reference to the target uwb_dev will be released. | ||
459 | */ | ||
460 | void uwb_rsv_terminate(struct uwb_rsv *rsv) | ||
461 | { | ||
462 | struct uwb_rc *rc = rsv->rc; | ||
463 | |||
464 | mutex_lock(&rc->rsvs_mutex); | ||
465 | |||
466 | uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); | ||
467 | |||
468 | mutex_unlock(&rc->rsvs_mutex); | ||
469 | } | ||
470 | EXPORT_SYMBOL_GPL(uwb_rsv_terminate); | ||
471 | |||
472 | /** | ||
473 | * uwb_rsv_accept - accept a new reservation from a peer | ||
474 | * @rsv: the reservation | ||
475 | * @cb: call back for reservation changes | ||
476 | * @pal_priv: data to be passed in the above call back | ||
477 | * | ||
478 | * Reservation requests from peers are denied unless a PAL accepts it | ||
479 | * by calling this function. | ||
480 | */ | ||
481 | void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv) | ||
482 | { | ||
483 | rsv->callback = cb; | ||
484 | rsv->pal_priv = pal_priv; | ||
485 | rsv->state = UWB_RSV_STATE_T_ACCEPTED; | ||
486 | } | ||
487 | EXPORT_SYMBOL_GPL(uwb_rsv_accept); | ||
488 | |||
489 | /* | ||
490 | * Is a received DRP IE for this reservation? | ||
491 | */ | ||
492 | static bool uwb_rsv_match(struct uwb_rsv *rsv, struct uwb_dev *src, | ||
493 | struct uwb_ie_drp *drp_ie) | ||
494 | { | ||
495 | struct uwb_dev_addr *rsv_src; | ||
496 | int stream; | ||
497 | |||
498 | stream = uwb_ie_drp_stream_index(drp_ie); | ||
499 | |||
500 | if (rsv->stream != stream) | ||
501 | return false; | ||
502 | |||
503 | switch (rsv->target.type) { | ||
504 | case UWB_RSV_TARGET_DEVADDR: | ||
505 | return rsv->stream == stream; | ||
506 | case UWB_RSV_TARGET_DEV: | ||
507 | if (uwb_ie_drp_owner(drp_ie)) | ||
508 | rsv_src = &rsv->owner->dev_addr; | ||
509 | else | ||
510 | rsv_src = &rsv->target.dev->dev_addr; | ||
511 | return uwb_dev_addr_cmp(&src->dev_addr, rsv_src) == 0; | ||
512 | } | ||
513 | return false; | ||
514 | } | ||
515 | |||
516 | static struct uwb_rsv *uwb_rsv_new_target(struct uwb_rc *rc, | ||
517 | struct uwb_dev *src, | ||
518 | struct uwb_ie_drp *drp_ie) | ||
519 | { | ||
520 | struct uwb_rsv *rsv; | ||
521 | struct uwb_pal *pal; | ||
522 | enum uwb_rsv_state state; | ||
523 | |||
524 | rsv = uwb_rsv_alloc(rc); | ||
525 | if (!rsv) | ||
526 | return NULL; | ||
527 | |||
528 | rsv->rc = rc; | ||
529 | rsv->owner = src; | ||
530 | uwb_dev_get(rsv->owner); | ||
531 | rsv->target.type = UWB_RSV_TARGET_DEV; | ||
532 | rsv->target.dev = &rc->uwb_dev; | ||
533 | rsv->type = uwb_ie_drp_type(drp_ie); | ||
534 | rsv->stream = uwb_ie_drp_stream_index(drp_ie); | ||
535 | set_bit(rsv->stream, rsv->owner->streams); | ||
536 | uwb_drp_ie_to_bm(&rsv->mas, drp_ie); | ||
537 | |||
538 | /* | ||
539 | * See if any PALs are interested in this reservation. If not, | ||
540 | * deny the request. | ||
541 | */ | ||
542 | rsv->state = UWB_RSV_STATE_T_DENIED; | ||
543 | spin_lock(&rc->pal_lock); | ||
544 | list_for_each_entry(pal, &rc->pals, node) { | ||
545 | if (pal->new_rsv) | ||
546 | pal->new_rsv(rsv); | ||
547 | if (rsv->state == UWB_RSV_STATE_T_ACCEPTED) | ||
548 | break; | ||
549 | } | ||
550 | spin_unlock(&rc->pal_lock); | ||
551 | |||
552 | list_add_tail(&rsv->rc_node, &rc->reservations); | ||
553 | state = rsv->state; | ||
554 | rsv->state = UWB_RSV_STATE_NONE; | ||
555 | uwb_rsv_set_state(rsv, state); | ||
556 | |||
557 | return rsv; | ||
558 | } | ||
559 | |||
560 | /** | ||
561 | * uwb_rsv_find - find a reservation for a received DRP IE. | ||
562 | * @rc: the radio controller | ||
563 | * @src: source of the DRP IE | ||
564 | * @drp_ie: the DRP IE | ||
565 | * | ||
566 | * If the reservation cannot be found and the DRP IE is from a peer | ||
567 | * attempting to establish a new reservation, create a new reservation | ||
568 | * and add it to the list. | ||
569 | */ | ||
570 | struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src, | ||
571 | struct uwb_ie_drp *drp_ie) | ||
572 | { | ||
573 | struct uwb_rsv *rsv; | ||
574 | |||
575 | list_for_each_entry(rsv, &rc->reservations, rc_node) { | ||
576 | if (uwb_rsv_match(rsv, src, drp_ie)) | ||
577 | return rsv; | ||
578 | } | ||
579 | |||
580 | if (uwb_ie_drp_owner(drp_ie)) | ||
581 | return uwb_rsv_new_target(rc, src, drp_ie); | ||
582 | |||
583 | return NULL; | ||
584 | } | ||
585 | |||
586 | /* | ||
587 | * Go through all the reservations and check for timeouts and (if | ||
588 | * necessary) update their DRP IEs. | ||
589 | * | ||
590 | * FIXME: look at building the SET_DRP_IE command here rather than | ||
591 | * having to rescan the list in uwb_rc_send_all_drp_ie(). | ||
592 | */ | ||
593 | static bool uwb_rsv_update_all(struct uwb_rc *rc) | ||
594 | { | ||
595 | struct uwb_rsv *rsv, *t; | ||
596 | bool ie_updated = false; | ||
597 | |||
598 | list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) { | ||
599 | if (rsv->expired) | ||
600 | uwb_drp_handle_timeout(rsv); | ||
601 | if (!rsv->ie_valid) { | ||
602 | uwb_drp_ie_update(rsv); | ||
603 | ie_updated = true; | ||
604 | } | ||
605 | } | ||
606 | |||
607 | return ie_updated; | ||
608 | } | ||
609 | |||
610 | void uwb_rsv_sched_update(struct uwb_rc *rc) | ||
611 | { | ||
612 | queue_work(rc->rsv_workq, &rc->rsv_update_work); | ||
613 | } | ||
614 | |||
615 | /* | ||
616 | * Update DRP IEs and, if necessary, the DRP Availability IE and send | ||
617 | * the updated IEs to the radio controller. | ||
618 | */ | ||
619 | static void uwb_rsv_update_work(struct work_struct *work) | ||
620 | { | ||
621 | struct uwb_rc *rc = container_of(work, struct uwb_rc, rsv_update_work); | ||
622 | bool ie_updated; | ||
623 | |||
624 | mutex_lock(&rc->rsvs_mutex); | ||
625 | |||
626 | ie_updated = uwb_rsv_update_all(rc); | ||
627 | |||
628 | if (!rc->drp_avail.ie_valid) { | ||
629 | uwb_drp_avail_ie_update(rc); | ||
630 | ie_updated = true; | ||
631 | } | ||
632 | |||
633 | if (ie_updated) | ||
634 | uwb_rc_send_all_drp_ie(rc); | ||
635 | |||
636 | mutex_unlock(&rc->rsvs_mutex); | ||
637 | } | ||
638 | |||
639 | static void uwb_rsv_timer(unsigned long arg) | ||
640 | { | ||
641 | struct uwb_rsv *rsv = (struct uwb_rsv *)arg; | ||
642 | |||
643 | rsv->expired = true; | ||
644 | uwb_rsv_sched_update(rsv->rc); | ||
645 | } | ||
646 | |||
647 | void uwb_rsv_init(struct uwb_rc *rc) | ||
648 | { | ||
649 | INIT_LIST_HEAD(&rc->reservations); | ||
650 | mutex_init(&rc->rsvs_mutex); | ||
651 | INIT_WORK(&rc->rsv_update_work, uwb_rsv_update_work); | ||
652 | |||
653 | bitmap_complement(rc->uwb_dev.streams, rc->uwb_dev.streams, UWB_NUM_STREAMS); | ||
654 | } | ||
655 | |||
656 | int uwb_rsv_setup(struct uwb_rc *rc) | ||
657 | { | ||
658 | char name[16]; | ||
659 | |||
660 | snprintf(name, sizeof(name), "%s_rsvd", dev_name(&rc->uwb_dev.dev)); | ||
661 | rc->rsv_workq = create_singlethread_workqueue(name); | ||
662 | if (rc->rsv_workq == NULL) | ||
663 | return -ENOMEM; | ||
664 | |||
665 | return 0; | ||
666 | } | ||
667 | |||
668 | void uwb_rsv_cleanup(struct uwb_rc *rc) | ||
669 | { | ||
670 | struct uwb_rsv *rsv, *t; | ||
671 | |||
672 | mutex_lock(&rc->rsvs_mutex); | ||
673 | list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) { | ||
674 | uwb_rsv_remove(rsv); | ||
675 | } | ||
676 | mutex_unlock(&rc->rsvs_mutex); | ||
677 | |||
678 | cancel_work_sync(&rc->rsv_update_work); | ||
679 | destroy_workqueue(rc->rsv_workq); | ||
680 | } | ||