2 * Wireless Host Controller (WHC) WUSB operations.
4 * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
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.
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.
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/>.
18 #include <linux/kernel.h>
19 #include <linux/init.h>
20 #include <linux/uwb/umc.h>
22 #include <linux/uwb/debug.h>
24 #include "../../wusbcore/wusbhc.h"
29 static void dump_di(struct whc
*whc
, int idx
)
31 struct di_buf_entry
*di
= &whc
->di_buf
[idx
];
32 struct device
*dev
= &whc
->umc
->dev
;
35 bitmap_scnprintf(buf
, sizeof(buf
), (unsigned long *)di
->availability_info
, UWB_NUM_MAS
);
37 d_printf(1, dev
, "DI[%d]\n", idx
);
38 d_printf(1, dev
, " availability: %s\n", buf
);
39 d_printf(1, dev
, " %c%c key idx: %d dev addr: %d\n",
40 (di
->addr_sec_info
& WHC_DI_SECURE
) ? 'S' : ' ',
41 (di
->addr_sec_info
& WHC_DI_DISABLE
) ? 'D' : ' ',
42 (di
->addr_sec_info
& WHC_DI_KEY_IDX_MASK
) >> 8,
43 (di
->addr_sec_info
& WHC_DI_DEV_ADDR_MASK
));
46 static inline void dump_di(struct whc
*whc
, int idx
)
51 static int whc_update_di(struct whc
*whc
, int idx
)
53 int offset
= idx
/ 32;
54 u32 bit
= 1 << (idx
% 32);
58 le_writel(bit
, whc
->base
+ WUSBDIBUPDATED
+ offset
);
60 return whci_wait_for(&whc
->umc
->dev
,
61 whc
->base
+ WUSBDIBUPDATED
+ offset
, bit
, 0,
66 * WHCI starts MMCs based on there being a valid GTK so these need
67 * only start/stop the asynchronous and periodic schedules and send a
68 * channel stop command.
71 int whc_wusbhc_start(struct wusbhc
*wusbhc
)
73 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
81 void whc_wusbhc_stop(struct wusbhc
*wusbhc
, int delay
)
83 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
84 u32 stop_time
, now_time
;
90 now_time
= le_readl(whc
->base
+ WUSBTIME
) & WUSBTIME_CHANNEL_TIME_MASK
;
91 stop_time
= (now_time
+ ((delay
* 8) << 7)) & 0x00ffffff;
92 ret
= whc_do_gencmd(whc
, WUSBGENCMDSTS_CHAN_STOP
, stop_time
, NULL
, 0);
97 int whc_mmcie_add(struct wusbhc
*wusbhc
, u8 interval
, u8 repeat_cnt
,
98 u8 handle
, struct wuie_hdr
*wuie
)
100 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
103 params
= (interval
<< 24)
105 | (wuie
->bLength
<< 8)
108 return whc_do_gencmd(whc
, WUSBGENCMDSTS_MMCIE_ADD
, params
, wuie
, wuie
->bLength
);
111 int whc_mmcie_rm(struct wusbhc
*wusbhc
, u8 handle
)
113 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
118 return whc_do_gencmd(whc
, WUSBGENCMDSTS_MMCIE_RM
, params
, NULL
, 0);
121 int whc_bwa_set(struct wusbhc
*wusbhc
, s8 stream_index
, const struct uwb_mas_bm
*mas_bm
)
123 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
125 if (stream_index
>= 0)
126 whc_write_wusbcmd(whc
, WUSBCMD_WUSBSI_MASK
, WUSBCMD_WUSBSI(stream_index
));
128 return whc_do_gencmd(whc
, WUSBGENCMDSTS_SET_MAS
, 0, (void *)mas_bm
, sizeof(*mas_bm
));
131 int whc_dev_info_set(struct wusbhc
*wusbhc
, struct wusb_dev
*wusb_dev
)
133 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
134 int idx
= wusb_dev
->port_idx
;
135 struct di_buf_entry
*di
= &whc
->di_buf
[idx
];
138 mutex_lock(&whc
->mutex
);
140 uwb_mas_bm_copy_le(di
->availability_info
, &wusb_dev
->availability
);
141 di
->addr_sec_info
&= ~(WHC_DI_DISABLE
| WHC_DI_DEV_ADDR_MASK
);
142 di
->addr_sec_info
|= WHC_DI_DEV_ADDR(wusb_dev
->addr
);
144 ret
= whc_update_di(whc
, idx
);
146 mutex_unlock(&whc
->mutex
);
152 * Set the number of Device Notification Time Slots (DNTS) and enable
153 * device notifications.
155 int whc_set_num_dnts(struct wusbhc
*wusbhc
, u8 interval
, u8 slots
)
157 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
160 dntsctrl
= WUSBDNTSCTRL_ACTIVE
161 | WUSBDNTSCTRL_INTERVAL(interval
)
162 | WUSBDNTSCTRL_SLOTS(slots
);
164 le_writel(dntsctrl
, whc
->base
+ WUSBDNTSCTRL
);
169 static int whc_set_key(struct whc
*whc
, u8 key_index
, uint32_t tkid
,
170 const void *key
, size_t key_size
, bool is_gtk
)
177 memcpy(seckey
, key
, key_size
);
178 setkeycmd
= WUSBSETSECKEYCMD_SET
| WUSBSETSECKEYCMD_IDX(key_index
);
180 setkeycmd
|= WUSBSETSECKEYCMD_GTK
;
182 le_writel(tkid
, whc
->base
+ WUSBTKID
);
183 for (i
= 0; i
< 4; i
++)
184 le_writel(seckey
[i
], whc
->base
+ WUSBSECKEY
+ 4*i
);
185 le_writel(setkeycmd
, whc
->base
+ WUSBSETSECKEYCMD
);
187 ret
= whci_wait_for(&whc
->umc
->dev
, whc
->base
+ WUSBSETSECKEYCMD
,
188 WUSBSETSECKEYCMD_SET
, 0, 100, "set key");
194 * whc_set_ptk - set the PTK to use for a device.
196 * The index into the key table for this PTK is the same as the
197 * device's port index.
199 int whc_set_ptk(struct wusbhc
*wusbhc
, u8 port_idx
, u32 tkid
,
200 const void *ptk
, size_t key_size
)
202 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
203 struct di_buf_entry
*di
= &whc
->di_buf
[port_idx
];
206 mutex_lock(&whc
->mutex
);
209 ret
= whc_set_key(whc
, port_idx
, tkid
, ptk
, key_size
, false);
213 di
->addr_sec_info
&= ~WHC_DI_KEY_IDX_MASK
;
214 di
->addr_sec_info
|= WHC_DI_SECURE
| WHC_DI_KEY_IDX(port_idx
);
216 di
->addr_sec_info
&= ~WHC_DI_SECURE
;
218 ret
= whc_update_di(whc
, port_idx
);
220 mutex_unlock(&whc
->mutex
);
225 * whc_set_gtk - set the GTK for subsequent broadcast packets
227 * The GTK is stored in the last entry in the key table (the previous
228 * N_DEVICES entries are for the per-device PTKs).
230 int whc_set_gtk(struct wusbhc
*wusbhc
, u32 tkid
,
231 const void *gtk
, size_t key_size
)
233 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
236 mutex_lock(&whc
->mutex
);
238 ret
= whc_set_key(whc
, whc
->n_devices
, tkid
, gtk
, key_size
, true);
240 mutex_unlock(&whc
->mutex
);
245 int whc_set_cluster_id(struct whc
*whc
, u8 bcid
)
247 whc_write_wusbcmd(whc
, WUSBCMD_BCID_MASK
, WUSBCMD_BCID(bcid
));