1 // SPDX-License-Identifier: GPL-2.0
3 * Wireless Host Controller (WHC) WUSB operations.
5 * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
7 #include <linux/kernel.h>
8 #include <linux/uwb/umc.h>
10 #include "../../wusbcore/wusbhc.h"
14 static int whc_update_di(struct whc
*whc
, int idx
)
16 int offset
= idx
/ 32;
17 u32 bit
= 1 << (idx
% 32);
19 le_writel(bit
, whc
->base
+ WUSBDIBUPDATED
+ offset
);
21 return whci_wait_for(&whc
->umc
->dev
,
22 whc
->base
+ WUSBDIBUPDATED
+ offset
, bit
, 0,
27 * WHCI starts MMCs based on there being a valid GTK so these need
28 * only start/stop the asynchronous and periodic schedules and send a
29 * channel stop command.
32 int whc_wusbhc_start(struct wusbhc
*wusbhc
)
34 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
42 void whc_wusbhc_stop(struct wusbhc
*wusbhc
, int delay
)
44 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
45 u32 stop_time
, now_time
;
51 now_time
= le_readl(whc
->base
+ WUSBTIME
) & WUSBTIME_CHANNEL_TIME_MASK
;
52 stop_time
= (now_time
+ ((delay
* 8) << 7)) & 0x00ffffff;
53 ret
= whc_do_gencmd(whc
, WUSBGENCMDSTS_CHAN_STOP
, stop_time
, NULL
, 0);
58 int whc_mmcie_add(struct wusbhc
*wusbhc
, u8 interval
, u8 repeat_cnt
,
59 u8 handle
, struct wuie_hdr
*wuie
)
61 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
64 params
= (interval
<< 24)
66 | (wuie
->bLength
<< 8)
69 return whc_do_gencmd(whc
, WUSBGENCMDSTS_MMCIE_ADD
, params
, wuie
, wuie
->bLength
);
72 int whc_mmcie_rm(struct wusbhc
*wusbhc
, u8 handle
)
74 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
79 return whc_do_gencmd(whc
, WUSBGENCMDSTS_MMCIE_RM
, params
, NULL
, 0);
82 int whc_bwa_set(struct wusbhc
*wusbhc
, s8 stream_index
, const struct uwb_mas_bm
*mas_bm
)
84 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
86 if (stream_index
>= 0)
87 whc_write_wusbcmd(whc
, WUSBCMD_WUSBSI_MASK
, WUSBCMD_WUSBSI(stream_index
));
89 return whc_do_gencmd(whc
, WUSBGENCMDSTS_SET_MAS
, 0, (void *)mas_bm
, sizeof(*mas_bm
));
92 int whc_dev_info_set(struct wusbhc
*wusbhc
, struct wusb_dev
*wusb_dev
)
94 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
95 int idx
= wusb_dev
->port_idx
;
96 struct di_buf_entry
*di
= &whc
->di_buf
[idx
];
99 mutex_lock(&whc
->mutex
);
101 uwb_mas_bm_copy_le(di
->availability_info
, &wusb_dev
->availability
);
102 di
->addr_sec_info
&= ~(WHC_DI_DISABLE
| WHC_DI_DEV_ADDR_MASK
);
103 di
->addr_sec_info
|= WHC_DI_DEV_ADDR(wusb_dev
->addr
);
105 ret
= whc_update_di(whc
, idx
);
107 mutex_unlock(&whc
->mutex
);
113 * Set the number of Device Notification Time Slots (DNTS) and enable
114 * device notifications.
116 int whc_set_num_dnts(struct wusbhc
*wusbhc
, u8 interval
, u8 slots
)
118 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
121 dntsctrl
= WUSBDNTSCTRL_ACTIVE
122 | WUSBDNTSCTRL_INTERVAL(interval
)
123 | WUSBDNTSCTRL_SLOTS(slots
);
125 le_writel(dntsctrl
, whc
->base
+ WUSBDNTSCTRL
);
130 static int whc_set_key(struct whc
*whc
, u8 key_index
, uint32_t tkid
,
131 const void *key
, size_t key_size
, bool is_gtk
)
138 memcpy(seckey
, key
, key_size
);
139 setkeycmd
= WUSBSETSECKEYCMD_SET
| WUSBSETSECKEYCMD_IDX(key_index
);
141 setkeycmd
|= WUSBSETSECKEYCMD_GTK
;
143 le_writel(tkid
, whc
->base
+ WUSBTKID
);
144 for (i
= 0; i
< 4; i
++)
145 le_writel(seckey
[i
], whc
->base
+ WUSBSECKEY
+ 4*i
);
146 le_writel(setkeycmd
, whc
->base
+ WUSBSETSECKEYCMD
);
148 ret
= whci_wait_for(&whc
->umc
->dev
, whc
->base
+ WUSBSETSECKEYCMD
,
149 WUSBSETSECKEYCMD_SET
, 0, 100, "set key");
155 * whc_set_ptk - set the PTK to use for a device.
157 * The index into the key table for this PTK is the same as the
158 * device's port index.
160 int whc_set_ptk(struct wusbhc
*wusbhc
, u8 port_idx
, u32 tkid
,
161 const void *ptk
, size_t key_size
)
163 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
164 struct di_buf_entry
*di
= &whc
->di_buf
[port_idx
];
167 mutex_lock(&whc
->mutex
);
170 ret
= whc_set_key(whc
, port_idx
, tkid
, ptk
, key_size
, false);
174 di
->addr_sec_info
&= ~WHC_DI_KEY_IDX_MASK
;
175 di
->addr_sec_info
|= WHC_DI_SECURE
| WHC_DI_KEY_IDX(port_idx
);
177 di
->addr_sec_info
&= ~WHC_DI_SECURE
;
179 ret
= whc_update_di(whc
, port_idx
);
181 mutex_unlock(&whc
->mutex
);
186 * whc_set_gtk - set the GTK for subsequent broadcast packets
188 * The GTK is stored in the last entry in the key table (the previous
189 * N_DEVICES entries are for the per-device PTKs).
191 int whc_set_gtk(struct wusbhc
*wusbhc
, u32 tkid
,
192 const void *gtk
, size_t key_size
)
194 struct whc
*whc
= wusbhc_to_whc(wusbhc
);
197 mutex_lock(&whc
->mutex
);
199 ret
= whc_set_key(whc
, whc
->n_devices
, tkid
, gtk
, key_size
, true);
201 mutex_unlock(&whc
->mutex
);
206 int whc_set_cluster_id(struct whc
*whc
, u8 bcid
)
208 whc_write_wusbcmd(whc
, WUSBCMD_BCID_MASK
, WUSBCMD_BCID(bcid
));