aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@csr.com>2008-09-17 11:34:09 -0400
committerDavid Vrabel <dv02@dv02pc01.europe.root.pri>2008-09-17 11:54:24 -0400
commit8cc13a09474bb30d15dbf449767bb6d0198a8bf8 (patch)
tree2423388e0a7e9bca0c6e6f7edd5f492887d38160 /drivers
parent22d203ecef9b0cc1fa8d8f64c935b451ca7d1022 (diff)
uwb: add the UWB stack (reservation manager)
DRP and reservation management. Signed-off-by: David Vrabel <david.vrabel@csr.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/uwb/drp-avail.c288
-rw-r--r--drivers/uwb/drp-ie.c232
-rw-r--r--drivers/uwb/drp.c461
-rw-r--r--drivers/uwb/rsv.c680
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 00000000000..3febd855280
--- /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 */
49void 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 */
61static 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 */
74int 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 */
91void 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 */
103void 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 */
116void 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 */
139static
140unsigned 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 */
200static
201void 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 */
225static
226int 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;
242error:
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 */
270int 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 00000000000..882724c5f12
--- /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 */
34static 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 */
55static 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 */
105int 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 */
185static
186void 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 */
213void 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 00000000000..c0b1e5e2bd0
--- /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 */
46static
47int 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 }
101error_cmd:
102 kfree(cmd);
103error:
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 */
116int 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
126void 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 */
154static 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 */
201static 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 */
248static 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 */
283static
284void 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 */
323static
324void 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 */
352static 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 */
396int 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 00000000000..bae16204576
--- /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
24static void uwb_rsv_timer(unsigned long arg);
25
26static 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
37static 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 */
49const 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}
55EXPORT_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 */
61const 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}
67EXPORT_SYMBOL_GPL(uwb_rsv_type_str);
68
69static 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 */
92static 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
119static 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 */
141static 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 */
172static 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
218static 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 */
250static 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
262static void uwb_rsv_callback(struct uwb_rsv *rsv)
263{
264 if (rsv->callback)
265 rsv->callback(rsv);
266}
267
268void 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
317static 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
336static 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 */
357struct 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}
370EXPORT_SYMBOL_GPL(uwb_rsv_create);
371
372void 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 */
387void 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}
395EXPORT_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 */
408int 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);
429out:
430 mutex_unlock(&rc->rsvs_mutex);
431 return ret;
432}
433EXPORT_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 */
444int uwb_rsv_modify(struct uwb_rsv *rsv, int max_mas, int min_mas, int sparsity)
445{
446 return -ENOSYS;
447}
448EXPORT_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 */
460void 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}
470EXPORT_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 */
481void 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}
487EXPORT_SYMBOL_GPL(uwb_rsv_accept);
488
489/*
490 * Is a received DRP IE for this reservation?
491 */
492static 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
516static 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 */
570struct 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 */
593static 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
610void 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 */
619static 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
639static 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
647void 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
656int 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
668void 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}