diff options
Diffstat (limited to 'drivers/uwb')
37 files changed, 0 insertions, 12047 deletions
diff --git a/drivers/uwb/Kconfig b/drivers/uwb/Kconfig deleted file mode 100644 index 259e053e1e09..000000000000 --- a/drivers/uwb/Kconfig +++ /dev/null @@ -1,72 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# UWB device configuration -# - -menuconfig UWB - tristate "Ultra Wideband devices" - default n - select GENERIC_NET_UTILS - help - UWB is a high-bandwidth, low-power, point-to-point radio - technology using a wide spectrum (3.1-10.6GHz). It is - optimized for in-room use (480Mbps at 2 meters, 110Mbps at - 10m). It serves as the transport layer for other protocols, - such as Wireless USB (WUSB). - - The topology is peer to peer; however, higher level - protocols (such as WUSB) might impose a master/slave - relationship. - - Say Y here if your computer has UWB radio controllers (USB or PCI) - based. You will need to enable the radio controllers - below. It is ok to select all of them, no harm done. - - For more help check the UWB and WUSB related files in - <file:Documentation/usb/>. - - To compile the UWB stack as a module, choose M here. - -if UWB - -config UWB_HWA - tristate "UWB Radio Control driver for WUSB-compliant USB dongles (HWA)" - depends on USB - help - This driver enables the radio controller for HWA USB - devices. HWA stands for Host Wire Adapter, and it is a UWB - Radio Controller connected to your system via USB. Most of - them come with a Wireless USB host controller also. - - To compile this driver select Y (built in) or M (module). It - is safe to select any even if you do not have the hardware. - -config UWB_WHCI - tristate "UWB Radio Control driver for WHCI-compliant cards" - depends on PCI - help - This driver enables the radio controller for WHCI cards. - - WHCI is a specification developed by Intel - (http://www.intel.com/technology/comms/wusb/whci.htm) much - in the spirit of USB's EHCI, but for UWB and Wireless USB - radio/host controllers connected via memory mapping (eg: - PCI). Most of these cards come also with a Wireless USB host - controller. - - To compile this driver select Y (built in) or M (module). It - is safe to select any even if you do not have the hardware. - -config UWB_I1480U - tristate "Support for Intel Wireless UWB Link 1480 HWA" - depends on UWB_HWA - select FW_LOADER - help - This driver enables support for the i1480 when connected via - USB. It consists of a firmware uploader that will enable it - to behave as an HWA device. - - To compile this driver select Y (built in) or M (module). It - is safe to select any even if you do not have the hardware. - -endif # UWB diff --git a/drivers/uwb/Makefile b/drivers/uwb/Makefile deleted file mode 100644 index 32f4de7afbd6..000000000000 --- a/drivers/uwb/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_UWB) += uwb.o -obj-$(CONFIG_UWB_WHCI) += umc.o whci.o whc-rc.o -obj-$(CONFIG_UWB_HWA) += hwa-rc.o -obj-$(CONFIG_UWB_I1480U) += i1480/ - -uwb-objs := \ - address.o \ - allocator.o \ - beacon.o \ - driver.o \ - drp.o \ - drp-avail.o \ - drp-ie.o \ - est.o \ - ie.o \ - ie-rcv.o \ - lc-dev.o \ - lc-rc.o \ - neh.o \ - pal.o \ - radio.o \ - reset.o \ - rsv.o \ - scan.o \ - uwb-debug.o \ - uwbd.o - -umc-objs := \ - umc-bus.o \ - umc-dev.o \ - umc-drv.o diff --git a/drivers/uwb/address.c b/drivers/uwb/address.c deleted file mode 100644 index 857d5cd56a95..000000000000 --- a/drivers/uwb/address.c +++ /dev/null @@ -1,352 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Ultra Wide Band - * Address management - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * FIXME: docs - */ - -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/random.h> -#include <linux/etherdevice.h> - -#include "uwb-internal.h" - - -/** Device Address Management command */ -struct uwb_rc_cmd_dev_addr_mgmt { - struct uwb_rccb rccb; - u8 bmOperationType; - u8 baAddr[6]; -} __attribute__((packed)); - - -/** - * Low level command for setting/getting UWB radio's addresses - * - * @hwarc: HWA Radio Control interface instance - * @bmOperationType: - * Set/get, MAC/DEV (see WUSB1.0[8.6.2.2]) - * @baAddr: address buffer--assumed to have enough data to hold - * the address type requested. - * @reply: Pointer to reply buffer (can be stack allocated) - * @returns: 0 if ok, < 0 errno code on error. - * - * @cmd has to be allocated because USB cannot grok USB or vmalloc - * buffers depending on your combination of host architecture. - */ -static -int uwb_rc_dev_addr_mgmt(struct uwb_rc *rc, - u8 bmOperationType, const u8 *baAddr, - struct uwb_rc_evt_dev_addr_mgmt *reply) -{ - int result; - struct uwb_rc_cmd_dev_addr_mgmt *cmd; - - result = -ENOMEM; - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - goto error_kzalloc; - cmd->rccb.bCommandType = UWB_RC_CET_GENERAL; - cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_DEV_ADDR_MGMT); - cmd->bmOperationType = bmOperationType; - if (baAddr) { - size_t size = 0; - switch (bmOperationType >> 1) { - case 0: size = 2; break; - case 1: size = 6; break; - default: BUG(); - } - memcpy(cmd->baAddr, baAddr, size); - } - reply->rceb.bEventType = UWB_RC_CET_GENERAL; - reply->rceb.wEvent = UWB_RC_CMD_DEV_ADDR_MGMT; - result = uwb_rc_cmd(rc, "DEV-ADDR-MGMT", - &cmd->rccb, sizeof(*cmd), - &reply->rceb, sizeof(*reply)); - if (result < 0) - goto error_cmd; - if (result < sizeof(*reply)) { - dev_err(&rc->uwb_dev.dev, - "DEV-ADDR-MGMT: not enough data replied: " - "%d vs %zu bytes needed\n", result, sizeof(*reply)); - result = -ENOMSG; - } else if (reply->bResultCode != UWB_RC_RES_SUCCESS) { - dev_err(&rc->uwb_dev.dev, - "DEV-ADDR-MGMT: command execution failed: %s (%d)\n", - uwb_rc_strerror(reply->bResultCode), - reply->bResultCode); - result = -EIO; - } else - result = 0; -error_cmd: - kfree(cmd); -error_kzalloc: - return result; -} - - -/** - * Set the UWB RC MAC or device address. - * - * @rc: UWB Radio Controller - * @_addr: Pointer to address to write [assumed to be either a - * 'struct uwb_mac_addr *' or a 'struct uwb_dev_addr *']. - * @type: Type of address to set (UWB_ADDR_DEV or UWB_ADDR_MAC). - * @returns: 0 if ok, < 0 errno code on error. - * - * Some anal retentivity here: even if both 'struct - * uwb_{dev,mac}_addr' have the actual byte array in the same offset - * and I could just pass _addr to hwarc_cmd_dev_addr_mgmt(), I prefer - * to use some syntatic sugar in case someday we decide to change the - * format of the structs. The compiler will optimize it out anyway. - */ -static int uwb_rc_addr_set(struct uwb_rc *rc, - const void *_addr, enum uwb_addr_type type) -{ - int result; - u8 bmOperationType = 0x1; /* Set address */ - const struct uwb_dev_addr *dev_addr = _addr; - const struct uwb_mac_addr *mac_addr = _addr; - struct uwb_rc_evt_dev_addr_mgmt reply; - const u8 *baAddr; - - result = -EINVAL; - switch (type) { - case UWB_ADDR_DEV: - baAddr = dev_addr->data; - break; - case UWB_ADDR_MAC: - baAddr = mac_addr->data; - bmOperationType |= 0x2; - break; - default: - return result; - } - return uwb_rc_dev_addr_mgmt(rc, bmOperationType, baAddr, &reply); -} - - -/** - * Get the UWB radio's MAC or device address. - * - * @rc: UWB Radio Controller - * @_addr: Where to write the address data [assumed to be either a - * 'struct uwb_mac_addr *' or a 'struct uwb_dev_addr *']. - * @type: Type of address to get (UWB_ADDR_DEV or UWB_ADDR_MAC). - * @returns: 0 if ok (and *_addr set), < 0 errno code on error. - * - * See comment in uwb_rc_addr_set() about anal retentivity in the - * type handling of the address variables. - */ -static int uwb_rc_addr_get(struct uwb_rc *rc, - void *_addr, enum uwb_addr_type type) -{ - int result; - u8 bmOperationType = 0x0; /* Get address */ - struct uwb_rc_evt_dev_addr_mgmt evt; - struct uwb_dev_addr *dev_addr = _addr; - struct uwb_mac_addr *mac_addr = _addr; - u8 *baAddr; - - result = -EINVAL; - switch (type) { - case UWB_ADDR_DEV: - baAddr = dev_addr->data; - break; - case UWB_ADDR_MAC: - bmOperationType |= 0x2; - baAddr = mac_addr->data; - break; - default: - return result; - } - result = uwb_rc_dev_addr_mgmt(rc, bmOperationType, baAddr, &evt); - if (result == 0) - switch (type) { - case UWB_ADDR_DEV: - memcpy(&dev_addr->data, evt.baAddr, - sizeof(dev_addr->data)); - break; - case UWB_ADDR_MAC: - memcpy(&mac_addr->data, evt.baAddr, - sizeof(mac_addr->data)); - break; - default: /* shut gcc up */ - BUG(); - } - return result; -} - - -/** Get @rc's MAC address to @addr */ -int uwb_rc_mac_addr_get(struct uwb_rc *rc, - struct uwb_mac_addr *addr) { - return uwb_rc_addr_get(rc, addr, UWB_ADDR_MAC); -} -EXPORT_SYMBOL_GPL(uwb_rc_mac_addr_get); - - -/** Get @rc's device address to @addr */ -int uwb_rc_dev_addr_get(struct uwb_rc *rc, - struct uwb_dev_addr *addr) { - return uwb_rc_addr_get(rc, addr, UWB_ADDR_DEV); -} -EXPORT_SYMBOL_GPL(uwb_rc_dev_addr_get); - - -/** Set @rc's address to @addr */ -int uwb_rc_mac_addr_set(struct uwb_rc *rc, - const struct uwb_mac_addr *addr) -{ - int result = -EINVAL; - mutex_lock(&rc->uwb_dev.mutex); - result = uwb_rc_addr_set(rc, addr, UWB_ADDR_MAC); - mutex_unlock(&rc->uwb_dev.mutex); - return result; -} - - -/** Set @rc's address to @addr */ -int uwb_rc_dev_addr_set(struct uwb_rc *rc, - const struct uwb_dev_addr *addr) -{ - int result = -EINVAL; - mutex_lock(&rc->uwb_dev.mutex); - result = uwb_rc_addr_set(rc, addr, UWB_ADDR_DEV); - rc->uwb_dev.dev_addr = *addr; - mutex_unlock(&rc->uwb_dev.mutex); - return result; -} - -/* Returns !0 if given address is already assigned to device. */ -int __uwb_mac_addr_assigned_check(struct device *dev, void *_addr) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - struct uwb_mac_addr *addr = _addr; - - if (!uwb_mac_addr_cmp(addr, &uwb_dev->mac_addr)) - return !0; - return 0; -} - -/* Returns !0 if given address is already assigned to device. */ -int __uwb_dev_addr_assigned_check(struct device *dev, void *_addr) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - struct uwb_dev_addr *addr = _addr; - if (!uwb_dev_addr_cmp(addr, &uwb_dev->dev_addr)) - return !0; - return 0; -} - -/** - * uwb_dev_addr_assign - assigned a generated DevAddr to a radio controller - * @rc: the (local) radio controller device requiring a new DevAddr - * - * A new DevAddr is required when: - * - first setting up a radio controller - * - if the hardware reports a DevAddr conflict - * - * The DevAddr is randomly generated in the generated DevAddr range - * [0x100, 0xfeff]. The number of devices in a beacon group is limited - * by mMaxBPLength (96) so this address space will never be exhausted. - * - * [ECMA-368] 17.1.1, 17.16. - */ -int uwb_rc_dev_addr_assign(struct uwb_rc *rc) -{ - struct uwb_dev_addr new_addr; - - do { - get_random_bytes(new_addr.data, sizeof(new_addr.data)); - } while (new_addr.data[0] == 0x00 || new_addr.data[0] == 0xff - || __uwb_dev_addr_assigned(rc, &new_addr)); - - return uwb_rc_dev_addr_set(rc, &new_addr); -} - -/** - * uwbd_evt_handle_rc_dev_addr_conflict - handle a DEV_ADDR_CONFLICT event - * @evt: the DEV_ADDR_CONFLICT notification from the radio controller - * - * A new (non-conflicting) DevAddr is assigned to the radio controller. - * - * [ECMA-368] 17.1.1.1. - */ -int uwbd_evt_handle_rc_dev_addr_conflict(struct uwb_event *evt) -{ - struct uwb_rc *rc = evt->rc; - - return uwb_rc_dev_addr_assign(rc); -} - -/* - * Print the 48-bit EUI MAC address of the radio controller when - * reading /sys/class/uwb_rc/XX/mac_address - */ -static ssize_t uwb_rc_mac_addr_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - struct uwb_rc *rc = uwb_dev->rc; - struct uwb_mac_addr addr; - ssize_t result; - - mutex_lock(&rc->uwb_dev.mutex); - result = uwb_rc_addr_get(rc, &addr, UWB_ADDR_MAC); - mutex_unlock(&rc->uwb_dev.mutex); - if (result >= 0) { - result = uwb_mac_addr_print(buf, UWB_ADDR_STRSIZE, &addr); - buf[result++] = '\n'; - } - return result; -} - -/* - * Parse a 48 bit address written to /sys/class/uwb_rc/XX/mac_address - * and if correct, set it. - */ -static ssize_t uwb_rc_mac_addr_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - struct uwb_rc *rc = uwb_dev->rc; - struct uwb_mac_addr addr; - ssize_t result; - - if (!mac_pton(buf, addr.data)) - return -EINVAL; - if (is_multicast_ether_addr(addr.data)) { - dev_err(&rc->uwb_dev.dev, "refusing to set multicast " - "MAC address %s\n", buf); - return -EINVAL; - } - result = uwb_rc_mac_addr_set(rc, &addr); - if (result == 0) - rc->uwb_dev.mac_addr = addr; - - return result < 0 ? result : size; -} -DEVICE_ATTR(mac_address, S_IRUGO | S_IWUSR, uwb_rc_mac_addr_show, uwb_rc_mac_addr_store); - -/** Print @addr to @buf, @return bytes written */ -size_t __uwb_addr_print(char *buf, size_t buf_size, const unsigned char *addr, - int type) -{ - size_t result; - if (type) - result = scnprintf(buf, buf_size, "%pM", addr); - else - result = scnprintf(buf, buf_size, "%02x:%02x", - addr[1], addr[0]); - return result; -} -EXPORT_SYMBOL_GPL(__uwb_addr_print); diff --git a/drivers/uwb/allocator.c b/drivers/uwb/allocator.c deleted file mode 100644 index 2e1590124d5f..000000000000 --- a/drivers/uwb/allocator.c +++ /dev/null @@ -1,374 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * UWB reservation management. - * - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - */ -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/uwb.h> - -#include "uwb-internal.h" - -static void uwb_rsv_fill_column_alloc(struct uwb_rsv_alloc_info *ai) -{ - int col, mas, safe_mas, unsafe_mas; - unsigned char *bm = ai->bm; - struct uwb_rsv_col_info *ci = ai->ci; - unsigned char c; - - for (col = ci->csi.start_col; col < UWB_NUM_ZONES; col += ci->csi.interval) { - - safe_mas = ci->csi.safe_mas_per_col; - unsafe_mas = ci->csi.unsafe_mas_per_col; - - for (mas = 0; mas < UWB_MAS_PER_ZONE; mas++ ) { - if (bm[col * UWB_MAS_PER_ZONE + mas] == 0) { - - if (safe_mas > 0) { - safe_mas--; - c = UWB_RSV_MAS_SAFE; - } else if (unsafe_mas > 0) { - unsafe_mas--; - c = UWB_RSV_MAS_UNSAFE; - } else { - break; - } - bm[col * UWB_MAS_PER_ZONE + mas] = c; - } - } - } -} - -static void uwb_rsv_fill_row_alloc(struct uwb_rsv_alloc_info *ai) -{ - int mas, col, rows; - unsigned char *bm = ai->bm; - struct uwb_rsv_row_info *ri = &ai->ri; - unsigned char c; - - rows = 1; - c = UWB_RSV_MAS_SAFE; - for (mas = UWB_MAS_PER_ZONE - 1; mas >= 0; mas--) { - if (ri->avail[mas] == 1) { - - if (rows > ri->used_rows) { - break; - } else if (rows > 7) { - c = UWB_RSV_MAS_UNSAFE; - } - - for (col = 0; col < UWB_NUM_ZONES; col++) { - if (bm[col * UWB_NUM_ZONES + mas] != UWB_RSV_MAS_NOT_AVAIL) { - bm[col * UWB_NUM_ZONES + mas] = c; - if(c == UWB_RSV_MAS_SAFE) - ai->safe_allocated_mases++; - else - ai->unsafe_allocated_mases++; - } - } - rows++; - } - } - ai->total_allocated_mases = ai->safe_allocated_mases + ai->unsafe_allocated_mases; -} - -/* - * Find the best column set for a given availability, interval, num safe mas and - * num unsafe mas. - * - * The different sets are tried in order as shown below, depending on the interval. - * - * interval = 16 - * deep = 0 - * set 1 -> { 8 } - * deep = 1 - * set 1 -> { 4 } - * set 2 -> { 12 } - * deep = 2 - * set 1 -> { 2 } - * set 2 -> { 6 } - * set 3 -> { 10 } - * set 4 -> { 14 } - * deep = 3 - * set 1 -> { 1 } - * set 2 -> { 3 } - * set 3 -> { 5 } - * set 4 -> { 7 } - * set 5 -> { 9 } - * set 6 -> { 11 } - * set 7 -> { 13 } - * set 8 -> { 15 } - * - * interval = 8 - * deep = 0 - * set 1 -> { 4 12 } - * deep = 1 - * set 1 -> { 2 10 } - * set 2 -> { 6 14 } - * deep = 2 - * set 1 -> { 1 9 } - * set 2 -> { 3 11 } - * set 3 -> { 5 13 } - * set 4 -> { 7 15 } - * - * interval = 4 - * deep = 0 - * set 1 -> { 2 6 10 14 } - * deep = 1 - * set 1 -> { 1 5 9 13 } - * set 2 -> { 3 7 11 15 } - * - * interval = 2 - * deep = 0 - * set 1 -> { 1 3 5 7 9 11 13 15 } - */ -static int uwb_rsv_find_best_column_set(struct uwb_rsv_alloc_info *ai, int interval, - int num_safe_mas, int num_unsafe_mas) -{ - struct uwb_rsv_col_info *ci = ai->ci; - struct uwb_rsv_col_set_info *csi = &ci->csi; - struct uwb_rsv_col_set_info tmp_csi; - int deep, set, col, start_col_deep, col_start_set; - int start_col, max_mas_in_set, lowest_max_mas_in_deep; - int n_mas; - int found = UWB_RSV_ALLOC_NOT_FOUND; - - tmp_csi.start_col = 0; - start_col_deep = interval; - n_mas = num_unsafe_mas + num_safe_mas; - - for (deep = 0; ((interval >> deep) & 0x1) == 0; deep++) { - start_col_deep /= 2; - col_start_set = 0; - lowest_max_mas_in_deep = UWB_MAS_PER_ZONE; - - for (set = 1; set <= (1 << deep); set++) { - max_mas_in_set = 0; - start_col = start_col_deep + col_start_set; - for (col = start_col; col < UWB_NUM_ZONES; col += interval) { - - if (ci[col].max_avail_safe >= num_safe_mas && - ci[col].max_avail_unsafe >= n_mas) { - if (ci[col].highest_mas[n_mas] > max_mas_in_set) - max_mas_in_set = ci[col].highest_mas[n_mas]; - } else { - max_mas_in_set = 0; - break; - } - } - if ((lowest_max_mas_in_deep > max_mas_in_set) && max_mas_in_set) { - lowest_max_mas_in_deep = max_mas_in_set; - - tmp_csi.start_col = start_col; - } - col_start_set += (interval >> deep); - } - - if (lowest_max_mas_in_deep < 8) { - csi->start_col = tmp_csi.start_col; - found = UWB_RSV_ALLOC_FOUND; - break; - } else if ((lowest_max_mas_in_deep > 8) && - (lowest_max_mas_in_deep != UWB_MAS_PER_ZONE) && - (found == UWB_RSV_ALLOC_NOT_FOUND)) { - csi->start_col = tmp_csi.start_col; - found = UWB_RSV_ALLOC_FOUND; - } - } - - if (found == UWB_RSV_ALLOC_FOUND) { - csi->interval = interval; - csi->safe_mas_per_col = num_safe_mas; - csi->unsafe_mas_per_col = num_unsafe_mas; - - ai->safe_allocated_mases = (UWB_NUM_ZONES / interval) * num_safe_mas; - ai->unsafe_allocated_mases = (UWB_NUM_ZONES / interval) * num_unsafe_mas; - ai->total_allocated_mases = ai->safe_allocated_mases + ai->unsafe_allocated_mases; - ai->interval = interval; - } - return found; -} - -static void get_row_descriptors(struct uwb_rsv_alloc_info *ai) -{ - unsigned char *bm = ai->bm; - struct uwb_rsv_row_info *ri = &ai->ri; - int col, mas; - - ri->free_rows = 16; - for (mas = 0; mas < UWB_MAS_PER_ZONE; mas ++) { - ri->avail[mas] = 1; - for (col = 1; col < UWB_NUM_ZONES; col++) { - if (bm[col * UWB_NUM_ZONES + mas] == UWB_RSV_MAS_NOT_AVAIL) { - ri->free_rows--; - ri->avail[mas]=0; - break; - } - } - } -} - -static void uwb_rsv_fill_column_info(unsigned char *bm, int column, struct uwb_rsv_col_info *rci) -{ - int mas; - int block_count = 0, start_block = 0; - int previous_avail = 0; - int available = 0; - int safe_mas_in_row[UWB_MAS_PER_ZONE] = { - 8, 7, 6, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 2, 1, - }; - - rci->max_avail_safe = 0; - - for (mas = 0; mas < UWB_MAS_PER_ZONE; mas ++) { - if (!bm[column * UWB_NUM_ZONES + mas]) { - available++; - rci->max_avail_unsafe = available; - - rci->highest_mas[available] = mas; - - if (previous_avail) { - block_count++; - if ((block_count > safe_mas_in_row[start_block]) && - (!rci->max_avail_safe)) - rci->max_avail_safe = available - 1; - } else { - previous_avail = 1; - start_block = mas; - block_count = 1; - } - } else { - previous_avail = 0; - } - } - if (!rci->max_avail_safe) - rci->max_avail_safe = rci->max_avail_unsafe; -} - -static void get_column_descriptors(struct uwb_rsv_alloc_info *ai) -{ - unsigned char *bm = ai->bm; - struct uwb_rsv_col_info *ci = ai->ci; - int col; - - for (col = 1; col < UWB_NUM_ZONES; col++) { - uwb_rsv_fill_column_info(bm, col, &ci[col]); - } -} - -static int uwb_rsv_find_best_row_alloc(struct uwb_rsv_alloc_info *ai) -{ - int n_rows; - int max_rows = ai->max_mas / UWB_USABLE_MAS_PER_ROW; - int min_rows = ai->min_mas / UWB_USABLE_MAS_PER_ROW; - if (ai->min_mas % UWB_USABLE_MAS_PER_ROW) - min_rows++; - for (n_rows = max_rows; n_rows >= min_rows; n_rows--) { - if (n_rows <= ai->ri.free_rows) { - ai->ri.used_rows = n_rows; - ai->interval = 1; /* row reservation */ - uwb_rsv_fill_row_alloc(ai); - return UWB_RSV_ALLOC_FOUND; - } - } - return UWB_RSV_ALLOC_NOT_FOUND; -} - -static int uwb_rsv_find_best_col_alloc(struct uwb_rsv_alloc_info *ai, int interval) -{ - int n_safe, n_unsafe, n_mas; - int n_column = UWB_NUM_ZONES / interval; - int max_per_zone = ai->max_mas / n_column; - int min_per_zone = ai->min_mas / n_column; - - if (ai->min_mas % n_column) - min_per_zone++; - - if (min_per_zone > UWB_MAS_PER_ZONE) { - return UWB_RSV_ALLOC_NOT_FOUND; - } - - if (max_per_zone > UWB_MAS_PER_ZONE) { - max_per_zone = UWB_MAS_PER_ZONE; - } - - for (n_mas = max_per_zone; n_mas >= min_per_zone; n_mas--) { - if (uwb_rsv_find_best_column_set(ai, interval, 0, n_mas) == UWB_RSV_ALLOC_NOT_FOUND) - continue; - for (n_safe = n_mas; n_safe >= 0; n_safe--) { - n_unsafe = n_mas - n_safe; - if (uwb_rsv_find_best_column_set(ai, interval, n_safe, n_unsafe) == UWB_RSV_ALLOC_FOUND) { - uwb_rsv_fill_column_alloc(ai); - return UWB_RSV_ALLOC_FOUND; - } - } - } - return UWB_RSV_ALLOC_NOT_FOUND; -} - -int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv, struct uwb_mas_bm *available, - struct uwb_mas_bm *result) -{ - struct uwb_rsv_alloc_info *ai; - int interval; - int bit_index; - - ai = kzalloc(sizeof(struct uwb_rsv_alloc_info), GFP_KERNEL); - if (!ai) - return UWB_RSV_ALLOC_NOT_FOUND; - ai->min_mas = rsv->min_mas; - ai->max_mas = rsv->max_mas; - ai->max_interval = rsv->max_interval; - - - /* fill the not available vector from the available bm */ - for_each_clear_bit(bit_index, available->bm, UWB_NUM_MAS) - ai->bm[bit_index] = UWB_RSV_MAS_NOT_AVAIL; - - if (ai->max_interval == 1) { - get_row_descriptors(ai); - if (uwb_rsv_find_best_row_alloc(ai) == UWB_RSV_ALLOC_FOUND) - goto alloc_found; - else - goto alloc_not_found; - } - - get_column_descriptors(ai); - - for (interval = 16; interval >= 2; interval>>=1) { - if (interval > ai->max_interval) - continue; - if (uwb_rsv_find_best_col_alloc(ai, interval) == UWB_RSV_ALLOC_FOUND) - goto alloc_found; - } - - /* try row reservation if no column is found */ - get_row_descriptors(ai); - if (uwb_rsv_find_best_row_alloc(ai) == UWB_RSV_ALLOC_FOUND) - goto alloc_found; - else - goto alloc_not_found; - - alloc_found: - bitmap_zero(result->bm, UWB_NUM_MAS); - bitmap_zero(result->unsafe_bm, UWB_NUM_MAS); - /* fill the safe and unsafe bitmaps */ - for (bit_index = 0; bit_index < UWB_NUM_MAS; bit_index++) { - if (ai->bm[bit_index] == UWB_RSV_MAS_SAFE) - set_bit(bit_index, result->bm); - else if (ai->bm[bit_index] == UWB_RSV_MAS_UNSAFE) - set_bit(bit_index, result->unsafe_bm); - } - bitmap_or(result->bm, result->bm, result->unsafe_bm, UWB_NUM_MAS); - - result->safe = ai->safe_allocated_mases; - result->unsafe = ai->unsafe_allocated_mases; - - kfree(ai); - return UWB_RSV_ALLOC_FOUND; - - alloc_not_found: - kfree(ai); - return UWB_RSV_ALLOC_NOT_FOUND; -} diff --git a/drivers/uwb/beacon.c b/drivers/uwb/beacon.c deleted file mode 100644 index c483c19c5ef8..000000000000 --- a/drivers/uwb/beacon.c +++ /dev/null @@ -1,595 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Ultra Wide Band - * Beacon management - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * FIXME: docs - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/err.h> -#include <linux/kdev_t.h> -#include <linux/slab.h> - -#include "uwb-internal.h" - -/* Start Beaconing command structure */ -struct uwb_rc_cmd_start_beacon { - struct uwb_rccb rccb; - __le16 wBPSTOffset; - u8 bChannelNumber; -} __attribute__((packed)); - - -static int uwb_rc_start_beacon(struct uwb_rc *rc, u16 bpst_offset, u8 channel) -{ - int result; - struct uwb_rc_cmd_start_beacon *cmd; - struct uwb_rc_evt_confirm reply; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; - cmd->rccb.bCommandType = UWB_RC_CET_GENERAL; - cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_START_BEACON); - cmd->wBPSTOffset = cpu_to_le16(bpst_offset); - cmd->bChannelNumber = channel; - reply.rceb.bEventType = UWB_RC_CET_GENERAL; - reply.rceb.wEvent = UWB_RC_CMD_START_BEACON; - result = uwb_rc_cmd(rc, "START-BEACON", &cmd->rccb, sizeof(*cmd), - &reply.rceb, sizeof(reply)); - if (result < 0) - goto error_cmd; - if (reply.bResultCode != UWB_RC_RES_SUCCESS) { - dev_err(&rc->uwb_dev.dev, - "START-BEACON: command execution failed: %s (%d)\n", - uwb_rc_strerror(reply.bResultCode), reply.bResultCode); - result = -EIO; - } -error_cmd: - kfree(cmd); - return result; -} - -static int uwb_rc_stop_beacon(struct uwb_rc *rc) -{ - int result; - struct uwb_rccb *cmd; - struct uwb_rc_evt_confirm reply; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; - cmd->bCommandType = UWB_RC_CET_GENERAL; - cmd->wCommand = cpu_to_le16(UWB_RC_CMD_STOP_BEACON); - reply.rceb.bEventType = UWB_RC_CET_GENERAL; - reply.rceb.wEvent = UWB_RC_CMD_STOP_BEACON; - result = uwb_rc_cmd(rc, "STOP-BEACON", cmd, sizeof(*cmd), - &reply.rceb, sizeof(reply)); - if (result < 0) - goto error_cmd; - if (reply.bResultCode != UWB_RC_RES_SUCCESS) { - dev_err(&rc->uwb_dev.dev, - "STOP-BEACON: command execution failed: %s (%d)\n", - uwb_rc_strerror(reply.bResultCode), reply.bResultCode); - result = -EIO; - } -error_cmd: - kfree(cmd); - return result; -} - -/* - * Start/stop beacons - * - * @rc: UWB Radio Controller to operate on - * @channel: UWB channel on which to beacon (WUSB[table - * 5-12]). If -1, stop beaconing. - * @bpst_offset: Beacon Period Start Time offset; FIXME-do zero - * - * According to WHCI 0.95 [4.13.6] the driver will only receive the RCEB - * of a SET IE command after the device sent the first beacon that includes - * the IEs specified in the SET IE command. So, after we start beaconing we - * check if there is anything in the IE cache and call the SET IE command - * if needed. - */ -int uwb_rc_beacon(struct uwb_rc *rc, int channel, unsigned bpst_offset) -{ - int result; - struct device *dev = &rc->uwb_dev.dev; - - dev_dbg(dev, "%s: channel = %d\n", __func__, channel); - if (channel < 0) - channel = -1; - if (channel == -1) - result = uwb_rc_stop_beacon(rc); - else { - /* channel >= 0...dah */ - result = uwb_rc_start_beacon(rc, bpst_offset, channel); - if (result < 0) { - dev_err(dev, "Cannot start beaconing: %d\n", result); - return result; - } - if (le16_to_cpu(rc->ies->wIELength) > 0) { - result = uwb_rc_set_ie(rc, rc->ies); - if (result < 0) { - dev_err(dev, "Cannot set new IE on device: " - "%d\n", result); - result = uwb_rc_stop_beacon(rc); - channel = -1; - bpst_offset = 0; - } - } - } - - if (result >= 0) - rc->beaconing = channel; - return result; -} - -/* - * Beacon cache - * - * The purpose of this is to speed up the lookup of becon information - * when a new beacon arrives. The UWB Daemon uses it also to keep a - * tab of which devices are in radio distance and which not. When a - * device's beacon stays present for more than a certain amount of - * time, it is considered a new, usable device. When a beacon ceases - * to be received for a certain amount of time, it is considered that - * the device is gone. - * - * FIXME: use an allocator for the entries - * FIXME: use something faster for search than a list - */ - -void uwb_bce_kfree(struct kref *_bce) -{ - struct uwb_beca_e *bce = container_of(_bce, struct uwb_beca_e, refcnt); - - kfree(bce->be); - kfree(bce); -} - - -/* Find a beacon by dev addr in the cache */ -static -struct uwb_beca_e *__uwb_beca_find_bydev(struct uwb_rc *rc, - const struct uwb_dev_addr *dev_addr) -{ - struct uwb_beca_e *bce, *next; - list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) { - if (!memcmp(&bce->dev_addr, dev_addr, sizeof(bce->dev_addr))) - goto out; - } - bce = NULL; -out: - return bce; -} - -/* Find a beacon by dev addr in the cache */ -static -struct uwb_beca_e *__uwb_beca_find_bymac(struct uwb_rc *rc, - const struct uwb_mac_addr *mac_addr) -{ - struct uwb_beca_e *bce, *next; - list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) { - if (!memcmp(bce->mac_addr, mac_addr->data, - sizeof(struct uwb_mac_addr))) - goto out; - } - bce = NULL; -out: - return bce; -} - -/** - * uwb_dev_get_by_devaddr - get a UWB device with a specific DevAddr - * @rc: the radio controller that saw the device - * @devaddr: DevAddr of the UWB device to find - * - * There may be more than one matching device (in the case of a - * DevAddr conflict), but only the first one is returned. - */ -struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc, - const struct uwb_dev_addr *devaddr) -{ - struct uwb_dev *found = NULL; - struct uwb_beca_e *bce; - - mutex_lock(&rc->uwb_beca.mutex); - bce = __uwb_beca_find_bydev(rc, devaddr); - if (bce) - found = uwb_dev_try_get(rc, bce->uwb_dev); - mutex_unlock(&rc->uwb_beca.mutex); - - return found; -} - -/** - * uwb_dev_get_by_macaddr - get a UWB device with a specific EUI-48 - * @rc: the radio controller that saw the device - * @devaddr: EUI-48 of the UWB device to find - */ -struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc, - const struct uwb_mac_addr *macaddr) -{ - struct uwb_dev *found = NULL; - struct uwb_beca_e *bce; - - mutex_lock(&rc->uwb_beca.mutex); - bce = __uwb_beca_find_bymac(rc, macaddr); - if (bce) - found = uwb_dev_try_get(rc, bce->uwb_dev); - mutex_unlock(&rc->uwb_beca.mutex); - - return found; -} - -/* Initialize a beacon cache entry */ -static void uwb_beca_e_init(struct uwb_beca_e *bce) -{ - mutex_init(&bce->mutex); - kref_init(&bce->refcnt); - stats_init(&bce->lqe_stats); - stats_init(&bce->rssi_stats); -} - -/* - * Add a beacon to the cache - * - * @be: Beacon event information - * @bf: Beacon frame (part of b, really) - * @ts_jiffies: Timestamp (in jiffies) when the beacon was received - */ -static -struct uwb_beca_e *__uwb_beca_add(struct uwb_rc *rc, - struct uwb_rc_evt_beacon *be, - struct uwb_beacon_frame *bf, - unsigned long ts_jiffies) -{ - struct uwb_beca_e *bce; - - bce = kzalloc(sizeof(*bce), GFP_KERNEL); - if (bce == NULL) - return NULL; - uwb_beca_e_init(bce); - bce->ts_jiffies = ts_jiffies; - bce->uwb_dev = NULL; - list_add(&bce->node, &rc->uwb_beca.list); - return bce; -} - -/* - * Wipe out beacon entries that became stale - * - * Remove associated devicest too. - */ -void uwb_beca_purge(struct uwb_rc *rc) -{ - struct uwb_beca_e *bce, *next; - unsigned long expires; - - mutex_lock(&rc->uwb_beca.mutex); - list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) { - expires = bce->ts_jiffies + msecs_to_jiffies(beacon_timeout_ms); - if (time_after(jiffies, expires)) { - uwbd_dev_offair(bce); - } - } - mutex_unlock(&rc->uwb_beca.mutex); -} - -/* Clean up the whole beacon cache. Called on shutdown */ -void uwb_beca_release(struct uwb_rc *rc) -{ - struct uwb_beca_e *bce, *next; - - mutex_lock(&rc->uwb_beca.mutex); - list_for_each_entry_safe(bce, next, &rc->uwb_beca.list, node) { - list_del(&bce->node); - uwb_bce_put(bce); - } - mutex_unlock(&rc->uwb_beca.mutex); -} - -static void uwb_beacon_print(struct uwb_rc *rc, struct uwb_rc_evt_beacon *be, - struct uwb_beacon_frame *bf) -{ - char macbuf[UWB_ADDR_STRSIZE]; - char devbuf[UWB_ADDR_STRSIZE]; - char dstbuf[UWB_ADDR_STRSIZE]; - - uwb_mac_addr_print(macbuf, sizeof(macbuf), &bf->Device_Identifier); - uwb_dev_addr_print(devbuf, sizeof(devbuf), &bf->hdr.SrcAddr); - uwb_dev_addr_print(dstbuf, sizeof(dstbuf), &bf->hdr.DestAddr); - dev_info(&rc->uwb_dev.dev, - "BEACON from %s to %s (ch%u offset %u slot %u MAC %s)\n", - devbuf, dstbuf, be->bChannelNumber, be->wBPSTOffset, - bf->Beacon_Slot_Number, macbuf); -} - -/* - * @bce: beacon cache entry, referenced - */ -ssize_t uwb_bce_print_IEs(struct uwb_dev *uwb_dev, struct uwb_beca_e *bce, - char *buf, size_t size) -{ - ssize_t result = 0; - struct uwb_rc_evt_beacon *be; - struct uwb_beacon_frame *bf; - int ies_len; - struct uwb_ie_hdr *ies; - - mutex_lock(&bce->mutex); - - be = bce->be; - if (be) { - bf = (struct uwb_beacon_frame *)bce->be->BeaconInfo; - ies_len = be->wBeaconInfoLength - sizeof(struct uwb_beacon_frame); - ies = (struct uwb_ie_hdr *)bf->IEData; - - result = uwb_ie_dump_hex(ies, ies_len, buf, size); - } - - mutex_unlock(&bce->mutex); - - return result; -} - -/* - * Verify that the beacon event, frame and IEs are ok - */ -static int uwb_verify_beacon(struct uwb_rc *rc, struct uwb_event *evt, - struct uwb_rc_evt_beacon *be) -{ - int result = -EINVAL; - struct uwb_beacon_frame *bf; - struct device *dev = &rc->uwb_dev.dev; - - /* Is there enough data to decode a beacon frame? */ - if (evt->notif.size < sizeof(*be) + sizeof(*bf)) { - dev_err(dev, "BEACON event: Not enough data to decode " - "(%zu vs %zu bytes needed)\n", evt->notif.size, - sizeof(*be) + sizeof(*bf)); - goto error; - } - /* FIXME: make sure beacon frame IEs are fine and that the whole thing - * is consistent */ - result = 0; -error: - return result; -} - -/* - * Handle UWB_RC_EVT_BEACON events - * - * We check the beacon cache to see how the received beacon fares. If - * is there already we refresh the timestamp. If not we create a new - * entry. - * - * According to the WHCI and WUSB specs, only one beacon frame is - * allowed per notification block, so we don't bother about scanning - * for more. - */ -int uwbd_evt_handle_rc_beacon(struct uwb_event *evt) -{ - int result = -EINVAL; - struct uwb_rc *rc; - struct uwb_rc_evt_beacon *be; - struct uwb_beacon_frame *bf; - struct uwb_beca_e *bce; - - rc = evt->rc; - be = container_of(evt->notif.rceb, struct uwb_rc_evt_beacon, rceb); - result = uwb_verify_beacon(rc, evt, be); - if (result < 0) - return result; - - /* FIXME: handle alien beacons. */ - if (be->bBeaconType == UWB_RC_BEACON_TYPE_OL_ALIEN || - be->bBeaconType == UWB_RC_BEACON_TYPE_NOL_ALIEN) { - return -ENOSYS; - } - - bf = (struct uwb_beacon_frame *) be->BeaconInfo; - - /* - * Drop beacons from devices with a NULL EUI-48 -- they cannot - * be uniquely identified. - * - * It's expected that these will all be WUSB devices and they - * have a WUSB specific connection method so ignoring them - * here shouldn't be a problem. - */ - if (uwb_mac_addr_bcast(&bf->Device_Identifier)) - return 0; - - mutex_lock(&rc->uwb_beca.mutex); - bce = __uwb_beca_find_bymac(rc, &bf->Device_Identifier); - if (bce == NULL) { - /* Not in there, a new device is pinging */ - uwb_beacon_print(evt->rc, be, bf); - bce = __uwb_beca_add(rc, be, bf, evt->ts_jiffies); - if (bce == NULL) { - mutex_unlock(&rc->uwb_beca.mutex); - return -ENOMEM; - } - } - mutex_unlock(&rc->uwb_beca.mutex); - - mutex_lock(&bce->mutex); - /* purge old beacon data */ - kfree(bce->be); - - /* Update commonly used fields */ - bce->ts_jiffies = evt->ts_jiffies; - bce->be = be; - bce->dev_addr = bf->hdr.SrcAddr; - bce->mac_addr = &bf->Device_Identifier; - be->wBPSTOffset = le16_to_cpu(be->wBPSTOffset); - be->wBeaconInfoLength = le16_to_cpu(be->wBeaconInfoLength); - stats_add_sample(&bce->lqe_stats, be->bLQI - 7); - stats_add_sample(&bce->rssi_stats, be->bRSSI + 18); - - /* - * This might be a beacon from a new device. - */ - if (bce->uwb_dev == NULL) - uwbd_dev_onair(evt->rc, bce); - - mutex_unlock(&bce->mutex); - - return 1; /* we keep the event data */ -} - -/* - * Handle UWB_RC_EVT_BEACON_SIZE events - * - * XXXXX - */ -int uwbd_evt_handle_rc_beacon_size(struct uwb_event *evt) -{ - int result = -EINVAL; - struct device *dev = &evt->rc->uwb_dev.dev; - struct uwb_rc_evt_beacon_size *bs; - - /* Is there enough data to decode the event? */ - if (evt->notif.size < sizeof(*bs)) { - dev_err(dev, "BEACON SIZE notification: Not enough data to " - "decode (%zu vs %zu bytes needed)\n", - evt->notif.size, sizeof(*bs)); - goto error; - } - bs = container_of(evt->notif.rceb, struct uwb_rc_evt_beacon_size, rceb); - if (0) - dev_info(dev, "Beacon size changed to %u bytes " - "(FIXME: action?)\n", le16_to_cpu(bs->wNewBeaconSize)); - else { - /* temporary hack until we do something with this message... */ - static unsigned count; - if (++count % 1000 == 0) - dev_info(dev, "Beacon size changed %u times " - "(FIXME: action?)\n", count); - } - result = 0; -error: - return result; -} - -/** - * uwbd_evt_handle_rc_bp_slot_change - handle a BP_SLOT_CHANGE event - * @evt: the BP_SLOT_CHANGE notification from the radio controller - * - * If the event indicates that no beacon period slots were available - * then radio controller has transitioned to a non-beaconing state. - * Otherwise, simply save the current beacon slot. - */ -int uwbd_evt_handle_rc_bp_slot_change(struct uwb_event *evt) -{ - struct uwb_rc *rc = evt->rc; - struct device *dev = &rc->uwb_dev.dev; - struct uwb_rc_evt_bp_slot_change *bpsc; - - if (evt->notif.size < sizeof(*bpsc)) { - dev_err(dev, "BP SLOT CHANGE event: Not enough data\n"); - return -EINVAL; - } - bpsc = container_of(evt->notif.rceb, struct uwb_rc_evt_bp_slot_change, rceb); - - if (uwb_rc_evt_bp_slot_change_no_slot(bpsc)) { - dev_err(dev, "stopped beaconing: No free slots in BP\n"); - mutex_lock(&rc->uwb_dev.mutex); - rc->beaconing = -1; - mutex_unlock(&rc->uwb_dev.mutex); - } else - rc->uwb_dev.beacon_slot = uwb_rc_evt_bp_slot_change_slot_num(bpsc); - - return 0; -} - -/** - * Handle UWB_RC_EVT_BPOIE_CHANGE events - * - * XXXXX - */ -struct uwb_ie_bpo { - struct uwb_ie_hdr hdr; - u8 bp_length; - u8 data[]; -} __attribute__((packed)); - -int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *evt) -{ - int result = -EINVAL; - struct device *dev = &evt->rc->uwb_dev.dev; - struct uwb_rc_evt_bpoie_change *bpoiec; - struct uwb_ie_bpo *bpoie; - static unsigned count; /* FIXME: this is a temp hack */ - size_t iesize; - - /* Is there enough data to decode it? */ - if (evt->notif.size < sizeof(*bpoiec)) { - dev_err(dev, "BPOIEC notification: Not enough data to " - "decode (%zu vs %zu bytes needed)\n", - evt->notif.size, sizeof(*bpoiec)); - goto error; - } - bpoiec = container_of(evt->notif.rceb, struct uwb_rc_evt_bpoie_change, rceb); - iesize = le16_to_cpu(bpoiec->wBPOIELength); - if (iesize < sizeof(*bpoie)) { - dev_err(dev, "BPOIEC notification: Not enough IE data to " - "decode (%zu vs %zu bytes needed)\n", - iesize, sizeof(*bpoie)); - goto error; - } - if (++count % 1000 == 0) /* Lame placeholder */ - dev_info(dev, "BPOIE: %u changes received\n", count); - /* - * FIXME: At this point we should go over all the IEs in the - * bpoiec->BPOIE array and act on each. - */ - result = 0; -error: - return result; -} - -/* - * Print beaconing state. - */ -static ssize_t uwb_rc_beacon_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - struct uwb_rc *rc = uwb_dev->rc; - ssize_t result; - - mutex_lock(&rc->uwb_dev.mutex); - result = sprintf(buf, "%d\n", rc->beaconing); - mutex_unlock(&rc->uwb_dev.mutex); - return result; -} - -/* - * Start beaconing on the specified channel, or stop beaconing. - */ -static ssize_t uwb_rc_beacon_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - struct uwb_rc *rc = uwb_dev->rc; - int channel; - ssize_t result = -EINVAL; - - result = sscanf(buf, "%d", &channel); - if (result >= 1) - result = uwb_radio_force_channel(rc, channel); - - return result < 0 ? result : size; -} -DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, uwb_rc_beacon_show, uwb_rc_beacon_store); diff --git a/drivers/uwb/driver.c b/drivers/uwb/driver.c deleted file mode 100644 index 5755c2e49ffc..000000000000 --- a/drivers/uwb/driver.c +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Ultra Wide Band - * Driver initialization, etc - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * FIXME: docs - * - * Life cycle: FIXME: explain - * - * UWB radio controller: - * - * 1. alloc a uwb_rc, zero it - * 2. call uwb_rc_init() on it to set it up + ops (won't do any - * kind of allocation) - * 3. register (now it is owned by the UWB stack--deregister before - * freeing/destroying). - * 4. It lives on it's own now (UWB stack handles)--when it - * disconnects, call unregister() - * 5. free it. - * - * Make sure you have a reference to the uwb_rc before calling - * any of the UWB API functions. - * - * TODO: - * - * 1. Locking and life cycle management is crappy still. All entry - * points to the UWB HCD API assume you have a reference on the - * uwb_rc structure and that it won't go away. They mutex lock it - * before doing anything. - */ - -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/err.h> -#include <linux/kdev_t.h> -#include <linux/random.h> - -#include "uwb-internal.h" - - -/* UWB stack attributes (or 'global' constants) */ - - -/** - * If a beacon disappears for longer than this, then we consider the - * device who was represented by that beacon to be gone. - * - * ECMA-368[17.2.3, last para] establishes that a device must not - * consider a device to be its neighbour if he doesn't receive a beacon - * for more than mMaxLostBeacons. mMaxLostBeacons is defined in - * ECMA-368[17.16] as 3; because we can get only one beacon per - * superframe, that'd be 3 * 65ms = 195 ~ 200 ms. Let's give it time - * for jitter and stuff and make it 500 ms. - */ -unsigned long beacon_timeout_ms = 500; - -static -ssize_t beacon_timeout_ms_show(struct class *class, - struct class_attribute *attr, - char *buf) -{ - return scnprintf(buf, PAGE_SIZE, "%lu\n", beacon_timeout_ms); -} - -static -ssize_t beacon_timeout_ms_store(struct class *class, - struct class_attribute *attr, - const char *buf, size_t size) -{ - unsigned long bt; - ssize_t result; - result = sscanf(buf, "%lu", &bt); - if (result != 1) - return -EINVAL; - beacon_timeout_ms = bt; - return size; -} -static CLASS_ATTR_RW(beacon_timeout_ms); - -static struct attribute *uwb_class_attrs[] = { - &class_attr_beacon_timeout_ms.attr, - NULL, -}; -ATTRIBUTE_GROUPS(uwb_class); - -/** Device model classes */ -struct class uwb_rc_class = { - .name = "uwb_rc", - .class_groups = uwb_class_groups, -}; - - -static int __init uwb_subsys_init(void) -{ - int result = 0; - - result = uwb_est_create(); - if (result < 0) { - printk(KERN_ERR "uwb: Can't initialize EST subsystem\n"); - goto error_est_init; - } - - result = class_register(&uwb_rc_class); - if (result < 0) - goto error_uwb_rc_class_register; - - /* Register the UWB bus */ - result = bus_register(&uwb_bus_type); - if (result) { - pr_err("%s - registering bus driver failed\n", __func__); - goto exit_bus; - } - - uwb_dbg_init(); - return 0; - -exit_bus: - class_unregister(&uwb_rc_class); -error_uwb_rc_class_register: - uwb_est_destroy(); -error_est_init: - return result; -} -module_init(uwb_subsys_init); - -static void __exit uwb_subsys_exit(void) -{ - uwb_dbg_exit(); - bus_unregister(&uwb_bus_type); - class_unregister(&uwb_rc_class); - uwb_est_destroy(); - return; -} -module_exit(uwb_subsys_exit); - -MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); -MODULE_DESCRIPTION("Ultra Wide Band core"); -MODULE_LICENSE("GPL"); diff --git a/drivers/uwb/drp-avail.c b/drivers/uwb/drp-avail.c deleted file mode 100644 index 02392ab82a7d..000000000000 --- a/drivers/uwb/drp-avail.c +++ /dev/null @@ -1,278 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Ultra Wide Band - * DRP availability management - * - * Copyright (C) 2005-2006 Intel Corporation - * Reinette Chatre <reinette.chatre@intel.com> - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - * - * Manage DRP Availability (the MAS available for DRP - * reservations). Thus: - * - * - Handle DRP Availability Change notifications - * - * - Allow the reservation manager to indicate MAS reserved/released - * by local (owned by/targeted at the radio controller) - * reservations. - * - * - Based on the two sources above, generate a DRP Availability IE to - * be included in the beacon. - * - * See also the documentation for struct uwb_drp_avail. - */ - -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/bitmap.h> -#include "uwb-internal.h" - -/** - * uwb_drp_avail_init - initialize an RC's MAS availability - * - * All MAS are available initially. The RC will inform use which - * slots are used for the BP (it may change in size). - */ -void uwb_drp_avail_init(struct uwb_rc *rc) -{ - bitmap_fill(rc->drp_avail.global, UWB_NUM_MAS); - bitmap_fill(rc->drp_avail.local, UWB_NUM_MAS); - bitmap_fill(rc->drp_avail.pending, UWB_NUM_MAS); -} - -/* - * Determine MAS available for new local reservations. - * - * avail = global & local & pending - */ -void uwb_drp_available(struct uwb_rc *rc, struct uwb_mas_bm *avail) -{ - bitmap_and(avail->bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS); - bitmap_and(avail->bm, avail->bm, rc->drp_avail.pending, UWB_NUM_MAS); -} - -/** - * uwb_drp_avail_reserve_pending - reserve MAS for a new reservation - * @rc: the radio controller - * @mas: the MAS to reserve - * - * Returns 0 on success, or -EBUSY if the MAS requested aren't available. - */ -int uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas) -{ - struct uwb_mas_bm avail; - - uwb_drp_available(rc, &avail); - if (!bitmap_subset(mas->bm, avail.bm, UWB_NUM_MAS)) - return -EBUSY; - - bitmap_andnot(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS); - return 0; -} - -/** - * uwb_drp_avail_reserve - reserve MAS for an established reservation - * @rc: the radio controller - * @mas: the MAS to reserve - */ -void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas) -{ - bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS); - bitmap_andnot(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS); - rc->drp_avail.ie_valid = false; -} - -/** - * uwb_drp_avail_release - release MAS from a pending or established reservation - * @rc: the radio controller - * @mas: the MAS to release - */ -void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas) -{ - bitmap_or(rc->drp_avail.local, rc->drp_avail.local, mas->bm, UWB_NUM_MAS); - bitmap_or(rc->drp_avail.pending, rc->drp_avail.pending, mas->bm, UWB_NUM_MAS); - rc->drp_avail.ie_valid = false; - uwb_rsv_handle_drp_avail_change(rc); -} - -/** - * uwb_drp_avail_ie_update - update the DRP Availability IE - * @rc: the radio controller - * - * avail = global & local - */ -void uwb_drp_avail_ie_update(struct uwb_rc *rc) -{ - struct uwb_mas_bm avail; - - bitmap_and(avail.bm, rc->drp_avail.global, rc->drp_avail.local, UWB_NUM_MAS); - - rc->drp_avail.ie.hdr.element_id = UWB_IE_DRP_AVAILABILITY; - rc->drp_avail.ie.hdr.length = UWB_NUM_MAS / 8; - uwb_mas_bm_copy_le(rc->drp_avail.ie.bmp, &avail); - rc->drp_avail.ie_valid = true; -} - -/** - * Create an unsigned long from a buffer containing a byte stream. - * - * @array: pointer to buffer - * @itr: index of buffer from where we start - * @len: the buffer's remaining size may not be exact multiple of - * sizeof(unsigned long), @len is the length of buffer that needs - * to be converted. This will be sizeof(unsigned long) or smaller - * (BUG if not). If it is smaller then we will pad the remaining - * space of the result with zeroes. - */ -static -unsigned long get_val(u8 *array, size_t itr, size_t len) -{ - unsigned long val = 0; - size_t top = itr + len; - - BUG_ON(len > sizeof(val)); - - while (itr < top) { - val <<= 8; - val |= array[top - 1]; - top--; - } - val <<= 8 * (sizeof(val) - len); /* padding */ - return val; -} - -/** - * Initialize bitmap from data buffer. - * - * The bitmap to be converted could come from a IE, for example a - * DRP Availability IE. - * From ECMA-368 1.0 [16.8.7]: " - * octets: 1 1 N * (0 to 32) - * Element ID Length (=N) DRP Availability Bitmap - * - * The DRP Availability Bitmap field is up to 256 bits long, one - * bit for each MAS in the superframe, where the least-significant - * bit of the field corresponds to the first MAS in the superframe - * and successive bits correspond to successive MASs." - * - * The DRP Availability bitmap is in octets from 0 to 32, so octet - * 32 contains bits for MAS 1-8, etc. If the bitmap is smaller than 32 - * octets, the bits in octets not included at the end of the bitmap are - * treated as zero. In this case (when the bitmap is smaller than 32 - * octets) the MAS represented range from MAS 1 to MAS (size of bitmap) - * with the last octet still containing bits for MAS 1-8, etc. - * - * For example: - * F00F0102 03040506 0708090A 0B0C0D0E 0F010203 - * ^^^^ - * |||| - * |||| - * |||\LSB of byte is MAS 9 - * ||\MSB of byte is MAS 16 - * |\LSB of first byte is MAS 1 - * \ MSB of byte is MAS 8 - * - * An example of this encoding can be found in ECMA-368 Annex-D [Table D.11] - * - * The resulting bitmap will have the following mapping: - * bit position 0 == MAS 1 - * bit position 1 == MAS 2 - * ... - * bit position (UWB_NUM_MAS - 1) == MAS UWB_NUM_MAS - * - * @bmp_itr: pointer to bitmap (can be declared with DECLARE_BITMAP) - * @buffer: pointer to buffer containing bitmap data in big endian - * format (MSB first) - * @buffer_size:number of bytes with which bitmap should be initialized - */ -static -void buffer_to_bmp(unsigned long *bmp_itr, void *_buffer, - size_t buffer_size) -{ - u8 *buffer = _buffer; - size_t itr, len; - unsigned long val; - - itr = 0; - while (itr < buffer_size) { - len = buffer_size - itr >= sizeof(val) ? - sizeof(val) : buffer_size - itr; - val = get_val(buffer, itr, len); - bmp_itr[itr / sizeof(val)] = val; - itr += sizeof(val); - } -} - - -/** - * Extract DRP Availability bitmap from the notification. - * - * The notification that comes in contains a bitmap of (UWB_NUM_MAS / 8) bytes - * We convert that to our internal representation. - */ -static -int uwbd_evt_get_drp_avail(struct uwb_event *evt, unsigned long *bmp) -{ - struct device *dev = &evt->rc->uwb_dev.dev; - struct uwb_rc_evt_drp_avail *drp_evt; - int result = -EINVAL; - - /* Is there enough data to decode the event? */ - if (evt->notif.size < sizeof(*drp_evt)) { - dev_err(dev, "DRP Availability Change: Not enough " - "data to decode event [%zu bytes, %zu " - "needed]\n", evt->notif.size, sizeof(*drp_evt)); - goto error; - } - drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp_avail, rceb); - buffer_to_bmp(bmp, drp_evt->bmp, UWB_NUM_MAS/8); - result = 0; -error: - return result; -} - - -/** - * Process an incoming DRP Availability notification. - * - * @evt: Event information (packs the actual event data, which - * radio controller it came to, etc). - * - * @returns: 0 on success (so uwbd() frees the event buffer), < 0 - * on error. - * - * According to ECMA-368 1.0 [16.8.7], bits set to ONE indicate that - * the MAS slot is available, bits set to ZERO indicate that the slot - * is busy. - * - * So we clear available slots, we set used slots :) - * - * The notification only marks non-availability based on the BP and - * received DRP IEs that are not for this radio controller. A copy of - * this bitmap is needed to generate the real availability (which - * includes local and pending reservations). - * - * The DRP Availability IE that this radio controller emits will need - * to be updated. - */ -int uwbd_evt_handle_rc_drp_avail(struct uwb_event *evt) -{ - int result; - struct uwb_rc *rc = evt->rc; - DECLARE_BITMAP(bmp, UWB_NUM_MAS); - - result = uwbd_evt_get_drp_avail(evt, bmp); - if (result < 0) - return result; - - mutex_lock(&rc->rsvs_mutex); - bitmap_copy(rc->drp_avail.global, bmp, UWB_NUM_MAS); - rc->drp_avail.ie_valid = false; - uwb_rsv_handle_drp_avail_change(rc); - mutex_unlock(&rc->rsvs_mutex); - - uwb_rsv_sched_update(rc); - - return 0; -} diff --git a/drivers/uwb/drp-ie.c b/drivers/uwb/drp-ie.c deleted file mode 100644 index 4b545b41161c..000000000000 --- a/drivers/uwb/drp-ie.c +++ /dev/null @@ -1,305 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * UWB DRP IE management. - * - * Copyright (C) 2005-2006 Intel Corporation - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - */ -#include <linux/kernel.h> -#include <linux/random.h> -#include <linux/slab.h> -#include <linux/uwb.h> - -#include "uwb-internal.h" - - -/* - * Return the reason code for a reservations's DRP IE. - */ -static int uwb_rsv_reason_code(struct uwb_rsv *rsv) -{ - static const int reason_codes[] = { - [UWB_RSV_STATE_O_INITIATED] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_O_PENDING] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_O_MODIFIED] = UWB_DRP_REASON_MODIFIED, - [UWB_RSV_STATE_O_ESTABLISHED] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_O_TO_BE_MOVED] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_O_MOVE_COMBINING] = UWB_DRP_REASON_MODIFIED, - [UWB_RSV_STATE_O_MOVE_REDUCING] = UWB_DRP_REASON_MODIFIED, - [UWB_RSV_STATE_O_MOVE_EXPANDING] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_T_ACCEPTED] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_T_CONFLICT] = UWB_DRP_REASON_CONFLICT, - [UWB_RSV_STATE_T_PENDING] = UWB_DRP_REASON_PENDING, - [UWB_RSV_STATE_T_DENIED] = UWB_DRP_REASON_DENIED, - [UWB_RSV_STATE_T_RESIZED] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = UWB_DRP_REASON_CONFLICT, - [UWB_RSV_STATE_T_EXPANDING_PENDING] = UWB_DRP_REASON_PENDING, - [UWB_RSV_STATE_T_EXPANDING_DENIED] = UWB_DRP_REASON_DENIED, - }; - - return reason_codes[rsv->state]; -} - -/* - * Return the reason code for a reservations's companion DRP IE . - */ -static int uwb_rsv_companion_reason_code(struct uwb_rsv *rsv) -{ - static const int companion_reason_codes[] = { - [UWB_RSV_STATE_O_MOVE_EXPANDING] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = UWB_DRP_REASON_ACCEPTED, - [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = UWB_DRP_REASON_CONFLICT, - [UWB_RSV_STATE_T_EXPANDING_PENDING] = UWB_DRP_REASON_PENDING, - [UWB_RSV_STATE_T_EXPANDING_DENIED] = UWB_DRP_REASON_DENIED, - }; - - return companion_reason_codes[rsv->state]; -} - -/* - * Return the status bit for a reservations's DRP IE. - */ -int uwb_rsv_status(struct uwb_rsv *rsv) -{ - static const int statuses[] = { - [UWB_RSV_STATE_O_INITIATED] = 0, - [UWB_RSV_STATE_O_PENDING] = 0, - [UWB_RSV_STATE_O_MODIFIED] = 1, - [UWB_RSV_STATE_O_ESTABLISHED] = 1, - [UWB_RSV_STATE_O_TO_BE_MOVED] = 0, - [UWB_RSV_STATE_O_MOVE_COMBINING] = 1, - [UWB_RSV_STATE_O_MOVE_REDUCING] = 1, - [UWB_RSV_STATE_O_MOVE_EXPANDING] = 1, - [UWB_RSV_STATE_T_ACCEPTED] = 1, - [UWB_RSV_STATE_T_CONFLICT] = 0, - [UWB_RSV_STATE_T_PENDING] = 0, - [UWB_RSV_STATE_T_DENIED] = 0, - [UWB_RSV_STATE_T_RESIZED] = 1, - [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = 1, - [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = 1, - [UWB_RSV_STATE_T_EXPANDING_PENDING] = 1, - [UWB_RSV_STATE_T_EXPANDING_DENIED] = 1, - - }; - - return statuses[rsv->state]; -} - -/* - * Return the status bit for a reservations's companion DRP IE . - */ -int uwb_rsv_companion_status(struct uwb_rsv *rsv) -{ - static const int companion_statuses[] = { - [UWB_RSV_STATE_O_MOVE_EXPANDING] = 0, - [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = 1, - [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = 0, - [UWB_RSV_STATE_T_EXPANDING_PENDING] = 0, - [UWB_RSV_STATE_T_EXPANDING_DENIED] = 0, - }; - - return companion_statuses[rsv->state]; -} - -/* - * Allocate a DRP IE. - * - * To save having to free/allocate a DRP IE when its MAS changes, - * enough memory is allocated for the maxiumum number of DRP - * allocation fields. This gives an overhead per reservation of up to - * (UWB_NUM_ZONES - 1) * 4 = 60 octets. - */ -static struct uwb_ie_drp *uwb_drp_ie_alloc(void) -{ - struct uwb_ie_drp *drp_ie; - - drp_ie = kzalloc(struct_size(drp_ie, allocs, UWB_NUM_ZONES), - GFP_KERNEL); - if (drp_ie) - drp_ie->hdr.element_id = UWB_IE_DRP; - return drp_ie; -} - - -/* - * Fill a DRP IE's allocation fields from a MAS bitmap. - */ -static void uwb_drp_ie_from_bm(struct uwb_ie_drp *drp_ie, - struct uwb_mas_bm *mas) -{ - int z, i, num_fields = 0, next = 0; - struct uwb_drp_alloc *zones; - __le16 current_bmp; - DECLARE_BITMAP(tmp_bmp, UWB_NUM_MAS); - DECLARE_BITMAP(tmp_mas_bm, UWB_MAS_PER_ZONE); - - zones = drp_ie->allocs; - - bitmap_copy(tmp_bmp, mas->bm, UWB_NUM_MAS); - - /* Determine unique MAS bitmaps in zones from bitmap. */ - for (z = 0; z < UWB_NUM_ZONES; z++) { - bitmap_copy(tmp_mas_bm, tmp_bmp, UWB_MAS_PER_ZONE); - if (bitmap_weight(tmp_mas_bm, UWB_MAS_PER_ZONE) > 0) { - bool found = false; - current_bmp = (__le16) *tmp_mas_bm; - for (i = 0; i < next; i++) { - if (current_bmp == zones[i].mas_bm) { - zones[i].zone_bm |= 1 << z; - found = true; - break; - } - } - if (!found) { - num_fields++; - zones[next].zone_bm = 1 << z; - zones[next].mas_bm = current_bmp; - next++; - } - } - bitmap_shift_right(tmp_bmp, tmp_bmp, UWB_MAS_PER_ZONE, UWB_NUM_MAS); - } - - /* Store in format ready for transmission (le16). */ - for (i = 0; i < num_fields; i++) { - drp_ie->allocs[i].zone_bm = cpu_to_le16(zones[i].zone_bm); - drp_ie->allocs[i].mas_bm = cpu_to_le16(zones[i].mas_bm); - } - - drp_ie->hdr.length = sizeof(struct uwb_ie_drp) - sizeof(struct uwb_ie_hdr) - + num_fields * sizeof(struct uwb_drp_alloc); -} - -/** - * uwb_drp_ie_update - update a reservation's DRP IE - * @rsv: the reservation - */ -int uwb_drp_ie_update(struct uwb_rsv *rsv) -{ - struct uwb_ie_drp *drp_ie; - struct uwb_rsv_move *mv; - int unsafe; - - if (rsv->state == UWB_RSV_STATE_NONE) { - kfree(rsv->drp_ie); - rsv->drp_ie = NULL; - return 0; - } - - unsafe = rsv->mas.unsafe ? 1 : 0; - - if (rsv->drp_ie == NULL) { - rsv->drp_ie = uwb_drp_ie_alloc(); - if (rsv->drp_ie == NULL) - return -ENOMEM; - } - drp_ie = rsv->drp_ie; - - uwb_ie_drp_set_unsafe(drp_ie, unsafe); - uwb_ie_drp_set_tiebreaker(drp_ie, rsv->tiebreaker); - uwb_ie_drp_set_owner(drp_ie, uwb_rsv_is_owner(rsv)); - uwb_ie_drp_set_status(drp_ie, uwb_rsv_status(rsv)); - uwb_ie_drp_set_reason_code(drp_ie, uwb_rsv_reason_code(rsv)); - uwb_ie_drp_set_stream_index(drp_ie, rsv->stream); - uwb_ie_drp_set_type(drp_ie, rsv->type); - - if (uwb_rsv_is_owner(rsv)) { - switch (rsv->target.type) { - case UWB_RSV_TARGET_DEV: - drp_ie->dev_addr = rsv->target.dev->dev_addr; - break; - case UWB_RSV_TARGET_DEVADDR: - drp_ie->dev_addr = rsv->target.devaddr; - break; - } - } else - drp_ie->dev_addr = rsv->owner->dev_addr; - - uwb_drp_ie_from_bm(drp_ie, &rsv->mas); - - if (uwb_rsv_has_two_drp_ies(rsv)) { - mv = &rsv->mv; - if (mv->companion_drp_ie == NULL) { - mv->companion_drp_ie = uwb_drp_ie_alloc(); - if (mv->companion_drp_ie == NULL) - return -ENOMEM; - } - drp_ie = mv->companion_drp_ie; - - /* keep all the same configuration of the main drp_ie */ - memcpy(drp_ie, rsv->drp_ie, sizeof(struct uwb_ie_drp)); - - - /* FIXME: handle properly the unsafe bit */ - uwb_ie_drp_set_unsafe(drp_ie, 1); - uwb_ie_drp_set_status(drp_ie, uwb_rsv_companion_status(rsv)); - uwb_ie_drp_set_reason_code(drp_ie, uwb_rsv_companion_reason_code(rsv)); - - uwb_drp_ie_from_bm(drp_ie, &mv->companion_mas); - } - - rsv->ie_valid = true; - return 0; -} - -/* - * Set MAS bits from given MAS bitmap in a single zone of large bitmap. - * - * We are given a zone id and the MAS bitmap of bits that need to be set in - * this zone. Note that this zone may already have bits set and this only - * adds settings - we cannot simply assign the MAS bitmap contents to the - * zone contents. We iterate over the the bits (MAS) in the zone and set the - * bits that are set in the given MAS bitmap. - */ -static -void uwb_drp_ie_single_zone_to_bm(struct uwb_mas_bm *bm, u8 zone, u16 mas_bm) -{ - int mas; - u16 mas_mask; - - for (mas = 0; mas < UWB_MAS_PER_ZONE; mas++) { - mas_mask = 1 << mas; - if (mas_bm & mas_mask) - set_bit(zone * UWB_NUM_ZONES + mas, bm->bm); - } -} - -/** - * uwb_drp_ie_zones_to_bm - convert DRP allocation fields to a bitmap - * @mas: MAS bitmap that will be populated to correspond to the - * allocation fields in the DRP IE - * @drp_ie: the DRP IE that contains the allocation fields. - * - * The input format is an array of MAS allocation fields (16 bit Zone - * bitmap, 16 bit MAS bitmap) as described in [ECMA-368] section - * 16.8.6. The output is a full 256 bit MAS bitmap. - * - * We go over all the allocation fields, for each allocation field we - * know which zones are impacted. We iterate over all the zones - * impacted and call a function that will set the correct MAS bits in - * each zone. - */ -void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie) -{ - int numallocs = (drp_ie->hdr.length - 4) / 4; - const struct uwb_drp_alloc *alloc; - int cnt; - u16 zone_bm, mas_bm; - u8 zone; - u16 zone_mask; - - bitmap_zero(bm->bm, UWB_NUM_MAS); - - for (cnt = 0; cnt < numallocs; cnt++) { - alloc = &drp_ie->allocs[cnt]; - zone_bm = le16_to_cpu(alloc->zone_bm); - mas_bm = le16_to_cpu(alloc->mas_bm); - for (zone = 0; zone < UWB_NUM_ZONES; zone++) { - zone_mask = 1 << zone; - if (zone_bm & zone_mask) - uwb_drp_ie_single_zone_to_bm(bm, zone, mas_bm); - } - } -} - diff --git a/drivers/uwb/drp.c b/drivers/uwb/drp.c deleted file mode 100644 index 869987bede7b..000000000000 --- a/drivers/uwb/drp.c +++ /dev/null @@ -1,842 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Ultra Wide Band - * Dynamic Reservation Protocol handling - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - */ -#include <linux/kthread.h> -#include <linux/freezer.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include "uwb-internal.h" - - -/* DRP Conflict Actions ([ECMA-368 2nd Edition] 17.4.6) */ -enum uwb_drp_conflict_action { - /* Reservation is maintained, no action needed */ - UWB_DRP_CONFLICT_MANTAIN = 0, - - /* the device shall not transmit frames in conflicting MASs in - * the following superframe. If the device is the reservation - * target, it shall also set the Reason Code in its DRP IE to - * Conflict in its beacon in the following superframe. - */ - UWB_DRP_CONFLICT_ACT1, - - /* the device shall not set the Reservation Status bit to ONE - * and shall not transmit frames in conflicting MASs. If the - * device is the reservation target, it shall also set the - * Reason Code in its DRP IE to Conflict. - */ - UWB_DRP_CONFLICT_ACT2, - - /* the device shall not transmit frames in conflicting MASs in - * the following superframe. It shall remove the conflicting - * MASs from the reservation or set the Reservation Status to - * ZERO in its beacon in the following superframe. If the - * device is the reservation target, it shall also set the - * Reason Code in its DRP IE to Conflict. - */ - UWB_DRP_CONFLICT_ACT3, -}; - - -static void uwb_rc_set_drp_cmd_done(struct uwb_rc *rc, void *arg, - struct uwb_rceb *reply, ssize_t reply_size) -{ - struct uwb_rc_evt_set_drp_ie *r = (struct uwb_rc_evt_set_drp_ie *)reply; - unsigned long flags; - - if (r != NULL) { - if (r->bResultCode != UWB_RC_RES_SUCCESS) - dev_err(&rc->uwb_dev.dev, "SET-DRP-IE failed: %s (%d)\n", - uwb_rc_strerror(r->bResultCode), r->bResultCode); - } else - dev_err(&rc->uwb_dev.dev, "SET-DRP-IE: timeout\n"); - - spin_lock_irqsave(&rc->rsvs_lock, flags); - if (rc->set_drp_ie_pending > 1) { - rc->set_drp_ie_pending = 0; - uwb_rsv_queue_update(rc); - } else { - rc->set_drp_ie_pending = 0; - } - spin_unlock_irqrestore(&rc->rsvs_lock, flags); -} - -/** - * Construct and send the SET DRP IE - * - * @rc: UWB Host controller - * @returns: >= 0 number of bytes still available in the beacon - * < 0 errno code on error. - * - * See WUSB[8.6.2.7]: The host must set all the DRP IEs that it wants the - * device to include in its beacon at the same time. We thus have to - * traverse all reservations and include the DRP IEs of all PENDING - * and NEGOTIATED reservations in a SET DRP command for transmission. - * - * A DRP Availability IE is appended. - * - * rc->rsvs_mutex is held - * - * FIXME We currently ignore the returned value indicating the remaining space - * in beacon. This could be used to deny reservation requests earlier if - * determined that they would cause the beacon space to be exceeded. - */ -int uwb_rc_send_all_drp_ie(struct uwb_rc *rc) -{ - int result; - struct uwb_rc_cmd_set_drp_ie *cmd; - struct uwb_rsv *rsv; - struct uwb_rsv_move *mv; - int num_bytes = 0; - u8 *IEDataptr; - - result = -ENOMEM; - /* First traverse all reservations to determine memory needed. */ - list_for_each_entry(rsv, &rc->reservations, rc_node) { - if (rsv->drp_ie != NULL) { - num_bytes += rsv->drp_ie->hdr.length + 2; - if (uwb_rsv_has_two_drp_ies(rsv) && - (rsv->mv.companion_drp_ie != NULL)) { - mv = &rsv->mv; - num_bytes += - mv->companion_drp_ie->hdr.length + 2; - } - } - } - num_bytes += sizeof(rc->drp_avail.ie); - cmd = kzalloc(sizeof(*cmd) + num_bytes, GFP_KERNEL); - if (cmd == NULL) - goto error; - cmd->rccb.bCommandType = UWB_RC_CET_GENERAL; - cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_DRP_IE); - cmd->wIELength = num_bytes; - IEDataptr = (u8 *)&cmd->IEData[0]; - - /* FIXME: DRV avail IE is not always needed */ - /* put DRP avail IE first */ - memcpy(IEDataptr, &rc->drp_avail.ie, sizeof(rc->drp_avail.ie)); - IEDataptr += sizeof(struct uwb_ie_drp_avail); - - /* Next traverse all reservations to place IEs in allocated memory. */ - list_for_each_entry(rsv, &rc->reservations, rc_node) { - if (rsv->drp_ie != NULL) { - memcpy(IEDataptr, rsv->drp_ie, - rsv->drp_ie->hdr.length + 2); - IEDataptr += rsv->drp_ie->hdr.length + 2; - - if (uwb_rsv_has_two_drp_ies(rsv) && - (rsv->mv.companion_drp_ie != NULL)) { - mv = &rsv->mv; - memcpy(IEDataptr, mv->companion_drp_ie, - mv->companion_drp_ie->hdr.length + 2); - IEDataptr += - mv->companion_drp_ie->hdr.length + 2; - } - } - } - - result = uwb_rc_cmd_async(rc, "SET-DRP-IE", - &cmd->rccb, sizeof(*cmd) + num_bytes, - UWB_RC_CET_GENERAL, UWB_RC_CMD_SET_DRP_IE, - uwb_rc_set_drp_cmd_done, NULL); - - rc->set_drp_ie_pending = 1; - - kfree(cmd); -error: - return result; -} - -/* - * Evaluate the action to perform using conflict resolution rules - * - * Return a uwb_drp_conflict_action. - */ -static int evaluate_conflict_action(struct uwb_ie_drp *ext_drp_ie, int ext_beacon_slot, - struct uwb_rsv *rsv, int our_status) -{ - int our_tie_breaker = rsv->tiebreaker; - int our_type = rsv->type; - int our_beacon_slot = rsv->rc->uwb_dev.beacon_slot; - - int ext_tie_breaker = uwb_ie_drp_tiebreaker(ext_drp_ie); - int ext_status = uwb_ie_drp_status(ext_drp_ie); - int ext_type = uwb_ie_drp_type(ext_drp_ie); - - - /* [ECMA-368 2nd Edition] 17.4.6 */ - if (ext_type == UWB_DRP_TYPE_PCA && our_type == UWB_DRP_TYPE_PCA) { - return UWB_DRP_CONFLICT_MANTAIN; - } - - /* [ECMA-368 2nd Edition] 17.4.6-1 */ - if (our_type == UWB_DRP_TYPE_ALIEN_BP) { - return UWB_DRP_CONFLICT_MANTAIN; - } - - /* [ECMA-368 2nd Edition] 17.4.6-2 */ - if (ext_type == UWB_DRP_TYPE_ALIEN_BP) { - /* here we know our_type != UWB_DRP_TYPE_ALIEN_BP */ - return UWB_DRP_CONFLICT_ACT1; - } - - /* [ECMA-368 2nd Edition] 17.4.6-3 */ - if (our_status == 0 && ext_status == 1) { - return UWB_DRP_CONFLICT_ACT2; - } - - /* [ECMA-368 2nd Edition] 17.4.6-4 */ - if (our_status == 1 && ext_status == 0) { - return UWB_DRP_CONFLICT_MANTAIN; - } - - /* [ECMA-368 2nd Edition] 17.4.6-5a */ - if (our_tie_breaker == ext_tie_breaker && - our_beacon_slot < ext_beacon_slot) { - return UWB_DRP_CONFLICT_MANTAIN; - } - - /* [ECMA-368 2nd Edition] 17.4.6-5b */ - if (our_tie_breaker != ext_tie_breaker && - our_beacon_slot > ext_beacon_slot) { - return UWB_DRP_CONFLICT_MANTAIN; - } - - if (our_status == 0) { - if (our_tie_breaker == ext_tie_breaker) { - /* [ECMA-368 2nd Edition] 17.4.6-6a */ - if (our_beacon_slot > ext_beacon_slot) { - return UWB_DRP_CONFLICT_ACT2; - } - } else { - /* [ECMA-368 2nd Edition] 17.4.6-6b */ - if (our_beacon_slot < ext_beacon_slot) { - return UWB_DRP_CONFLICT_ACT2; - } - } - } else { - if (our_tie_breaker == ext_tie_breaker) { - /* [ECMA-368 2nd Edition] 17.4.6-7a */ - if (our_beacon_slot > ext_beacon_slot) { - return UWB_DRP_CONFLICT_ACT3; - } - } else { - /* [ECMA-368 2nd Edition] 17.4.6-7b */ - if (our_beacon_slot < ext_beacon_slot) { - return UWB_DRP_CONFLICT_ACT3; - } - } - } - return UWB_DRP_CONFLICT_MANTAIN; -} - -static void handle_conflict_normal(struct uwb_ie_drp *drp_ie, - int ext_beacon_slot, - struct uwb_rsv *rsv, - struct uwb_mas_bm *conflicting_mas) -{ - struct uwb_rc *rc = rsv->rc; - struct uwb_rsv_move *mv = &rsv->mv; - struct uwb_drp_backoff_win *bow = &rc->bow; - int action; - - action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, uwb_rsv_status(rsv)); - - if (uwb_rsv_is_owner(rsv)) { - switch(action) { - case UWB_DRP_CONFLICT_ACT2: - /* try move */ - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_TO_BE_MOVED); - if (bow->can_reserve_extra_mases == false) - uwb_rsv_backoff_win_increment(rc); - - break; - case UWB_DRP_CONFLICT_ACT3: - uwb_rsv_backoff_win_increment(rc); - /* drop some mases with reason modified */ - /* put in the companion the mases to be dropped */ - bitmap_and(mv->companion_mas.bm, rsv->mas.bm, conflicting_mas->bm, UWB_NUM_MAS); - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED); - default: - break; - } - } else { - switch(action) { - case UWB_DRP_CONFLICT_ACT2: - case UWB_DRP_CONFLICT_ACT3: - uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT); - default: - break; - } - - } - -} - -static void handle_conflict_expanding(struct uwb_ie_drp *drp_ie, int ext_beacon_slot, - struct uwb_rsv *rsv, bool companion_only, - struct uwb_mas_bm *conflicting_mas) -{ - struct uwb_rc *rc = rsv->rc; - struct uwb_drp_backoff_win *bow = &rc->bow; - struct uwb_rsv_move *mv = &rsv->mv; - int action; - - if (companion_only) { - /* status of companion is 0 at this point */ - action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, 0); - if (uwb_rsv_is_owner(rsv)) { - switch(action) { - case UWB_DRP_CONFLICT_ACT2: - case UWB_DRP_CONFLICT_ACT3: - uwb_rsv_set_state(rsv, - UWB_RSV_STATE_O_ESTABLISHED); - rsv->needs_release_companion_mas = false; - if (bow->can_reserve_extra_mases == false) - uwb_rsv_backoff_win_increment(rc); - uwb_drp_avail_release(rsv->rc, - &rsv->mv.companion_mas); - } - } else { /* rsv is target */ - switch(action) { - case UWB_DRP_CONFLICT_ACT2: - case UWB_DRP_CONFLICT_ACT3: - uwb_rsv_set_state(rsv, - UWB_RSV_STATE_T_EXPANDING_CONFLICT); - /* send_drp_avail_ie = true; */ - } - } - } else { /* also base part of the reservation is conflicting */ - if (uwb_rsv_is_owner(rsv)) { - uwb_rsv_backoff_win_increment(rc); - /* remove companion part */ - uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas); - - /* drop some mases with reason modified */ - - /* put in the companion the mases to be dropped */ - bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, - conflicting_mas->bm, UWB_NUM_MAS); - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED); - } else { /* it is a target rsv */ - uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT); - /* send_drp_avail_ie = true; */ - } - } -} - -static void uwb_drp_handle_conflict_rsv(struct uwb_rc *rc, struct uwb_rsv *rsv, - struct uwb_rc_evt_drp *drp_evt, - struct uwb_ie_drp *drp_ie, - struct uwb_mas_bm *conflicting_mas) -{ - struct uwb_rsv_move *mv; - - /* check if the conflicting reservation has two drp_ies */ - if (uwb_rsv_has_two_drp_ies(rsv)) { - mv = &rsv->mv; - if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm, - UWB_NUM_MAS)) { - handle_conflict_expanding(drp_ie, - drp_evt->beacon_slot_number, - rsv, false, conflicting_mas); - } else { - if (bitmap_intersects(mv->companion_mas.bm, - conflicting_mas->bm, UWB_NUM_MAS)) { - handle_conflict_expanding( - drp_ie, drp_evt->beacon_slot_number, - rsv, true, conflicting_mas); - } - } - } else if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm, - UWB_NUM_MAS)) { - handle_conflict_normal(drp_ie, drp_evt->beacon_slot_number, - rsv, conflicting_mas); - } -} - -static void uwb_drp_handle_all_conflict_rsv(struct uwb_rc *rc, - struct uwb_rc_evt_drp *drp_evt, - struct uwb_ie_drp *drp_ie, - struct uwb_mas_bm *conflicting_mas) -{ - struct uwb_rsv *rsv; - - list_for_each_entry(rsv, &rc->reservations, rc_node) { - uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie, - conflicting_mas); - } -} - -static void uwb_drp_process_target_accepted(struct uwb_rc *rc, - struct uwb_rsv *rsv, struct uwb_rc_evt_drp *drp_evt, - struct uwb_ie_drp *drp_ie, struct uwb_mas_bm *mas) -{ - struct uwb_rsv_move *mv = &rsv->mv; - int status; - - status = uwb_ie_drp_status(drp_ie); - - if (rsv->state == UWB_RSV_STATE_T_CONFLICT) { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT); - return; - } - - if (rsv->state == UWB_RSV_STATE_T_EXPANDING_ACCEPTED) { - /* drp_ie is companion */ - if (!bitmap_equal(rsv->mas.bm, mas->bm, UWB_NUM_MAS)) { - /* stroke companion */ - uwb_rsv_set_state(rsv, - UWB_RSV_STATE_T_EXPANDING_ACCEPTED); - } - } else { - if (!bitmap_equal(rsv->mas.bm, mas->bm, UWB_NUM_MAS)) { - if (uwb_drp_avail_reserve_pending(rc, mas) == -EBUSY) { - /* FIXME: there is a conflict, find - * the conflicting reservations and - * take a sensible action. Consider - * that in drp_ie there is the - * "neighbour" */ - uwb_drp_handle_all_conflict_rsv(rc, drp_evt, - drp_ie, mas); - } else { - /* accept the extra reservation */ - bitmap_copy(mv->companion_mas.bm, mas->bm, - UWB_NUM_MAS); - uwb_rsv_set_state(rsv, - UWB_RSV_STATE_T_EXPANDING_ACCEPTED); - } - } else { - if (status) { - uwb_rsv_set_state(rsv, - UWB_RSV_STATE_T_ACCEPTED); - } - } - - } -} - -/* - * Based on the DRP IE, transition a target reservation to a new - * state. - */ -static void uwb_drp_process_target(struct uwb_rc *rc, struct uwb_rsv *rsv, - struct uwb_ie_drp *drp_ie, struct uwb_rc_evt_drp *drp_evt) -{ - struct device *dev = &rc->uwb_dev.dev; - struct uwb_rsv_move *mv = &rsv->mv; - int status; - enum uwb_drp_reason reason_code; - struct uwb_mas_bm mas; - - status = uwb_ie_drp_status(drp_ie); - reason_code = uwb_ie_drp_reason_code(drp_ie); - uwb_drp_ie_to_bm(&mas, drp_ie); - - switch (reason_code) { - case UWB_DRP_REASON_ACCEPTED: - uwb_drp_process_target_accepted(rc, rsv, drp_evt, drp_ie, &mas); - break; - - case UWB_DRP_REASON_MODIFIED: - /* check to see if we have already modified the reservation */ - if (bitmap_equal(rsv->mas.bm, mas.bm, UWB_NUM_MAS)) { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED); - break; - } - - /* find if the owner wants to expand or reduce */ - if (bitmap_subset(mas.bm, rsv->mas.bm, UWB_NUM_MAS)) { - /* owner is reducing */ - bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, mas.bm, - UWB_NUM_MAS); - uwb_drp_avail_release(rsv->rc, &mv->companion_mas); - } - - bitmap_copy(rsv->mas.bm, mas.bm, UWB_NUM_MAS); - uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_RESIZED); - break; - default: - dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n", - reason_code, status); - } -} - -static void uwb_drp_process_owner_accepted(struct uwb_rsv *rsv, - struct uwb_mas_bm *mas) -{ - struct uwb_rsv_move *mv = &rsv->mv; - - switch (rsv->state) { - case UWB_RSV_STATE_O_PENDING: - case UWB_RSV_STATE_O_INITIATED: - case UWB_RSV_STATE_O_ESTABLISHED: - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); - break; - case UWB_RSV_STATE_O_MODIFIED: - if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS)) - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); - else - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED); - break; - - case UWB_RSV_STATE_O_MOVE_REDUCING: /* shouldn' t be a problem */ - if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS)) - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); - else - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING); - break; - case UWB_RSV_STATE_O_MOVE_EXPANDING: - if (bitmap_equal(mas->bm, mv->companion_mas.bm, UWB_NUM_MAS)) { - /* Companion reservation accepted */ - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING); - } else { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING); - } - break; - case UWB_RSV_STATE_O_MOVE_COMBINING: - if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS)) - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING); - else - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING); - break; - default: - break; - } -} -/* - * Based on the DRP IE, transition an owner reservation to a new - * state. - */ -static void uwb_drp_process_owner(struct uwb_rc *rc, struct uwb_rsv *rsv, - struct uwb_dev *src, struct uwb_ie_drp *drp_ie, - struct uwb_rc_evt_drp *drp_evt) -{ - struct device *dev = &rc->uwb_dev.dev; - int status; - enum uwb_drp_reason reason_code; - struct uwb_mas_bm mas; - - status = uwb_ie_drp_status(drp_ie); - reason_code = uwb_ie_drp_reason_code(drp_ie); - uwb_drp_ie_to_bm(&mas, drp_ie); - - if (status) { - switch (reason_code) { - case UWB_DRP_REASON_ACCEPTED: - uwb_drp_process_owner_accepted(rsv, &mas); - break; - default: - dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n", - reason_code, status); - } - } else { - switch (reason_code) { - case UWB_DRP_REASON_PENDING: - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_PENDING); - break; - case UWB_DRP_REASON_DENIED: - uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); - break; - case UWB_DRP_REASON_CONFLICT: - /* resolve the conflict */ - bitmap_complement(mas.bm, src->last_availability_bm, - UWB_NUM_MAS); - uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie, &mas); - break; - default: - dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n", - reason_code, status); - } - } -} - -static void uwb_cnflt_alien_stroke_timer(struct uwb_cnflt_alien *cnflt) -{ - unsigned timeout_us = UWB_MAX_LOST_BEACONS * UWB_SUPERFRAME_LENGTH_US; - mod_timer(&cnflt->timer, jiffies + usecs_to_jiffies(timeout_us)); -} - -static void uwb_cnflt_update_work(struct work_struct *work) -{ - struct uwb_cnflt_alien *cnflt = container_of(work, - struct uwb_cnflt_alien, - cnflt_update_work); - struct uwb_cnflt_alien *c; - struct uwb_rc *rc = cnflt->rc; - - unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE; - - mutex_lock(&rc->rsvs_mutex); - - list_del(&cnflt->rc_node); - - /* update rc global conflicting alien bitmap */ - bitmap_zero(rc->cnflt_alien_bitmap.bm, UWB_NUM_MAS); - - list_for_each_entry(c, &rc->cnflt_alien_list, rc_node) { - bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm, - c->mas.bm, UWB_NUM_MAS); - } - - queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work, - usecs_to_jiffies(delay_us)); - - kfree(cnflt); - mutex_unlock(&rc->rsvs_mutex); -} - -static void uwb_cnflt_timer(struct timer_list *t) -{ - struct uwb_cnflt_alien *cnflt = from_timer(cnflt, t, timer); - - queue_work(cnflt->rc->rsv_workq, &cnflt->cnflt_update_work); -} - -/* - * We have received an DRP_IE of type Alien BP and we need to make - * sure we do not transmit in conflicting MASs. - */ -static void uwb_drp_handle_alien_drp(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie) -{ - struct device *dev = &rc->uwb_dev.dev; - struct uwb_mas_bm mas; - struct uwb_cnflt_alien *cnflt; - unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE; - - uwb_drp_ie_to_bm(&mas, drp_ie); - - list_for_each_entry(cnflt, &rc->cnflt_alien_list, rc_node) { - if (bitmap_equal(cnflt->mas.bm, mas.bm, UWB_NUM_MAS)) { - /* Existing alien BP reservation conflicting - * bitmap, just reset the timer */ - uwb_cnflt_alien_stroke_timer(cnflt); - return; - } - } - - /* New alien BP reservation conflicting bitmap */ - - /* alloc and initialize new uwb_cnflt_alien */ - cnflt = kzalloc(sizeof(struct uwb_cnflt_alien), GFP_KERNEL); - if (!cnflt) { - dev_err(dev, "failed to alloc uwb_cnflt_alien struct\n"); - return; - } - - INIT_LIST_HEAD(&cnflt->rc_node); - timer_setup(&cnflt->timer, uwb_cnflt_timer, 0); - - cnflt->rc = rc; - INIT_WORK(&cnflt->cnflt_update_work, uwb_cnflt_update_work); - - bitmap_copy(cnflt->mas.bm, mas.bm, UWB_NUM_MAS); - - list_add_tail(&cnflt->rc_node, &rc->cnflt_alien_list); - - /* update rc global conflicting alien bitmap */ - bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm, mas.bm, UWB_NUM_MAS); - - queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work, usecs_to_jiffies(delay_us)); - - /* start the timer */ - uwb_cnflt_alien_stroke_timer(cnflt); -} - -static void uwb_drp_process_not_involved(struct uwb_rc *rc, - struct uwb_rc_evt_drp *drp_evt, - struct uwb_ie_drp *drp_ie) -{ - struct uwb_mas_bm mas; - - uwb_drp_ie_to_bm(&mas, drp_ie); - uwb_drp_handle_all_conflict_rsv(rc, drp_evt, drp_ie, &mas); -} - -static void uwb_drp_process_involved(struct uwb_rc *rc, struct uwb_dev *src, - struct uwb_rc_evt_drp *drp_evt, - struct uwb_ie_drp *drp_ie) -{ - struct uwb_rsv *rsv; - - rsv = uwb_rsv_find(rc, src, drp_ie); - if (!rsv) { - /* - * No reservation? It's either for a recently - * terminated reservation; or the DRP IE couldn't be - * processed (e.g., an invalid IE or out of memory). - */ - return; - } - - /* - * Do nothing with DRP IEs for reservations that have been - * terminated. - */ - if (rsv->state == UWB_RSV_STATE_NONE) { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); - return; - } - - if (uwb_ie_drp_owner(drp_ie)) - uwb_drp_process_target(rc, rsv, drp_ie, drp_evt); - else - uwb_drp_process_owner(rc, rsv, src, drp_ie, drp_evt); - -} - - -static bool uwb_drp_involves_us(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie) -{ - return uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, &drp_ie->dev_addr) == 0; -} - -/* - * Process a received DRP IE. - */ -static void uwb_drp_process(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt, - struct uwb_dev *src, struct uwb_ie_drp *drp_ie) -{ - if (uwb_ie_drp_type(drp_ie) == UWB_DRP_TYPE_ALIEN_BP) - uwb_drp_handle_alien_drp(rc, drp_ie); - else if (uwb_drp_involves_us(rc, drp_ie)) - uwb_drp_process_involved(rc, src, drp_evt, drp_ie); - else - uwb_drp_process_not_involved(rc, drp_evt, drp_ie); -} - -/* - * Process a received DRP Availability IE - */ -static void uwb_drp_availability_process(struct uwb_rc *rc, struct uwb_dev *src, - struct uwb_ie_drp_avail *drp_availability_ie) -{ - bitmap_copy(src->last_availability_bm, - drp_availability_ie->bmp, UWB_NUM_MAS); -} - -/* - * Process all the DRP IEs (both DRP IEs and the DRP Availability IE) - * from a device. - */ -static -void uwb_drp_process_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt, - size_t ielen, struct uwb_dev *src_dev) -{ - struct device *dev = &rc->uwb_dev.dev; - struct uwb_ie_hdr *ie_hdr; - void *ptr; - - ptr = drp_evt->ie_data; - for (;;) { - ie_hdr = uwb_ie_next(&ptr, &ielen); - if (!ie_hdr) - break; - - switch (ie_hdr->element_id) { - case UWB_IE_DRP_AVAILABILITY: - uwb_drp_availability_process(rc, src_dev, (struct uwb_ie_drp_avail *)ie_hdr); - break; - case UWB_IE_DRP: - uwb_drp_process(rc, drp_evt, src_dev, (struct uwb_ie_drp *)ie_hdr); - break; - default: - dev_warn(dev, "unexpected IE in DRP notification\n"); - break; - } - } - - if (ielen > 0) - dev_warn(dev, "%d octets remaining in DRP notification\n", - (int)ielen); -} - -/** - * uwbd_evt_handle_rc_drp - handle a DRP_IE event - * @evt: the DRP_IE event from the radio controller - * - * This processes DRP notifications from the radio controller, either - * initiating a new reservation or transitioning an existing - * reservation into a different state. - * - * DRP notifications can occur for three different reasons: - * - * - UWB_DRP_NOTIF_DRP_IE_RECVD: one or more DRP IEs with the RC as - * the target or source have been received. - * - * These DRP IEs could be new or for an existing reservation. - * - * If the DRP IE for an existing reservation ceases to be to - * received for at least mMaxLostBeacons, the reservation should be - * considered to be terminated. Note that the TERMINATE reason (see - * below) may not always be signalled (e.g., the remote device has - * two or more reservations established with the RC). - * - * - UWB_DRP_NOTIF_CONFLICT: DRP IEs from any device in the beacon - * group conflict with the RC's reservations. - * - * - UWB_DRP_NOTIF_TERMINATE: DRP IEs are no longer being received - * from a device (i.e., it's terminated all reservations). - * - * Only the software state of the reservations is changed; the setting - * of the radio controller's DRP IEs is done after all the events in - * an event buffer are processed. This saves waiting multiple times - * for the SET_DRP_IE command to complete. - */ -int uwbd_evt_handle_rc_drp(struct uwb_event *evt) -{ - struct device *dev = &evt->rc->uwb_dev.dev; - struct uwb_rc *rc = evt->rc; - struct uwb_rc_evt_drp *drp_evt; - size_t ielength, bytes_left; - struct uwb_dev_addr src_addr; - struct uwb_dev *src_dev; - - /* Is there enough data to decode the event (and any IEs in - its payload)? */ - if (evt->notif.size < sizeof(*drp_evt)) { - dev_err(dev, "DRP event: Not enough data to decode event " - "[%zu bytes left, %zu needed]\n", - evt->notif.size, sizeof(*drp_evt)); - return 0; - } - bytes_left = evt->notif.size - sizeof(*drp_evt); - drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp, rceb); - ielength = le16_to_cpu(drp_evt->ie_length); - if (bytes_left != ielength) { - dev_err(dev, "DRP event: Not enough data in payload [%zu" - "bytes left, %zu declared in the event]\n", - bytes_left, ielength); - return 0; - } - - memcpy(src_addr.data, &drp_evt->src_addr, sizeof(src_addr)); - src_dev = uwb_dev_get_by_devaddr(rc, &src_addr); - if (!src_dev) { - /* - * A DRP notification from an unrecognized device. - * - * This is probably from a WUSB device that doesn't - * have an EUI-48 and therefore doesn't show up in the - * UWB device database. It's safe to simply ignore - * these. - */ - return 0; - } - - mutex_lock(&rc->rsvs_mutex); - - /* We do not distinguish from the reason */ - uwb_drp_process_all(rc, drp_evt, ielength, src_dev); - - mutex_unlock(&rc->rsvs_mutex); - - uwb_dev_put(src_dev); - return 0; -} diff --git a/drivers/uwb/est.c b/drivers/uwb/est.c deleted file mode 100644 index d4141ffdd775..000000000000 --- a/drivers/uwb/est.c +++ /dev/null @@ -1,450 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Ultra Wide Band Radio Control - * Event Size Tables management - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * FIXME: docs - * - * Infrastructure, code and data tables for guessing the size of - * events received on the notification endpoints of UWB radio - * controllers. - * - * You define a table of events and for each, its size and how to get - * the extra size. - * - * ENTRY POINTS: - * - * uwb_est_{init/destroy}(): To initialize/release the EST subsystem. - * - * uwb_est_[u]register(): To un/register event size tables - * uwb_est_grow() - * - * uwb_est_find_size(): Get the size of an event - * uwb_est_get_size() - */ -#include <linux/spinlock.h> -#include <linux/slab.h> -#include <linux/export.h> - -#include "uwb-internal.h" - -struct uwb_est { - u16 type_event_high; - u16 vendor, product; - u8 entries; - const struct uwb_est_entry *entry; -}; - -static struct uwb_est *uwb_est; -static u8 uwb_est_size; -static u8 uwb_est_used; -static DEFINE_RWLOCK(uwb_est_lock); - -/** - * WUSB Standard Event Size Table, HWA-RC interface - * - * Sizes for events and notifications type 0 (general), high nibble 0. - */ -static -struct uwb_est_entry uwb_est_00_00xx[] = { - [UWB_RC_EVT_IE_RCV] = { - .size = sizeof(struct uwb_rc_evt_ie_rcv), - .offset = 1 + offsetof(struct uwb_rc_evt_ie_rcv, wIELength), - }, - [UWB_RC_EVT_BEACON] = { - .size = sizeof(struct uwb_rc_evt_beacon), - .offset = 1 + offsetof(struct uwb_rc_evt_beacon, wBeaconInfoLength), - }, - [UWB_RC_EVT_BEACON_SIZE] = { - .size = sizeof(struct uwb_rc_evt_beacon_size), - }, - [UWB_RC_EVT_BPOIE_CHANGE] = { - .size = sizeof(struct uwb_rc_evt_bpoie_change), - .offset = 1 + offsetof(struct uwb_rc_evt_bpoie_change, - wBPOIELength), - }, - [UWB_RC_EVT_BP_SLOT_CHANGE] = { - .size = sizeof(struct uwb_rc_evt_bp_slot_change), - }, - [UWB_RC_EVT_BP_SWITCH_IE_RCV] = { - .size = sizeof(struct uwb_rc_evt_bp_switch_ie_rcv), - .offset = 1 + offsetof(struct uwb_rc_evt_bp_switch_ie_rcv, wIELength), - }, - [UWB_RC_EVT_DEV_ADDR_CONFLICT] = { - .size = sizeof(struct uwb_rc_evt_dev_addr_conflict), - }, - [UWB_RC_EVT_DRP_AVAIL] = { - .size = sizeof(struct uwb_rc_evt_drp_avail) - }, - [UWB_RC_EVT_DRP] = { - .size = sizeof(struct uwb_rc_evt_drp), - .offset = 1 + offsetof(struct uwb_rc_evt_drp, ie_length), - }, - [UWB_RC_EVT_BP_SWITCH_STATUS] = { - .size = sizeof(struct uwb_rc_evt_bp_switch_status), - }, - [UWB_RC_EVT_CMD_FRAME_RCV] = { - .size = sizeof(struct uwb_rc_evt_cmd_frame_rcv), - .offset = 1 + offsetof(struct uwb_rc_evt_cmd_frame_rcv, dataLength), - }, - [UWB_RC_EVT_CHANNEL_CHANGE_IE_RCV] = { - .size = sizeof(struct uwb_rc_evt_channel_change_ie_rcv), - .offset = 1 + offsetof(struct uwb_rc_evt_channel_change_ie_rcv, wIELength), - }, - [UWB_RC_CMD_CHANNEL_CHANGE] = { - .size = sizeof(struct uwb_rc_evt_confirm), - }, - [UWB_RC_CMD_DEV_ADDR_MGMT] = { - .size = sizeof(struct uwb_rc_evt_dev_addr_mgmt) }, - [UWB_RC_CMD_GET_IE] = { - .size = sizeof(struct uwb_rc_evt_get_ie), - .offset = 1 + offsetof(struct uwb_rc_evt_get_ie, wIELength), - }, - [UWB_RC_CMD_RESET] = { - .size = sizeof(struct uwb_rc_evt_confirm), - }, - [UWB_RC_CMD_SCAN] = { - .size = sizeof(struct uwb_rc_evt_confirm), - }, - [UWB_RC_CMD_SET_BEACON_FILTER] = { - .size = sizeof(struct uwb_rc_evt_confirm), - }, - [UWB_RC_CMD_SET_DRP_IE] = { - .size = sizeof(struct uwb_rc_evt_set_drp_ie), - }, - [UWB_RC_CMD_SET_IE] = { - .size = sizeof(struct uwb_rc_evt_set_ie), - }, - [UWB_RC_CMD_SET_NOTIFICATION_FILTER] = { - .size = sizeof(struct uwb_rc_evt_confirm), - }, - [UWB_RC_CMD_SET_TX_POWER] = { - .size = sizeof(struct uwb_rc_evt_confirm), - }, - [UWB_RC_CMD_SLEEP] = { - .size = sizeof(struct uwb_rc_evt_confirm), - }, - [UWB_RC_CMD_START_BEACON] = { - .size = sizeof(struct uwb_rc_evt_confirm), - }, - [UWB_RC_CMD_STOP_BEACON] = { - .size = sizeof(struct uwb_rc_evt_confirm), - }, - [UWB_RC_CMD_BP_MERGE] = { - .size = sizeof(struct uwb_rc_evt_confirm), - }, - [UWB_RC_CMD_SEND_COMMAND_FRAME] = { - .size = sizeof(struct uwb_rc_evt_confirm), - }, - [UWB_RC_CMD_SET_ASIE_NOTIF] = { - .size = sizeof(struct uwb_rc_evt_confirm), - }, -}; - -static -struct uwb_est_entry uwb_est_01_00xx[] = { - [UWB_RC_DAA_ENERGY_DETECTED] = { - .size = sizeof(struct uwb_rc_evt_daa_energy_detected), - }, - [UWB_RC_SET_DAA_ENERGY_MASK] = { - .size = sizeof(struct uwb_rc_evt_set_daa_energy_mask), - }, - [UWB_RC_SET_NOTIFICATION_FILTER_EX] = { - .size = sizeof(struct uwb_rc_evt_set_notification_filter_ex), - }, -}; - -/** - * Initialize the EST subsystem - * - * Register the standard tables also. - * - * FIXME: tag init - */ -int uwb_est_create(void) -{ - int result; - - uwb_est_size = 2; - uwb_est_used = 0; - uwb_est = kcalloc(uwb_est_size, sizeof(uwb_est[0]), GFP_KERNEL); - if (uwb_est == NULL) - return -ENOMEM; - - result = uwb_est_register(UWB_RC_CET_GENERAL, 0, 0xffff, 0xffff, - uwb_est_00_00xx, ARRAY_SIZE(uwb_est_00_00xx)); - if (result < 0) - goto out; - result = uwb_est_register(UWB_RC_CET_EX_TYPE_1, 0, 0xffff, 0xffff, - uwb_est_01_00xx, ARRAY_SIZE(uwb_est_01_00xx)); -out: - return result; -} - - -/** Clean it up */ -void uwb_est_destroy(void) -{ - kfree(uwb_est); - uwb_est = NULL; - uwb_est_size = uwb_est_used = 0; -} - - -/** - * Double the capacity of the EST table - * - * @returns 0 if ok, < 0 errno no error. - */ -static -int uwb_est_grow(void) -{ - size_t actual_size = uwb_est_size * sizeof(uwb_est[0]); - void *new = kmalloc_array(2, actual_size, GFP_ATOMIC); - if (new == NULL) - return -ENOMEM; - memcpy(new, uwb_est, actual_size); - memset(new + actual_size, 0, actual_size); - kfree(uwb_est); - uwb_est = new; - uwb_est_size *= 2; - return 0; -} - - -/** - * Register an event size table - * - * Makes room for it if the table is full, and then inserts it in the - * right position (entries are sorted by type, event_high, vendor and - * then product). - * - * @vendor: vendor code for matching against the device (0x0000 and - * 0xffff mean any); use 0x0000 to force all to match without - * checking possible vendor specific ones, 0xfffff to match - * after checking vendor specific ones. - * - * @product: product code from that vendor; same matching rules, use - * 0x0000 for not allowing vendor specific matches, 0xffff - * for allowing. - * - * This arragement just makes the tables sort differenty. Because the - * table is sorted by growing type-event_high-vendor-product, a zero - * vendor will match before than a 0x456a vendor, that will match - * before a 0xfffff vendor. - * - * @returns 0 if ok, < 0 errno on error (-ENOENT if not found). - */ -/* FIXME: add bus type to vendor/product code */ -int uwb_est_register(u8 type, u8 event_high, u16 vendor, u16 product, - const struct uwb_est_entry *entry, size_t entries) -{ - unsigned long flags; - unsigned itr; - int result = 0; - - write_lock_irqsave(&uwb_est_lock, flags); - if (uwb_est_used == uwb_est_size) { - result = uwb_est_grow(); - if (result < 0) - goto out; - } - /* Find the right spot to insert it in */ - for (itr = 0; itr < uwb_est_used; itr++) - if (uwb_est[itr].type_event_high < type - && uwb_est[itr].vendor < vendor - && uwb_est[itr].product < product) - break; - - /* Shift others to make room for the new one? */ - if (itr < uwb_est_used) - memmove(&uwb_est[itr+1], &uwb_est[itr], uwb_est_used - itr); - uwb_est[itr].type_event_high = type << 8 | event_high; - uwb_est[itr].vendor = vendor; - uwb_est[itr].product = product; - uwb_est[itr].entry = entry; - uwb_est[itr].entries = entries; - uwb_est_used++; -out: - write_unlock_irqrestore(&uwb_est_lock, flags); - return result; -} -EXPORT_SYMBOL_GPL(uwb_est_register); - - -/** - * Unregister an event size table - * - * This just removes the specified entry and moves the ones after it - * to fill in the gap. This is needed to keep the list sorted; no - * reallocation is done to reduce the size of the table. - * - * We unregister by all the data we used to register instead of by - * pointer to the @entry array because we might have used the same - * table for a bunch of IDs (for example). - * - * @returns 0 if ok, < 0 errno on error (-ENOENT if not found). - */ -int uwb_est_unregister(u8 type, u8 event_high, u16 vendor, u16 product, - const struct uwb_est_entry *entry, size_t entries) -{ - unsigned long flags; - unsigned itr; - struct uwb_est est_cmp = { - .type_event_high = type << 8 | event_high, - .vendor = vendor, - .product = product, - .entry = entry, - .entries = entries - }; - write_lock_irqsave(&uwb_est_lock, flags); - for (itr = 0; itr < uwb_est_used; itr++) - if (!memcmp(&uwb_est[itr], &est_cmp, sizeof(est_cmp))) - goto found; - write_unlock_irqrestore(&uwb_est_lock, flags); - return -ENOENT; - -found: - if (itr < uwb_est_used - 1) /* Not last one? move ones above */ - memmove(&uwb_est[itr], &uwb_est[itr+1], uwb_est_used - itr - 1); - uwb_est_used--; - write_unlock_irqrestore(&uwb_est_lock, flags); - return 0; -} -EXPORT_SYMBOL_GPL(uwb_est_unregister); - - -/** - * Get the size of an event from a table - * - * @rceb: pointer to the buffer with the event - * @rceb_size: size of the area pointed to by @rceb in bytes. - * @returns: > 0 Size of the event - * -ENOSPC An area big enough was not provided to look - * ahead into the event's guts and guess the size. - * -EINVAL Unknown event code (wEvent). - * - * This will look at the received RCEB and guess what is the total - * size. For variable sized events, it will look further ahead into - * their length field to see how much data should be read. - * - * Note this size is *not* final--the neh (Notification/Event Handle) - * might specificy an extra size to add. - */ -static -ssize_t uwb_est_get_size(struct uwb_rc *uwb_rc, struct uwb_est *est, - u8 event_low, const struct uwb_rceb *rceb, - size_t rceb_size) -{ - unsigned offset; - ssize_t size; - struct device *dev = &uwb_rc->uwb_dev.dev; - const struct uwb_est_entry *entry; - - size = -ENOENT; - if (event_low >= est->entries) { /* in range? */ - dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: event %u out of range\n", - est, est->type_event_high, est->vendor, est->product, - est->entries, event_low); - goto out; - } - size = -ENOENT; - entry = &est->entry[event_low]; - if (entry->size == 0 && entry->offset == 0) { /* unknown? */ - dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: event %u unknown\n", - est, est->type_event_high, est->vendor, est->product, - est->entries, event_low); - goto out; - } - offset = entry->offset; /* extra fries with that? */ - if (offset == 0) - size = entry->size; - else { - /* Ops, got an extra size field at 'offset'--read it */ - const void *ptr = rceb; - size_t type_size = 0; - offset--; - size = -ENOSPC; /* enough data for more? */ - switch (entry->type) { - case UWB_EST_16: type_size = sizeof(__le16); break; - case UWB_EST_8: type_size = sizeof(u8); break; - default: BUG(); - } - if (offset + type_size > rceb_size) { - dev_err(dev, "EST %p 0x%04x/%04x/%04x[%u]: " - "not enough data to read extra size\n", - est, est->type_event_high, est->vendor, - est->product, est->entries); - goto out; - } - size = entry->size; - ptr += offset; - switch (entry->type) { - case UWB_EST_16: size += le16_to_cpu(*(__le16 *)ptr); break; - case UWB_EST_8: size += *(u8 *)ptr; break; - default: BUG(); - } - } -out: - return size; -} - - -/** - * Guesses the size of a WA event - * - * @rceb: pointer to the buffer with the event - * @rceb_size: size of the area pointed to by @rceb in bytes. - * @returns: > 0 Size of the event - * -ENOSPC An area big enough was not provided to look - * ahead into the event's guts and guess the size. - * -EINVAL Unknown event code (wEvent). - * - * This will look at the received RCEB and guess what is the total - * size by checking all the tables registered with - * uwb_est_register(). For variable sized events, it will look further - * ahead into their length field to see how much data should be read. - * - * Note this size is *not* final--the neh (Notification/Event Handle) - * might specificy an extra size to add or replace. - */ -ssize_t uwb_est_find_size(struct uwb_rc *rc, const struct uwb_rceb *rceb, - size_t rceb_size) -{ - /* FIXME: add vendor/product data */ - ssize_t size; - struct device *dev = &rc->uwb_dev.dev; - unsigned long flags; - unsigned itr; - u16 type_event_high, event; - - read_lock_irqsave(&uwb_est_lock, flags); - size = -ENOSPC; - if (rceb_size < sizeof(*rceb)) - goto out; - event = le16_to_cpu(rceb->wEvent); - type_event_high = rceb->bEventType << 8 | (event & 0xff00) >> 8; - for (itr = 0; itr < uwb_est_used; itr++) { - if (uwb_est[itr].type_event_high != type_event_high) - continue; - size = uwb_est_get_size(rc, &uwb_est[itr], - event & 0x00ff, rceb, rceb_size); - /* try more tables that might handle the same type */ - if (size != -ENOENT) - goto out; - } - dev_dbg(dev, - "event 0x%02x/%04x/%02x: no handlers available; RCEB %4ph\n", - (unsigned) rceb->bEventType, - (unsigned) le16_to_cpu(rceb->wEvent), - (unsigned) rceb->bEventContext, - rceb); - size = -ENOENT; -out: - read_unlock_irqrestore(&uwb_est_lock, flags); - return size; -} -EXPORT_SYMBOL_GPL(uwb_est_find_size); diff --git a/drivers/uwb/hwa-rc.c b/drivers/uwb/hwa-rc.c deleted file mode 100644 index cd03b7f827c1..000000000000 --- a/drivers/uwb/hwa-rc.c +++ /dev/null @@ -1,929 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * WUSB Host Wire Adapter: Radio Control Interface (WUSB[8.6]) - * Radio Control command/event transport - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * Initialize the Radio Control interface Driver. - * - * For each device probed, creates an 'struct hwarc' which contains - * just the representation of the UWB Radio Controller, and the logic - * for reading notifications and passing them to the UWB Core. - * - * So we initialize all of those, register the UWB Radio Controller - * and setup the notification/event handle to pipe the notifications - * to the UWB management Daemon. - * - * Command and event filtering. - * - * This is the driver for the Radio Control Interface described in WUSB - * 1.0. The core UWB module assumes that all drivers are compliant to the - * WHCI 0.95 specification. We thus create a filter that parses all - * incoming messages from the (WUSB 1.0) device and manipulate them to - * conform to the WHCI 0.95 specification. Similarly, outgoing messages - * are parsed and manipulated to conform to the WUSB 1.0 compliant messages - * that the device expects. Only a few messages are affected: - * Affected events: - * UWB_RC_EVT_BEACON - * UWB_RC_EVT_BP_SLOT_CHANGE - * UWB_RC_EVT_DRP_AVAIL - * UWB_RC_EVT_DRP - * Affected commands: - * UWB_RC_CMD_SCAN - * UWB_RC_CMD_SET_DRP_IE - */ -#include <linux/init.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/usb.h> -#include <linux/usb/wusb.h> -#include <linux/usb/wusb-wa.h> -#include <linux/uwb.h> - -#include "uwb-internal.h" - -/* The device uses commands and events from the WHCI specification, although - * reporting itself as WUSB compliant. */ -#define WUSB_QUIRK_WHCI_CMD_EVT 0x01 - -/** - * Descriptor for an instance of the UWB Radio Control Driver that - * attaches to the RCI interface of the Host Wired Adapter. - * - * Unless there is a lock specific to the 'data members', all access - * is protected by uwb_rc->mutex. - * - * The NEEP (Notification/Event EndPoint) URB (@neep_urb) writes to - * @rd_buffer. Note there is no locking because it is perfectly (heh!) - * serialized--probe() submits an URB, callback is called, processes - * the data (synchronously), submits another URB, and so on. There is - * no concurrent access to the buffer. - */ -struct hwarc { - struct usb_device *usb_dev; - struct usb_interface *usb_iface; - struct uwb_rc *uwb_rc; /* UWB host controller */ - struct urb *neep_urb; /* Notification endpoint handling */ - struct edc neep_edc; - void *rd_buffer; /* NEEP read buffer */ -}; - - -/* Beacon received notification (WUSB 1.0 [8.6.3.2]) */ -struct uwb_rc_evt_beacon_WUSB_0100 { - struct uwb_rceb rceb; - u8 bChannelNumber; - __le16 wBPSTOffset; - u8 bLQI; - u8 bRSSI; - __le16 wBeaconInfoLength; - u8 BeaconInfo[]; -} __attribute__((packed)); - -/** - * Filter WUSB 1.0 BEACON RCV notification to be WHCI 0.95 - * - * @header: the incoming event - * @buf_size: size of buffer containing incoming event - * @new_size: size of event after filtering completed - * - * The WHCI 0.95 spec has a "Beacon Type" field. This value is unknown at - * the time we receive the beacon from WUSB so we just set it to - * UWB_RC_BEACON_TYPE_NEIGHBOR as a default. - * The solution below allocates memory upon receipt of every beacon from a - * WUSB device. This will deteriorate performance. What is the right way to - * do this? - */ -static -int hwarc_filter_evt_beacon_WUSB_0100(struct uwb_rc *rc, - struct uwb_rceb **header, - const size_t buf_size, - size_t *new_size) -{ - struct uwb_rc_evt_beacon_WUSB_0100 *be; - struct uwb_rc_evt_beacon *newbe; - size_t bytes_left, ielength; - struct device *dev = &rc->uwb_dev.dev; - - be = container_of(*header, struct uwb_rc_evt_beacon_WUSB_0100, rceb); - bytes_left = buf_size; - if (bytes_left < sizeof(*be)) { - dev_err(dev, "Beacon Received Notification: Not enough data " - "to decode for filtering (%zu vs %zu bytes needed)\n", - bytes_left, sizeof(*be)); - return -EINVAL; - } - bytes_left -= sizeof(*be); - ielength = le16_to_cpu(be->wBeaconInfoLength); - if (bytes_left < ielength) { - dev_err(dev, "Beacon Received Notification: Not enough data " - "to decode IEs (%zu vs %zu bytes needed)\n", - bytes_left, ielength); - return -EINVAL; - } - newbe = kzalloc(sizeof(*newbe) + ielength, GFP_ATOMIC); - if (newbe == NULL) - return -ENOMEM; - newbe->rceb = be->rceb; - newbe->bChannelNumber = be->bChannelNumber; - newbe->bBeaconType = UWB_RC_BEACON_TYPE_NEIGHBOR; - newbe->wBPSTOffset = be->wBPSTOffset; - newbe->bLQI = be->bLQI; - newbe->bRSSI = be->bRSSI; - newbe->wBeaconInfoLength = be->wBeaconInfoLength; - memcpy(newbe->BeaconInfo, be->BeaconInfo, ielength); - *header = &newbe->rceb; - *new_size = sizeof(*newbe) + ielength; - return 1; /* calling function will free memory */ -} - - -/* DRP Availability change notification (WUSB 1.0 [8.6.3.8]) */ -struct uwb_rc_evt_drp_avail_WUSB_0100 { - struct uwb_rceb rceb; - __le16 wIELength; - u8 IEData[]; -} __attribute__((packed)); - -/** - * Filter WUSB 1.0 DRP AVAILABILITY CHANGE notification to be WHCI 0.95 - * - * @header: the incoming event - * @buf_size: size of buffer containing incoming event - * @new_size: size of event after filtering completed - */ -static -int hwarc_filter_evt_drp_avail_WUSB_0100(struct uwb_rc *rc, - struct uwb_rceb **header, - const size_t buf_size, - size_t *new_size) -{ - struct uwb_rc_evt_drp_avail_WUSB_0100 *da; - struct uwb_rc_evt_drp_avail *newda; - struct uwb_ie_hdr *ie_hdr; - size_t bytes_left, ielength; - struct device *dev = &rc->uwb_dev.dev; - - - da = container_of(*header, struct uwb_rc_evt_drp_avail_WUSB_0100, rceb); - bytes_left = buf_size; - if (bytes_left < sizeof(*da)) { - dev_err(dev, "Not enough data to decode DRP Avail " - "Notification for filtering. Expected %zu, " - "received %zu.\n", (size_t)sizeof(*da), bytes_left); - return -EINVAL; - } - bytes_left -= sizeof(*da); - ielength = le16_to_cpu(da->wIELength); - if (bytes_left < ielength) { - dev_err(dev, "DRP Avail Notification filter: IE length " - "[%zu bytes] does not match actual length " - "[%zu bytes].\n", ielength, bytes_left); - return -EINVAL; - } - if (ielength < sizeof(*ie_hdr)) { - dev_err(dev, "DRP Avail Notification filter: Not enough " - "data to decode IE [%zu bytes, %zu needed]\n", - ielength, sizeof(*ie_hdr)); - return -EINVAL; - } - ie_hdr = (void *) da->IEData; - if (ie_hdr->length > 32) { - dev_err(dev, "DRP Availability Change event has unexpected " - "length for filtering. Expected < 32 bytes, " - "got %zu bytes.\n", (size_t)ie_hdr->length); - return -EINVAL; - } - newda = kzalloc(sizeof(*newda), GFP_ATOMIC); - if (newda == NULL) - return -ENOMEM; - newda->rceb = da->rceb; - memcpy(newda->bmp, (u8 *) ie_hdr + sizeof(*ie_hdr), ie_hdr->length); - *header = &newda->rceb; - *new_size = sizeof(*newda); - return 1; /* calling function will free memory */ -} - - -/* DRP notification (WUSB 1.0 [8.6.3.9]) */ -struct uwb_rc_evt_drp_WUSB_0100 { - struct uwb_rceb rceb; - struct uwb_dev_addr wSrcAddr; - u8 bExplicit; - __le16 wIELength; - u8 IEData[]; -} __attribute__((packed)); - -/** - * Filter WUSB 1.0 DRP Notification to be WHCI 0.95 - * - * @header: the incoming event - * @buf_size: size of buffer containing incoming event - * @new_size: size of event after filtering completed - * - * It is hard to manage DRP reservations without having a Reason code. - * Unfortunately there is none in the WUSB spec. We just set the default to - * DRP IE RECEIVED. - * We do not currently use the bBeaconSlotNumber value, so we set this to - * zero for now. - */ -static -int hwarc_filter_evt_drp_WUSB_0100(struct uwb_rc *rc, - struct uwb_rceb **header, - const size_t buf_size, - size_t *new_size) -{ - struct uwb_rc_evt_drp_WUSB_0100 *drpev; - struct uwb_rc_evt_drp *newdrpev; - size_t bytes_left, ielength; - struct device *dev = &rc->uwb_dev.dev; - - drpev = container_of(*header, struct uwb_rc_evt_drp_WUSB_0100, rceb); - bytes_left = buf_size; - if (bytes_left < sizeof(*drpev)) { - dev_err(dev, "Not enough data to decode DRP Notification " - "for filtering. Expected %zu, received %zu.\n", - (size_t)sizeof(*drpev), bytes_left); - return -EINVAL; - } - ielength = le16_to_cpu(drpev->wIELength); - bytes_left -= sizeof(*drpev); - if (bytes_left < ielength) { - dev_err(dev, "DRP Notification filter: header length [%zu " - "bytes] does not match actual length [%zu " - "bytes].\n", ielength, bytes_left); - return -EINVAL; - } - newdrpev = kzalloc(sizeof(*newdrpev) + ielength, GFP_ATOMIC); - if (newdrpev == NULL) - return -ENOMEM; - newdrpev->rceb = drpev->rceb; - newdrpev->src_addr = drpev->wSrcAddr; - newdrpev->reason = UWB_DRP_NOTIF_DRP_IE_RCVD; - newdrpev->beacon_slot_number = 0; - newdrpev->ie_length = drpev->wIELength; - memcpy(newdrpev->ie_data, drpev->IEData, ielength); - *header = &newdrpev->rceb; - *new_size = sizeof(*newdrpev) + ielength; - return 1; /* calling function will free memory */ -} - - -/* Scan Command (WUSB 1.0 [8.6.2.5]) */ -struct uwb_rc_cmd_scan_WUSB_0100 { - struct uwb_rccb rccb; - u8 bChannelNumber; - u8 bScanState; -} __attribute__((packed)); - -/** - * Filter WHCI 0.95 SCAN command to be WUSB 1.0 SCAN command - * - * @header: command sent to device (compliant to WHCI 0.95) - * @size: size of command sent to device - * - * We only reduce the size by two bytes because the WUSB 1.0 scan command - * does not have the last field (wStarttime). Also, make sure we don't send - * the device an unexpected scan type. - */ -static -int hwarc_filter_cmd_scan_WUSB_0100(struct uwb_rc *rc, - struct uwb_rccb **header, - size_t *size) -{ - struct uwb_rc_cmd_scan *sc; - - sc = container_of(*header, struct uwb_rc_cmd_scan, rccb); - - if (sc->bScanState == UWB_SCAN_ONLY_STARTTIME) - sc->bScanState = UWB_SCAN_ONLY; - /* Don't send the last two bytes. */ - *size -= 2; - return 0; -} - - -/* SET DRP IE command (WUSB 1.0 [8.6.2.7]) */ -struct uwb_rc_cmd_set_drp_ie_WUSB_0100 { - struct uwb_rccb rccb; - u8 bExplicit; - __le16 wIELength; - struct uwb_ie_drp IEData[]; -} __attribute__((packed)); - -/** - * Filter WHCI 0.95 SET DRP IE command to be WUSB 1.0 SET DRP IE command - * - * @header: command sent to device (compliant to WHCI 0.95) - * @size: size of command sent to device - * - * WUSB has an extra bExplicit field - we assume always explicit - * negotiation so this field is set. The command expected by the device is - * thus larger than the one prepared by the driver so we need to - * reallocate memory to accommodate this. - * We trust the driver to send us the correct data so no checking is done - * on incoming data - evn though it is variable length. - */ -static -int hwarc_filter_cmd_set_drp_ie_WUSB_0100(struct uwb_rc *rc, - struct uwb_rccb **header, - size_t *size) -{ - struct uwb_rc_cmd_set_drp_ie *orgcmd; - struct uwb_rc_cmd_set_drp_ie_WUSB_0100 *cmd; - size_t ielength; - - orgcmd = container_of(*header, struct uwb_rc_cmd_set_drp_ie, rccb); - ielength = le16_to_cpu(orgcmd->wIELength); - cmd = kzalloc(sizeof(*cmd) + ielength, GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; - cmd->rccb = orgcmd->rccb; - cmd->bExplicit = 0; - cmd->wIELength = orgcmd->wIELength; - memcpy(cmd->IEData, orgcmd->IEData, ielength); - *header = &cmd->rccb; - *size = sizeof(*cmd) + ielength; - return 1; /* calling function will free memory */ -} - - -/** - * Filter data from WHCI driver to WUSB device - * - * @header: WHCI 0.95 compliant command from driver - * @size: length of command - * - * The routine managing commands to the device (uwb_rc_cmd()) will call the - * filtering function pointer (if it exists) before it passes any data to - * the device. At this time the command has been formatted according to - * WHCI 0.95 and is ready to be sent to the device. - * - * The filter function will be provided with the current command and its - * length. The function will manipulate the command if necessary and - * potentially reallocate memory for a command that needed more memory that - * the given command. If new memory was created the function will return 1 - * to indicate to the calling function that the memory need to be freed - * when not needed any more. The size will contain the new length of the - * command. - * If memory has not been allocated we rely on the original mechanisms to - * free the memory of the command - even when we reduce the value of size. - */ -static -int hwarc_filter_cmd_WUSB_0100(struct uwb_rc *rc, struct uwb_rccb **header, - size_t *size) -{ - int result; - struct uwb_rccb *rccb = *header; - int cmd = le16_to_cpu(rccb->wCommand); - switch (cmd) { - case UWB_RC_CMD_SCAN: - result = hwarc_filter_cmd_scan_WUSB_0100(rc, header, size); - break; - case UWB_RC_CMD_SET_DRP_IE: - result = hwarc_filter_cmd_set_drp_ie_WUSB_0100(rc, header, size); - break; - default: - result = -ENOANO; - break; - } - return result; -} - - -/** - * Filter data from WHCI driver to WUSB device - * - * @header: WHCI 0.95 compliant command from driver - * @size: length of command - * - * Filter commands based on which protocol the device supports. The WUSB - * errata should be the same as WHCI 0.95 so we do not filter that here - - * only WUSB 1.0. - */ -static -int hwarc_filter_cmd(struct uwb_rc *rc, struct uwb_rccb **header, - size_t *size) -{ - int result = -ENOANO; - if (rc->version == 0x0100) - result = hwarc_filter_cmd_WUSB_0100(rc, header, size); - return result; -} - - -/** - * Compute return value as sum of incoming value and value at given offset - * - * @rceb: event for which we compute the size, it contains a variable - * length field. - * @core_size: size of the "non variable" part of the event - * @offset: place in event where the length of the variable part is stored - * @buf_size: total length of buffer in which event arrived - we need to make - * sure we read the offset in memory that is still part of the event - */ -static -ssize_t hwarc_get_event_size(struct uwb_rc *rc, const struct uwb_rceb *rceb, - size_t core_size, size_t offset, - const size_t buf_size) -{ - ssize_t size = -ENOSPC; - const void *ptr = rceb; - size_t type_size = sizeof(__le16); - struct device *dev = &rc->uwb_dev.dev; - - if (offset + type_size >= buf_size) { - dev_err(dev, "Not enough data to read extra size of event " - "0x%02x/%04x/%02x, only got %zu bytes.\n", - rceb->bEventType, le16_to_cpu(rceb->wEvent), - rceb->bEventContext, buf_size); - goto out; - } - ptr += offset; - size = core_size + le16_to_cpu(*(__le16 *)ptr); -out: - return size; -} - - -/* Beacon slot change notification (WUSB 1.0 [8.6.3.5]) */ -struct uwb_rc_evt_bp_slot_change_WUSB_0100 { - struct uwb_rceb rceb; - u8 bSlotNumber; -} __attribute__((packed)); - - -/** - * Filter data from WUSB device to WHCI driver - * - * @header: incoming event - * @buf_size: size of buffer in which event arrived - * @_event_size: actual size of event in the buffer - * @new_size: size of event after filtered - * - * We don't know how the buffer is constructed - there may be more than one - * event in it so buffer length does not determine event length. We first - * determine the expected size of the incoming event. This value is passed - * back only if the actual filtering succeeded (so we know the computed - * expected size is correct). This value will be zero if - * the event did not need any filtering. - * - * WHCI interprets the BP Slot Change event's data differently than - * WUSB. The event sizes are exactly the same. The data field - * indicates the new beacon slot in which a RC is transmitting its - * beacon. The maximum value of this is 96 (wMacBPLength ECMA-368 - * 17.16 (Table 117)). We thus know that the WUSB value will not set - * the bit bNoSlot, so we don't really do anything (placeholder). - */ -static -int hwarc_filter_event_WUSB_0100(struct uwb_rc *rc, struct uwb_rceb **header, - const size_t buf_size, size_t *_real_size, - size_t *_new_size) -{ - int result = -ENOANO; - struct uwb_rceb *rceb = *header; - int event = le16_to_cpu(rceb->wEvent); - ssize_t event_size; - size_t core_size, offset; - - if (rceb->bEventType != UWB_RC_CET_GENERAL) - goto out; - switch (event) { - case UWB_RC_EVT_BEACON: - core_size = sizeof(struct uwb_rc_evt_beacon_WUSB_0100); - offset = offsetof(struct uwb_rc_evt_beacon_WUSB_0100, - wBeaconInfoLength); - event_size = hwarc_get_event_size(rc, rceb, core_size, - offset, buf_size); - if (event_size < 0) - goto out; - *_real_size = event_size; - result = hwarc_filter_evt_beacon_WUSB_0100(rc, header, - buf_size, _new_size); - break; - case UWB_RC_EVT_BP_SLOT_CHANGE: - *_new_size = *_real_size = - sizeof(struct uwb_rc_evt_bp_slot_change_WUSB_0100); - result = 0; - break; - - case UWB_RC_EVT_DRP_AVAIL: - core_size = sizeof(struct uwb_rc_evt_drp_avail_WUSB_0100); - offset = offsetof(struct uwb_rc_evt_drp_avail_WUSB_0100, - wIELength); - event_size = hwarc_get_event_size(rc, rceb, core_size, - offset, buf_size); - if (event_size < 0) - goto out; - *_real_size = event_size; - result = hwarc_filter_evt_drp_avail_WUSB_0100( - rc, header, buf_size, _new_size); - break; - - case UWB_RC_EVT_DRP: - core_size = sizeof(struct uwb_rc_evt_drp_WUSB_0100); - offset = offsetof(struct uwb_rc_evt_drp_WUSB_0100, wIELength); - event_size = hwarc_get_event_size(rc, rceb, core_size, - offset, buf_size); - if (event_size < 0) - goto out; - *_real_size = event_size; - result = hwarc_filter_evt_drp_WUSB_0100(rc, header, - buf_size, _new_size); - break; - - default: - break; - } -out: - return result; -} - -/** - * Filter data from WUSB device to WHCI driver - * - * @header: incoming event - * @buf_size: size of buffer in which event arrived - * @_event_size: actual size of event in the buffer - * @_new_size: size of event after filtered - * - * Filter events based on which protocol the device supports. The WUSB - * errata should be the same as WHCI 0.95 so we do not filter that here - - * only WUSB 1.0. - * - * If we don't handle it, we return -ENOANO (why the weird error code? - * well, so if I get it, I can pinpoint in the code that raised - * it...after all, not too many places use the higher error codes). - */ -static -int hwarc_filter_event(struct uwb_rc *rc, struct uwb_rceb **header, - const size_t buf_size, size_t *_real_size, - size_t *_new_size) -{ - int result = -ENOANO; - if (rc->version == 0x0100) - result = hwarc_filter_event_WUSB_0100( - rc, header, buf_size, _real_size, _new_size); - return result; -} - - -/** - * Execute an UWB RC command on HWA - * - * @rc: Instance of a Radio Controller that is a HWA - * @cmd: Buffer containing the RCCB and payload to execute - * @cmd_size: Size of the command buffer. - * - * NOTE: rc's mutex has to be locked - */ -static -int hwarc_cmd(struct uwb_rc *uwb_rc, const struct uwb_rccb *cmd, size_t cmd_size) -{ - struct hwarc *hwarc = uwb_rc->priv; - return usb_control_msg( - hwarc->usb_dev, usb_sndctrlpipe(hwarc->usb_dev, 0), - WA_EXEC_RC_CMD, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - 0, hwarc->usb_iface->cur_altsetting->desc.bInterfaceNumber, - (void *) cmd, cmd_size, 100 /* FIXME: this is totally arbitrary */); -} - -static -int hwarc_reset(struct uwb_rc *uwb_rc) -{ - struct hwarc *hwarc = uwb_rc->priv; - int result; - - /* device lock must be held when calling usb_reset_device. */ - result = usb_lock_device_for_reset(hwarc->usb_dev, NULL); - if (result >= 0) { - result = usb_reset_device(hwarc->usb_dev); - usb_unlock_device(hwarc->usb_dev); - } - - return result; -} - -/** - * Callback for the notification and event endpoint - * - * Check's that everything is fine and then passes the read data to - * the notification/event handling mechanism (neh). - */ -static -void hwarc_neep_cb(struct urb *urb) -{ - struct hwarc *hwarc = urb->context; - struct usb_interface *usb_iface = hwarc->usb_iface; - struct device *dev = &usb_iface->dev; - int result; - - switch (result = urb->status) { - case 0: - uwb_rc_neh_grok(hwarc->uwb_rc, urb->transfer_buffer, - urb->actual_length); - break; - case -ECONNRESET: /* Not an error, but a controlled situation; */ - case -ENOENT: /* (we killed the URB)...so, no broadcast */ - goto out; - case -ESHUTDOWN: /* going away! */ - goto out; - default: /* On general errors, retry unless it gets ugly */ - if (edc_inc(&hwarc->neep_edc, EDC_MAX_ERRORS, - EDC_ERROR_TIMEFRAME)) - goto error_exceeded; - dev_err(dev, "NEEP: URB error %d\n", urb->status); - } - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result < 0 && result != -ENODEV && result != -EPERM) { - /* ignoring unrecoverable errors */ - dev_err(dev, "NEEP: Can't resubmit URB (%d) resetting device\n", - result); - goto error; - } -out: - return; - -error_exceeded: - dev_err(dev, "NEEP: URB max acceptable errors " - "exceeded, resetting device\n"); -error: - uwb_rc_neh_error(hwarc->uwb_rc, result); - uwb_rc_reset_all(hwarc->uwb_rc); - return; -} - -static void hwarc_init(struct hwarc *hwarc) -{ - edc_init(&hwarc->neep_edc); -} - -/** - * Initialize the notification/event endpoint stuff - * - * Note this is effectively a parallel thread; it knows that - * hwarc->uwb_rc always exists because the existence of a 'hwarc' - * means that there is a reverence on the hwarc->uwb_rc (see - * _probe()), and thus _neep_cb() can execute safely. - */ -static int hwarc_neep_init(struct uwb_rc *rc) -{ - struct hwarc *hwarc = rc->priv; - struct usb_interface *iface = hwarc->usb_iface; - struct usb_device *usb_dev = interface_to_usbdev(iface); - struct device *dev = &iface->dev; - int result; - struct usb_endpoint_descriptor *epd; - - epd = &iface->cur_altsetting->endpoint[0].desc; - hwarc->rd_buffer = (void *) __get_free_page(GFP_KERNEL); - if (hwarc->rd_buffer == NULL) { - dev_err(dev, "Unable to allocate notification's read buffer\n"); - goto error_rd_buffer; - } - hwarc->neep_urb = usb_alloc_urb(0, GFP_KERNEL); - if (hwarc->neep_urb == NULL) - goto error_urb_alloc; - usb_fill_int_urb(hwarc->neep_urb, usb_dev, - usb_rcvintpipe(usb_dev, epd->bEndpointAddress), - hwarc->rd_buffer, PAGE_SIZE, - hwarc_neep_cb, hwarc, epd->bInterval); - result = usb_submit_urb(hwarc->neep_urb, GFP_ATOMIC); - if (result < 0) { - dev_err(dev, "Cannot submit notification URB: %d\n", result); - goto error_neep_submit; - } - return 0; - -error_neep_submit: - usb_free_urb(hwarc->neep_urb); - hwarc->neep_urb = NULL; -error_urb_alloc: - free_page((unsigned long)hwarc->rd_buffer); - hwarc->rd_buffer = NULL; -error_rd_buffer: - return -ENOMEM; -} - - -/** Clean up all the notification endpoint resources */ -static void hwarc_neep_release(struct uwb_rc *rc) -{ - struct hwarc *hwarc = rc->priv; - - usb_kill_urb(hwarc->neep_urb); - usb_free_urb(hwarc->neep_urb); - hwarc->neep_urb = NULL; - - free_page((unsigned long)hwarc->rd_buffer); - hwarc->rd_buffer = NULL; -} - -/** - * Get the version from class-specific descriptor - * - * NOTE: this descriptor comes with the big bundled configuration - * descriptor that includes the interfaces' and endpoints', so - * we just look for it in the cached copy kept by the USB stack. - * - * NOTE2: We convert LE fields to CPU order. - */ -static int hwarc_get_version(struct uwb_rc *rc) -{ - int result; - - struct hwarc *hwarc = rc->priv; - struct uwb_rc_control_intf_class_desc *descr; - struct device *dev = &rc->uwb_dev.dev; - struct usb_device *usb_dev = hwarc->usb_dev; - char *itr; - struct usb_descriptor_header *hdr; - size_t itr_size, actconfig_idx; - u16 version; - - actconfig_idx = (usb_dev->actconfig - usb_dev->config) / - sizeof(usb_dev->config[0]); - itr = usb_dev->rawdescriptors[actconfig_idx]; - itr_size = le16_to_cpu(usb_dev->actconfig->desc.wTotalLength); - while (itr_size >= sizeof(*hdr)) { - hdr = (struct usb_descriptor_header *) itr; - dev_dbg(dev, "Extra device descriptor: " - "type %02x/%u bytes @ %zu (%zu left)\n", - hdr->bDescriptorType, hdr->bLength, - (itr - usb_dev->rawdescriptors[actconfig_idx]), - itr_size); - if (hdr->bDescriptorType == USB_DT_CS_RADIO_CONTROL) - goto found; - itr += hdr->bLength; - itr_size -= hdr->bLength; - } - dev_err(dev, "cannot find Radio Control Interface Class descriptor\n"); - return -ENODEV; - -found: - result = -EINVAL; - if (hdr->bLength > itr_size) { /* is it available? */ - dev_err(dev, "incomplete Radio Control Interface Class " - "descriptor (%zu bytes left, %u needed)\n", - itr_size, hdr->bLength); - goto error; - } - if (hdr->bLength < sizeof(*descr)) { - dev_err(dev, "short Radio Control Interface Class " - "descriptor\n"); - goto error; - } - descr = (struct uwb_rc_control_intf_class_desc *) hdr; - /* Make LE fields CPU order */ - version = __le16_to_cpu(descr->bcdRCIVersion); - if (version != 0x0100) { - dev_err(dev, "Device reports protocol version 0x%04x. We " - "do not support that. \n", version); - result = -EINVAL; - goto error; - } - rc->version = version; - dev_dbg(dev, "Device supports WUSB protocol version 0x%04x \n", rc->version); - result = 0; -error: - return result; -} - -/* - * By creating a 'uwb_rc', we have a reference on it -- that reference - * is the one we drop when we disconnect. - * - * No need to switch altsettings; according to WUSB1.0[8.6.1.1], there - * is only one altsetting allowed. - */ -static int hwarc_probe(struct usb_interface *iface, - const struct usb_device_id *id) -{ - int result; - struct uwb_rc *uwb_rc; - struct hwarc *hwarc; - struct device *dev = &iface->dev; - - if (iface->cur_altsetting->desc.bNumEndpoints < 1) - return -ENODEV; - if (!usb_endpoint_xfer_int(&iface->cur_altsetting->endpoint[0].desc)) - return -ENODEV; - - result = -ENOMEM; - uwb_rc = uwb_rc_alloc(); - if (uwb_rc == NULL) { - dev_err(dev, "unable to allocate RC instance\n"); - goto error_rc_alloc; - } - hwarc = kzalloc(sizeof(*hwarc), GFP_KERNEL); - if (hwarc == NULL) { - dev_err(dev, "unable to allocate HWA RC instance\n"); - goto error_alloc; - } - hwarc_init(hwarc); - hwarc->usb_dev = usb_get_dev(interface_to_usbdev(iface)); - hwarc->usb_iface = usb_get_intf(iface); - hwarc->uwb_rc = uwb_rc; - - uwb_rc->owner = THIS_MODULE; - uwb_rc->start = hwarc_neep_init; - uwb_rc->stop = hwarc_neep_release; - uwb_rc->cmd = hwarc_cmd; - uwb_rc->reset = hwarc_reset; - if (id->driver_info & WUSB_QUIRK_WHCI_CMD_EVT) { - uwb_rc->filter_cmd = NULL; - uwb_rc->filter_event = NULL; - } else { - uwb_rc->filter_cmd = hwarc_filter_cmd; - uwb_rc->filter_event = hwarc_filter_event; - } - - result = uwb_rc_add(uwb_rc, dev, hwarc); - if (result < 0) - goto error_rc_add; - result = hwarc_get_version(uwb_rc); - if (result < 0) { - dev_err(dev, "cannot retrieve version of RC \n"); - goto error_get_version; - } - usb_set_intfdata(iface, hwarc); - return 0; - -error_get_version: - uwb_rc_rm(uwb_rc); -error_rc_add: - usb_put_intf(iface); - usb_put_dev(hwarc->usb_dev); - kfree(hwarc); -error_alloc: - uwb_rc_put(uwb_rc); -error_rc_alloc: - return result; -} - -static void hwarc_disconnect(struct usb_interface *iface) -{ - struct hwarc *hwarc = usb_get_intfdata(iface); - struct uwb_rc *uwb_rc = hwarc->uwb_rc; - - usb_set_intfdata(hwarc->usb_iface, NULL); - uwb_rc_rm(uwb_rc); - usb_put_intf(hwarc->usb_iface); - usb_put_dev(hwarc->usb_dev); - kfree(hwarc); - uwb_rc_put(uwb_rc); /* when creating the device, refcount = 1 */ -} - -static int hwarc_pre_reset(struct usb_interface *iface) -{ - struct hwarc *hwarc = usb_get_intfdata(iface); - struct uwb_rc *uwb_rc = hwarc->uwb_rc; - - uwb_rc_pre_reset(uwb_rc); - return 0; -} - -static int hwarc_post_reset(struct usb_interface *iface) -{ - struct hwarc *hwarc = usb_get_intfdata(iface); - struct uwb_rc *uwb_rc = hwarc->uwb_rc; - - return uwb_rc_post_reset(uwb_rc); -} - -/** USB device ID's that we handle */ -static const struct usb_device_id hwarc_id_table[] = { - /* D-Link DUB-1210 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3d02, 0xe0, 0x01, 0x02), - .driver_info = WUSB_QUIRK_WHCI_CMD_EVT }, - /* Intel i1480 (using firmware 1.3PA2-20070828) */ - { USB_DEVICE_AND_INTERFACE_INFO(0x8086, 0x0c3b, 0xe0, 0x01, 0x02), - .driver_info = WUSB_QUIRK_WHCI_CMD_EVT }, - /* Alereon 5310 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x01, 0x02), - .driver_info = WUSB_QUIRK_WHCI_CMD_EVT }, - /* Alereon 5611 */ - { USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5611, 0xe0, 0x01, 0x02), - .driver_info = WUSB_QUIRK_WHCI_CMD_EVT }, - /* Generic match for the Radio Control interface */ - { USB_INTERFACE_INFO(0xe0, 0x01, 0x02), }, - { }, -}; -MODULE_DEVICE_TABLE(usb, hwarc_id_table); - -static struct usb_driver hwarc_driver = { - .name = "hwa-rc", - .id_table = hwarc_id_table, - .probe = hwarc_probe, - .disconnect = hwarc_disconnect, - .pre_reset = hwarc_pre_reset, - .post_reset = hwarc_post_reset, -}; - -module_usb_driver(hwarc_driver); - -MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); -MODULE_DESCRIPTION("Host Wireless Adapter Radio Control Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/uwb/i1480/Makefile b/drivers/uwb/i1480/Makefile deleted file mode 100644 index d26fb9b845ae..000000000000 --- a/drivers/uwb/i1480/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_UWB_I1480U) += dfu/ i1480-est.o diff --git a/drivers/uwb/i1480/dfu/Makefile b/drivers/uwb/i1480/dfu/Makefile deleted file mode 100644 index 4739fdac5922..000000000000 --- a/drivers/uwb/i1480/dfu/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_UWB_I1480U) += i1480-dfu-usb.o - -i1480-dfu-usb-objs := \ - dfu.o \ - mac.o \ - phy.o \ - usb.o - - diff --git a/drivers/uwb/i1480/dfu/dfu.c b/drivers/uwb/i1480/dfu/dfu.c deleted file mode 100644 index ec1af858ead9..000000000000 --- a/drivers/uwb/i1480/dfu/dfu.c +++ /dev/null @@ -1,198 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Wireless UWB Link 1480 - * Main driver - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * Common code for firmware upload used by the USB and PCI version; - * i1480_fw_upload() takes a device descriptor and uses the function - * pointers it provides to upload firmware and prepare the PHY. - * - * As well, provides common functions used by the rest of the code. - */ -#include "i1480-dfu.h" -#include <linux/errno.h> -#include <linux/delay.h> -#include <linux/pci.h> -#include <linux/device.h> -#include <linux/uwb.h> -#include <linux/random.h> -#include <linux/export.h> - -/* - * i1480_rceb_check - Check RCEB for expected field values - * @i1480: pointer to device for which RCEB is being checked - * @rceb: RCEB being checked - * @cmd: which command the RCEB is related to - * @context: expected context - * @expected_type: expected event type - * @expected_event: expected event - * - * If @cmd is NULL, do not print error messages, but still return an error - * code. - * - * Return 0 if @rceb matches the expected values, -EINVAL otherwise. - */ -int i1480_rceb_check(const struct i1480 *i1480, const struct uwb_rceb *rceb, - const char *cmd, u8 context, u8 expected_type, - unsigned expected_event) -{ - int result = 0; - struct device *dev = i1480->dev; - if (rceb->bEventContext != context) { - if (cmd) - dev_err(dev, "%s: unexpected context id 0x%02x " - "(expected 0x%02x)\n", cmd, - rceb->bEventContext, context); - result = -EINVAL; - } - if (rceb->bEventType != expected_type) { - if (cmd) - dev_err(dev, "%s: unexpected event type 0x%02x " - "(expected 0x%02x)\n", cmd, - rceb->bEventType, expected_type); - result = -EINVAL; - } - if (le16_to_cpu(rceb->wEvent) != expected_event) { - if (cmd) - dev_err(dev, "%s: unexpected event 0x%04x " - "(expected 0x%04x)\n", cmd, - le16_to_cpu(rceb->wEvent), expected_event); - result = -EINVAL; - } - return result; -} -EXPORT_SYMBOL_GPL(i1480_rceb_check); - - -/* - * Execute a Radio Control Command - * - * Command data has to be in i1480->cmd_buf. - * - * @returns size of the reply data filled in i1480->evt_buf or < 0 errno - * code on error. - */ -ssize_t i1480_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size, - size_t reply_size) -{ - ssize_t result; - struct uwb_rceb *reply = i1480->evt_buf; - struct uwb_rccb *cmd = i1480->cmd_buf; - u16 expected_event = reply->wEvent; - u8 expected_type = reply->bEventType; - u8 context; - - init_completion(&i1480->evt_complete); - i1480->evt_result = -EINPROGRESS; - do { - get_random_bytes(&context, 1); - } while (context == 0x00 || context == 0xff); - cmd->bCommandContext = context; - result = i1480->cmd(i1480, cmd_name, cmd_size); - if (result < 0) - goto error; - /* wait for the callback to report a event was received */ - result = wait_for_completion_interruptible_timeout( - &i1480->evt_complete, HZ); - if (result == 0) { - result = -ETIMEDOUT; - goto error; - } - if (result < 0) - goto error; - result = i1480->evt_result; - if (result < 0) { - dev_err(i1480->dev, "%s: command reply reception failed: %zd\n", - cmd_name, result); - goto error; - } - /* - * Firmware versions >= 1.4.12224 for IOGear GUWA100U generate a - * spurious notification after firmware is downloaded. So check whether - * the receibed RCEB is such notification before assuming that the - * command has failed. - */ - if (i1480_rceb_check(i1480, i1480->evt_buf, NULL, - 0, 0xfd, 0x0022) == 0) { - /* Now wait for the actual RCEB for this command. */ - result = i1480->wait_init_done(i1480); - if (result < 0) - goto error; - result = i1480->evt_result; - } - if (result != reply_size) { - dev_err(i1480->dev, "%s returned only %zu bytes, %zu expected\n", - cmd_name, result, reply_size); - result = -EINVAL; - goto error; - } - /* Verify we got the right event in response */ - result = i1480_rceb_check(i1480, i1480->evt_buf, cmd_name, context, - expected_type, expected_event); -error: - return result; -} -EXPORT_SYMBOL_GPL(i1480_cmd); - - -static -int i1480_print_state(struct i1480 *i1480) -{ - int result; - u32 *buf = (u32 *) i1480->cmd_buf; - - result = i1480->read(i1480, 0x80080000, 2 * sizeof(*buf)); - if (result < 0) { - dev_err(i1480->dev, "cannot read U & L states: %d\n", result); - goto error; - } - dev_info(i1480->dev, "state U 0x%08x, L 0x%08x\n", buf[0], buf[1]); -error: - return result; -} - - -/* - * PCI probe, firmware uploader - * - * _mac_fw_upload() will call rc_setup(), which needs an rc_release(). - */ -int i1480_fw_upload(struct i1480 *i1480) -{ - int result; - - result = i1480_pre_fw_upload(i1480); /* PHY pre fw */ - if (result < 0 && result != -ENOENT) { - i1480_print_state(i1480); - goto error; - } - result = i1480_mac_fw_upload(i1480); /* MAC fw */ - if (result < 0) { - if (result == -ENOENT) - dev_err(i1480->dev, "Cannot locate MAC FW file '%s'\n", - i1480->mac_fw_name); - else - i1480_print_state(i1480); - goto error; - } - result = i1480_phy_fw_upload(i1480); /* PHY fw */ - if (result < 0 && result != -ENOENT) { - i1480_print_state(i1480); - goto error_rc_release; - } - /* - * FIXME: find some reliable way to check whether firmware is running - * properly. Maybe use some standard request that has no side effects? - */ - dev_info(i1480->dev, "firmware uploaded successfully\n"); -error_rc_release: - if (i1480->rc_release) - i1480->rc_release(i1480); - result = 0; -error: - return result; -} -EXPORT_SYMBOL_GPL(i1480_fw_upload); diff --git a/drivers/uwb/i1480/dfu/i1480-dfu.h b/drivers/uwb/i1480/dfu/i1480-dfu.h deleted file mode 100644 index 9dd567d174b3..000000000000 --- a/drivers/uwb/i1480/dfu/i1480-dfu.h +++ /dev/null @@ -1,246 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * i1480 Device Firmware Upload - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * This driver is the firmware uploader for the Intel Wireless UWB - * Link 1480 device (both in the USB and PCI incarnations). - * - * The process is quite simple: we stop the device, write the firmware - * to its memory and then restart it. Wait for the device to let us - * know it is done booting firmware. Ready. - * - * We might have to upload before or after a phy firmware (which might - * be done in two methods, using a normal firmware image or through - * the MPI port). - * - * Because USB and PCI use common methods, we just make ops out of the - * common operations (read, write, wait_init_done and cmd) and - * implement them in usb.c and pci.c. - * - * The flow is (some parts omitted): - * - * i1480_{usb,pci}_probe() On enumerate/discovery - * i1480_fw_upload() - * i1480_pre_fw_upload() - * __mac_fw_upload() - * fw_hdrs_load() - * mac_fw_hdrs_push() - * i1480->write() [i1480_{usb,pci}_write()] - * i1480_fw_cmp() - * i1480->read() [i1480_{usb,pci}_read()] - * i1480_mac_fw_upload() - * __mac_fw_upload() - * i1480->setup(() - * i1480->wait_init_done() - * i1480_cmd_reset() - * i1480->cmd() [i1480_{usb,pci}_cmd()] - * ... - * i1480_phy_fw_upload() - * request_firmware() - * i1480_mpi_write() - * i1480->cmd() [i1480_{usb,pci}_cmd()] - * - * Once the probe function enumerates the device and uploads the - * firmware, we just exit with -ENODEV, as we don't really want to - * attach to the device. - */ -#ifndef __i1480_DFU_H__ -#define __i1480_DFU_H__ - -#include <linux/uwb/spec.h> -#include <linux/types.h> -#include <linux/completion.h> - -#define i1480_FW_UPLOAD_MODE_MASK (cpu_to_le32(0x00000018)) - -#if i1480_FW > 0x00000302 -#define i1480_RCEB_EXTENDED -#endif - -struct uwb_rccb; -struct uwb_rceb; - -/* - * Common firmware upload handlers - * - * Normally you embed this struct in another one specific to your hw. - * - * @write Write to device's memory from buffer. - * @read Read from device's memory to i1480->evt_buf. - * @setup Setup device after basic firmware is uploaded - * @wait_init_done - * Wait for the device to send a notification saying init - * is done. - * @cmd FOP for issuing the command to the hardware. The - * command data is contained in i1480->cmd_buf and the size - * is supplied as an argument. The command replied is put - * in i1480->evt_buf and the size in i1480->evt_result (or if - * an error, a < 0 errno code). - * - * @cmd_buf Memory buffer used to send commands to the device. - * Allocated by the upper layers i1480_fw_upload(). - * Size has to be @buf_size. - * @evt_buf Memory buffer used to place the async notifications - * received by the hw. Allocated by the upper layers - * i1480_fw_upload(). - * Size has to be @buf_size. - * @cmd_complete - * Low level driver uses this to notify code waiting afor - * an event that the event has arrived and data is in - * i1480->evt_buf (and size/result in i1480->evt_result). - * @hw_rev - * Use this value to activate dfu code to support new revisions - * of hardware. i1480_init() sets this to a default value. - * It should be updated by the USB and PCI code. - */ -struct i1480 { - struct device *dev; - - int (*write)(struct i1480 *, u32 addr, const void *, size_t); - int (*read)(struct i1480 *, u32 addr, size_t); - int (*rc_setup)(struct i1480 *); - void (*rc_release)(struct i1480 *); - int (*wait_init_done)(struct i1480 *); - int (*cmd)(struct i1480 *, const char *cmd_name, size_t cmd_size); - const char *pre_fw_name; - const char *mac_fw_name; - const char *mac_fw_name_deprecate; /* FIXME: Will go away */ - const char *phy_fw_name; - u8 hw_rev; - - size_t buf_size; /* size of both evt_buf and cmd_buf */ - void *evt_buf, *cmd_buf; - ssize_t evt_result; - struct completion evt_complete; -}; - -static inline -void i1480_init(struct i1480 *i1480) -{ - i1480->hw_rev = 1; - init_completion(&i1480->evt_complete); -} - -extern int i1480_fw_upload(struct i1480 *); -extern int i1480_pre_fw_upload(struct i1480 *); -extern int i1480_mac_fw_upload(struct i1480 *); -extern int i1480_phy_fw_upload(struct i1480 *); -extern ssize_t i1480_cmd(struct i1480 *, const char *, size_t, size_t); -extern int i1480_rceb_check(const struct i1480 *, - const struct uwb_rceb *, const char *, u8, - u8, unsigned); - -enum { - /* Vendor specific command type */ - i1480_CET_VS1 = 0xfd, - /* i1480 commands */ - i1480_CMD_SET_IP_MAS = 0x000e, - i1480_CMD_GET_MAC_PHY_INFO = 0x0003, - i1480_CMD_MPI_WRITE = 0x000f, - i1480_CMD_MPI_READ = 0x0010, - /* i1480 events */ -#if i1480_FW > 0x00000302 - i1480_EVT_CONFIRM = 0x0002, - i1480_EVT_RM_INIT_DONE = 0x0101, - i1480_EVT_DEV_ADD = 0x0103, - i1480_EVT_DEV_RM = 0x0104, - i1480_EVT_DEV_ID_CHANGE = 0x0105, - i1480_EVT_GET_MAC_PHY_INFO = i1480_CMD_GET_MAC_PHY_INFO, -#else - i1480_EVT_CONFIRM = 0x0002, - i1480_EVT_RM_INIT_DONE = 0x0101, - i1480_EVT_DEV_ADD = 0x0103, - i1480_EVT_DEV_RM = 0x0104, - i1480_EVT_DEV_ID_CHANGE = 0x0105, - i1480_EVT_GET_MAC_PHY_INFO = i1480_EVT_CONFIRM, -#endif -}; - - -struct i1480_evt_confirm { - struct uwb_rceb rceb; -#ifdef i1480_RCEB_EXTENDED - __le16 wParamLength; -#endif - u8 bResultCode; -} __attribute__((packed)); - - -struct i1480_rceb { - struct uwb_rceb rceb; -#ifdef i1480_RCEB_EXTENDED - __le16 wParamLength; -#endif -} __attribute__((packed)); - - -/** - * Get MAC & PHY Information confirm event structure - * - * Confirm event returned by the command. - */ -struct i1480_evt_confirm_GMPI { -#if i1480_FW > 0x00000302 - struct uwb_rceb rceb; - __le16 wParamLength; - __le16 status; - u8 mac_addr[6]; /* EUI-64 bit IEEE address [still 8 bytes?] */ - u8 dev_addr[2]; - __le16 mac_fw_rev; /* major = v >> 8; minor = v & 0xff */ - u8 hw_rev; - u8 phy_vendor; - u8 phy_rev; /* major v = >> 8; minor = v & 0xff */ - __le16 mac_caps; - u8 phy_caps[3]; - u8 key_stores; - __le16 mcast_addr_stores; - u8 sec_mode_supported; -#else - struct uwb_rceb rceb; - u8 status; - u8 mac_addr[8]; /* EUI-64 bit IEEE address [still 8 bytes?] */ - u8 dev_addr[2]; - __le16 mac_fw_rev; /* major = v >> 8; minor = v & 0xff */ - __le16 phy_fw_rev; /* major v = >> 8; minor = v & 0xff */ - __le16 mac_caps; - u8 phy_caps; - u8 key_stores; - __le16 mcast_addr_stores; - u8 sec_mode_supported; -#endif -} __attribute__((packed)); - - -struct i1480_cmd_mpi_write { - struct uwb_rccb rccb; - __le16 size; - u8 data[]; -}; - - -struct i1480_cmd_mpi_read { - struct uwb_rccb rccb; - __le16 size; - struct { - u8 page, offset; - } __attribute__((packed)) data[]; -} __attribute__((packed)); - - -struct i1480_evt_mpi_read { - struct uwb_rceb rceb; -#ifdef i1480_RCEB_EXTENDED - __le16 wParamLength; -#endif - u8 bResultCode; - __le16 size; - struct { - u8 page, offset, value; - } __attribute__((packed)) data[]; -} __attribute__((packed)); - - -#endif /* #ifndef __i1480_DFU_H__ */ diff --git a/drivers/uwb/i1480/dfu/mac.c b/drivers/uwb/i1480/dfu/mac.c deleted file mode 100644 index ddc224f01a7f..000000000000 --- a/drivers/uwb/i1480/dfu/mac.c +++ /dev/null @@ -1,496 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Wireless UWB Link 1480 - * MAC Firmware upload implementation - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * Implementation of the code for parsing the firmware file (extract - * the headers and binary code chunks) in the fw_*() functions. The - * code to upload pre and mac firmwares is the same, so it uses a - * common entry point in __mac_fw_upload(), which uses the i1480 - * function pointers to push the firmware to the device. - */ -#include <linux/delay.h> -#include <linux/firmware.h> -#include <linux/slab.h> -#include <linux/uwb.h> -#include "i1480-dfu.h" - -/* - * Descriptor for a continuous segment of MAC fw data - */ -struct fw_hdr { - unsigned long address; - size_t length; - const u32 *bin; - struct fw_hdr *next; -}; - - -/* Free a chain of firmware headers */ -static -void fw_hdrs_free(struct fw_hdr *hdr) -{ - struct fw_hdr *next; - - while (hdr) { - next = hdr->next; - kfree(hdr); - hdr = next; - } -} - - -/* Fill a firmware header descriptor from a memory buffer */ -static -int fw_hdr_load(struct i1480 *i1480, struct fw_hdr *hdr, unsigned hdr_cnt, - const char *_data, const u32 *data_itr, const u32 *data_top) -{ - size_t hdr_offset = (const char *) data_itr - _data; - size_t remaining_size = (void *) data_top - (void *) data_itr; - if (data_itr + 2 > data_top) { - dev_err(i1480->dev, "fw hdr #%u/%zu: EOF reached in header at " - "offset %zu, limit %zu\n", - hdr_cnt, hdr_offset, - (const char *) data_itr + 2 - _data, - (const char *) data_top - _data); - return -EINVAL; - } - hdr->next = NULL; - hdr->address = le32_to_cpu(*data_itr++); - hdr->length = le32_to_cpu(*data_itr++); - hdr->bin = data_itr; - if (hdr->length > remaining_size) { - dev_err(i1480->dev, "fw hdr #%u/%zu: EOF reached in data; " - "chunk too long (%zu bytes), only %zu left\n", - hdr_cnt, hdr_offset, hdr->length, remaining_size); - return -EINVAL; - } - return 0; -} - - -/** - * Get a buffer where the firmware is supposed to be and create a - * chain of headers linking them together. - * - * @phdr: where to place the pointer to the first header (headers link - * to the next via the @hdr->next ptr); need to free the whole - * chain when done. - * - * @_data: Pointer to the data buffer. - * - * @_data_size: Size of the data buffer (bytes); data size has to be a - * multiple of 4. Function will fail if not. - * - * Goes over the whole binary blob; reads the first chunk and creates - * a fw hdr from it (which points to where the data is in @_data and - * the length of the chunk); then goes on to the next chunk until - * done. Each header is linked to the next. - */ -static -int fw_hdrs_load(struct i1480 *i1480, struct fw_hdr **phdr, - const char *_data, size_t data_size) -{ - int result; - unsigned hdr_cnt = 0; - u32 *data = (u32 *) _data, *data_itr, *data_top; - struct fw_hdr *hdr, **prev_hdr = phdr; - - result = -EINVAL; - /* Check size is ok and pointer is aligned */ - if (data_size % sizeof(u32) != 0) - goto error; - if ((unsigned long) _data % sizeof(u16) != 0) - goto error; - *phdr = NULL; - data_itr = data; - data_top = (u32 *) (_data + data_size); - while (data_itr < data_top) { - result = -ENOMEM; - hdr = kmalloc(sizeof(*hdr), GFP_KERNEL); - if (hdr == NULL) { - dev_err(i1480->dev, "Cannot allocate fw header " - "for chunk #%u\n", hdr_cnt); - goto error_alloc; - } - result = fw_hdr_load(i1480, hdr, hdr_cnt, - _data, data_itr, data_top); - if (result < 0) - goto error_load; - data_itr += 2 + hdr->length; - *prev_hdr = hdr; - prev_hdr = &hdr->next; - hdr_cnt++; - }; - *prev_hdr = NULL; - return 0; - -error_load: - kfree(hdr); -error_alloc: - fw_hdrs_free(*phdr); -error: - return result; -} - - -/** - * Compares a chunk of fw with one in the devices's memory - * - * @i1480: Device instance - * @hdr: Pointer to the firmware chunk - * @returns: 0 if equal, < 0 errno on error. If > 0, it is the offset - * where the difference was found (plus one). - * - * Kind of dirty and simplistic, but does the trick in both the PCI - * and USB version. We do a quick[er] memcmp(), and if it fails, we do - * a byte-by-byte to find the offset. - */ -static -ssize_t i1480_fw_cmp(struct i1480 *i1480, struct fw_hdr *hdr) -{ - ssize_t result = 0; - u32 src_itr = 0, cnt; - size_t size = hdr->length*sizeof(hdr->bin[0]); - size_t chunk_size; - u8 *bin = (u8 *) hdr->bin; - - while (size > 0) { - chunk_size = size < i1480->buf_size ? size : i1480->buf_size; - result = i1480->read(i1480, hdr->address + src_itr, chunk_size); - if (result < 0) { - dev_err(i1480->dev, "error reading for verification: " - "%zd\n", result); - goto error; - } - if (memcmp(i1480->cmd_buf, bin + src_itr, result)) { - u8 *buf = i1480->cmd_buf; - for (cnt = 0; cnt < result; cnt++) - if (bin[src_itr + cnt] != buf[cnt]) { - dev_err(i1480->dev, "byte failed at " - "src_itr %u cnt %u [0x%02x " - "vs 0x%02x]\n", src_itr, cnt, - bin[src_itr + cnt], buf[cnt]); - result = src_itr + cnt + 1; - goto cmp_failed; - } - } - src_itr += result; - size -= result; - } - result = 0; -error: -cmp_failed: - return result; -} - - -/** - * Writes firmware headers to the device. - * - * @prd: PRD instance - * @hdr: Processed firmware - * @returns: 0 if ok, < 0 errno on error. - */ -static -int mac_fw_hdrs_push(struct i1480 *i1480, struct fw_hdr *hdr, - const char *fw_name, const char *fw_tag) -{ - struct device *dev = i1480->dev; - ssize_t result = 0; - struct fw_hdr *hdr_itr; - int verif_retry_count; - - /* Now, header by header, push them to the hw */ - for (hdr_itr = hdr; hdr_itr != NULL; hdr_itr = hdr_itr->next) { - verif_retry_count = 0; -retry: - dev_dbg(dev, "fw chunk (%zu @ 0x%08lx)\n", - hdr_itr->length * sizeof(hdr_itr->bin[0]), - hdr_itr->address); - result = i1480->write(i1480, hdr_itr->address, hdr_itr->bin, - hdr_itr->length*sizeof(hdr_itr->bin[0])); - if (result < 0) { - dev_err(dev, "%s fw '%s': write failed (%zuB @ 0x%lx):" - " %zd\n", fw_tag, fw_name, - hdr_itr->length * sizeof(hdr_itr->bin[0]), - hdr_itr->address, result); - break; - } - result = i1480_fw_cmp(i1480, hdr_itr); - if (result < 0) { - dev_err(dev, "%s fw '%s': verification read " - "failed (%zuB @ 0x%lx): %zd\n", - fw_tag, fw_name, - hdr_itr->length * sizeof(hdr_itr->bin[0]), - hdr_itr->address, result); - break; - } - if (result > 0) { /* Offset where it failed + 1 */ - result--; - dev_err(dev, "%s fw '%s': WARNING: verification " - "failed at 0x%lx: retrying\n", - fw_tag, fw_name, hdr_itr->address + result); - if (++verif_retry_count < 3) - goto retry; /* write this block again! */ - dev_err(dev, "%s fw '%s': verification failed at 0x%lx: " - "tried %d times\n", fw_tag, fw_name, - hdr_itr->address + result, verif_retry_count); - result = -EINVAL; - break; - } - } - return result; -} - - -/** Puts the device in firmware upload mode.*/ -static -int mac_fw_upload_enable(struct i1480 *i1480) -{ - int result; - u32 reg = 0x800000c0; - u32 *buffer = (u32 *)i1480->cmd_buf; - - if (i1480->hw_rev > 1) - reg = 0x8000d0d4; - result = i1480->read(i1480, reg, sizeof(u32)); - if (result < 0) - goto error_cmd; - *buffer &= ~i1480_FW_UPLOAD_MODE_MASK; - result = i1480->write(i1480, reg, buffer, sizeof(u32)); - if (result < 0) - goto error_cmd; - return 0; -error_cmd: - dev_err(i1480->dev, "can't enable fw upload mode: %d\n", result); - return result; -} - - -/** Gets the device out of firmware upload mode. */ -static -int mac_fw_upload_disable(struct i1480 *i1480) -{ - int result; - u32 reg = 0x800000c0; - u32 *buffer = (u32 *)i1480->cmd_buf; - - if (i1480->hw_rev > 1) - reg = 0x8000d0d4; - result = i1480->read(i1480, reg, sizeof(u32)); - if (result < 0) - goto error_cmd; - *buffer |= i1480_FW_UPLOAD_MODE_MASK; - result = i1480->write(i1480, reg, buffer, sizeof(u32)); - if (result < 0) - goto error_cmd; - return 0; -error_cmd: - dev_err(i1480->dev, "can't disable fw upload mode: %d\n", result); - return result; -} - - - -/** - * Generic function for uploading a MAC firmware. - * - * @i1480: Device instance - * @fw_name: Name of firmware file to upload. - * @fw_tag: Name of the firmware type (for messages) - * [eg: MAC, PRE] - * @do_wait: Wait for device to emit initialization done message (0 - * for PRE fws, 1 for MAC fws). - * @returns: 0 if ok, < 0 errno on error. - */ -static -int __mac_fw_upload(struct i1480 *i1480, const char *fw_name, - const char *fw_tag) -{ - int result; - const struct firmware *fw; - struct fw_hdr *fw_hdrs; - - result = request_firmware(&fw, fw_name, i1480->dev); - if (result < 0) /* Up to caller to complain on -ENOENT */ - goto out; - result = fw_hdrs_load(i1480, &fw_hdrs, fw->data, fw->size); - if (result < 0) { - dev_err(i1480->dev, "%s fw '%s': failed to parse firmware " - "file: %d\n", fw_tag, fw_name, result); - goto out_release; - } - result = mac_fw_upload_enable(i1480); - if (result < 0) - goto out_hdrs_release; - result = mac_fw_hdrs_push(i1480, fw_hdrs, fw_name, fw_tag); - mac_fw_upload_disable(i1480); -out_hdrs_release: - if (result >= 0) - dev_info(i1480->dev, "%s fw '%s': uploaded\n", fw_tag, fw_name); - else - dev_err(i1480->dev, "%s fw '%s': failed to upload (%d), " - "power cycle device\n", fw_tag, fw_name, result); - fw_hdrs_free(fw_hdrs); -out_release: - release_firmware(fw); -out: - return result; -} - - -/** - * Upload a pre-PHY firmware - * - */ -int i1480_pre_fw_upload(struct i1480 *i1480) -{ - int result; - result = __mac_fw_upload(i1480, i1480->pre_fw_name, "PRE"); - if (result == 0) - msleep(400); - return result; -} - - -/** - * Reset a the MAC and PHY - * - * @i1480: Device's instance - * @returns: 0 if ok, < 0 errno code on error - * - * We put the command on kmalloc'ed memory as some arches cannot do - * USB from the stack. The reply event is copied from an stage buffer, - * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details. - * - * We issue the reset to make sure the UWB controller reinits the PHY; - * this way we can now if the PHY init went ok. - */ -static -int i1480_cmd_reset(struct i1480 *i1480) -{ - int result; - struct uwb_rccb *cmd = (void *) i1480->cmd_buf; - struct i1480_evt_reset { - struct uwb_rceb rceb; - u8 bResultCode; - } __attribute__((packed)) *reply = (void *) i1480->evt_buf; - - result = -ENOMEM; - cmd->bCommandType = UWB_RC_CET_GENERAL; - cmd->wCommand = cpu_to_le16(UWB_RC_CMD_RESET); - reply->rceb.bEventType = UWB_RC_CET_GENERAL; - reply->rceb.wEvent = UWB_RC_CMD_RESET; - result = i1480_cmd(i1480, "RESET", sizeof(*cmd), sizeof(*reply)); - if (result < 0) - goto out; - if (reply->bResultCode != UWB_RC_RES_SUCCESS) { - dev_err(i1480->dev, "RESET: command execution failed: %u\n", - reply->bResultCode); - result = -EIO; - } -out: - return result; - -} - - -/* Wait for the MAC FW to start running */ -static -int i1480_fw_is_running_q(struct i1480 *i1480) -{ - int cnt = 0; - int result; - u32 *val = (u32 *) i1480->cmd_buf; - - for (cnt = 0; cnt < 10; cnt++) { - msleep(100); - result = i1480->read(i1480, 0x80080000, 4); - if (result < 0) { - dev_err(i1480->dev, "Can't read 0x8008000: %d\n", result); - goto out; - } - if (*val == 0x55555555UL) /* fw running? cool */ - goto out; - } - dev_err(i1480->dev, "Timed out waiting for fw to start\n"); - result = -ETIMEDOUT; -out: - return result; - -} - - -/** - * Upload MAC firmware, wait for it to start - * - * @i1480: Device instance - * @fw_name: Name of the file that contains the firmware - * - * This has to be called after the pre fw has been uploaded (if - * there is any). - */ -int i1480_mac_fw_upload(struct i1480 *i1480) -{ - int result = 0, deprecated_name = 0; - struct i1480_rceb *rcebe = (void *) i1480->evt_buf; - - result = __mac_fw_upload(i1480, i1480->mac_fw_name, "MAC"); - if (result == -ENOENT) { - result = __mac_fw_upload(i1480, i1480->mac_fw_name_deprecate, - "MAC"); - deprecated_name = 1; - } - if (result < 0) - return result; - if (deprecated_name == 1) - dev_warn(i1480->dev, - "WARNING: firmware file name %s is deprecated, " - "please rename to %s\n", - i1480->mac_fw_name_deprecate, i1480->mac_fw_name); - result = i1480_fw_is_running_q(i1480); - if (result < 0) - goto error_fw_not_running; - result = i1480->rc_setup ? i1480->rc_setup(i1480) : 0; - if (result < 0) { - dev_err(i1480->dev, "Cannot setup after MAC fw upload: %d\n", - result); - goto error_setup; - } - result = i1480->wait_init_done(i1480); /* wait init'on */ - if (result < 0) { - dev_err(i1480->dev, "MAC fw '%s': Initialization timed out " - "(%d)\n", i1480->mac_fw_name, result); - goto error_init_timeout; - } - /* verify we got the right initialization done event */ - if (i1480->evt_result != sizeof(*rcebe)) { - dev_err(i1480->dev, "MAC fw '%s': initialization event returns " - "wrong size (%zu bytes vs %zu needed)\n", - i1480->mac_fw_name, i1480->evt_result, sizeof(*rcebe)); - goto error_size; - } - result = -EIO; - if (i1480_rceb_check(i1480, &rcebe->rceb, NULL, 0, i1480_CET_VS1, - i1480_EVT_RM_INIT_DONE) < 0) { - dev_err(i1480->dev, "wrong initialization event 0x%02x/%04x/%02x " - "received; expected 0x%02x/%04x/00\n", - rcebe->rceb.bEventType, le16_to_cpu(rcebe->rceb.wEvent), - rcebe->rceb.bEventContext, i1480_CET_VS1, - i1480_EVT_RM_INIT_DONE); - goto error_init_timeout; - } - result = i1480_cmd_reset(i1480); - if (result < 0) - dev_err(i1480->dev, "MAC fw '%s': MBOA reset failed (%d)\n", - i1480->mac_fw_name, result); -error_fw_not_running: -error_init_timeout: -error_size: -error_setup: - return result; -} diff --git a/drivers/uwb/i1480/dfu/phy.c b/drivers/uwb/i1480/dfu/phy.c deleted file mode 100644 index 50da4527c113..000000000000 --- a/drivers/uwb/i1480/dfu/phy.c +++ /dev/null @@ -1,190 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Wireless UWB Link 1480 - * PHY parameters upload - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * Code for uploading the PHY parameters to the PHY through the UWB - * Radio Control interface. - * - * We just send the data through the MPI interface using HWA-like - * commands and then reset the PHY to make sure it is ok. - */ -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/firmware.h> -#include <linux/usb/wusb.h> -#include "i1480-dfu.h" - - -/** - * Write a value array to an address of the MPI interface - * - * @i1480: Device descriptor - * @data: Data array to write - * @size: Size of the data array - * @returns: 0 if ok, < 0 errno code on error. - * - * The data array is organized into pairs: - * - * ADDRESS VALUE - * - * ADDRESS is BE 16 bit unsigned, VALUE 8 bit unsigned. Size thus has - * to be a multiple of three. - */ -static -int i1480_mpi_write(struct i1480 *i1480, const void *data, size_t size) -{ - int result; - struct i1480_cmd_mpi_write *cmd = i1480->cmd_buf; - struct i1480_evt_confirm *reply = i1480->evt_buf; - - BUG_ON(size > 480); - result = -ENOMEM; - cmd->rccb.bCommandType = i1480_CET_VS1; - cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_WRITE); - cmd->size = cpu_to_le16(size); - memcpy(cmd->data, data, size); - reply->rceb.bEventType = i1480_CET_VS1; - reply->rceb.wEvent = i1480_CMD_MPI_WRITE; - result = i1480_cmd(i1480, "MPI-WRITE", sizeof(*cmd) + size, sizeof(*reply)); - if (result < 0) - goto out; - if (reply->bResultCode != UWB_RC_RES_SUCCESS) { - dev_err(i1480->dev, "MPI-WRITE: command execution failed: %d\n", - reply->bResultCode); - result = -EIO; - } -out: - return result; -} - - -/** - * Read a value array to from an address of the MPI interface - * - * @i1480: Device descriptor - * @data: where to place the read array - * @srcaddr: Where to read from - * @size: Size of the data read array - * @returns: 0 if ok, < 0 errno code on error. - * - * The command data array is organized into pairs ADDR0 ADDR1..., and - * the returned data in ADDR0 VALUE0 ADDR1 VALUE1... - * - * We generate the command array to be a sequential read and then - * rearrange the result. - * - * We use the i1480->cmd_buf for the command, i1480->evt_buf for the reply. - * - * As the reply has to fit in 512 bytes (i1480->evt_buffer), the max amount - * of values we can read is (512 - sizeof(*reply)) / 3 - */ -static -int i1480_mpi_read(struct i1480 *i1480, u8 *data, u16 srcaddr, size_t size) -{ - int result; - struct i1480_cmd_mpi_read *cmd = i1480->cmd_buf; - struct i1480_evt_mpi_read *reply = i1480->evt_buf; - unsigned cnt; - - memset(i1480->cmd_buf, 0x69, 512); - memset(i1480->evt_buf, 0x69, 512); - - BUG_ON(size > (i1480->buf_size - sizeof(*reply)) / 3); - result = -ENOMEM; - cmd->rccb.bCommandType = i1480_CET_VS1; - cmd->rccb.wCommand = cpu_to_le16(i1480_CMD_MPI_READ); - cmd->size = cpu_to_le16(3*size); - for (cnt = 0; cnt < size; cnt++) { - cmd->data[cnt].page = (srcaddr + cnt) >> 8; - cmd->data[cnt].offset = (srcaddr + cnt) & 0xff; - } - reply->rceb.bEventType = i1480_CET_VS1; - reply->rceb.wEvent = i1480_CMD_MPI_READ; - result = i1480_cmd(i1480, "MPI-READ", sizeof(*cmd) + 2*size, - sizeof(*reply) + 3*size); - if (result < 0) - goto out; - if (reply->bResultCode != UWB_RC_RES_SUCCESS) { - dev_err(i1480->dev, "MPI-READ: command execution failed: %d\n", - reply->bResultCode); - result = -EIO; - goto out; - } - for (cnt = 0; cnt < size; cnt++) { - if (reply->data[cnt].page != (srcaddr + cnt) >> 8) - dev_err(i1480->dev, "MPI-READ: page inconsistency at " - "index %u: expected 0x%02x, got 0x%02x\n", cnt, - (srcaddr + cnt) >> 8, reply->data[cnt].page); - if (reply->data[cnt].offset != ((srcaddr + cnt) & 0x00ff)) - dev_err(i1480->dev, "MPI-READ: offset inconsistency at " - "index %u: expected 0x%02x, got 0x%02x\n", cnt, - (srcaddr + cnt) & 0x00ff, - reply->data[cnt].offset); - data[cnt] = reply->data[cnt].value; - } - result = 0; -out: - return result; -} - - -/** - * Upload a PHY firmware, wait for it to start - * - * @i1480: Device instance - * @fw_name: Name of the file that contains the firmware - * - * We assume the MAC fw is up and running. This means we can use the - * MPI interface to write the PHY firmware. Once done, we issue an - * MBOA Reset, which will force the MAC to reset and reinitialize the - * PHY. If that works, we are ready to go. - * - * Max packet size for the MPI write is 512, so the max buffer is 480 - * (which gives us 160 byte triads of MSB, LSB and VAL for the data). - */ -int i1480_phy_fw_upload(struct i1480 *i1480) -{ - int result; - const struct firmware *fw; - const char *data_itr, *data_top; - const size_t MAX_BLK_SIZE = 480; /* 160 triads */ - size_t data_size; - u8 phy_stat; - - result = request_firmware(&fw, i1480->phy_fw_name, i1480->dev); - if (result < 0) - goto out; - /* Loop writing data in chunks as big as possible until done. */ - for (data_itr = fw->data, data_top = data_itr + fw->size; - data_itr < data_top; data_itr += MAX_BLK_SIZE) { - data_size = min(MAX_BLK_SIZE, (size_t) (data_top - data_itr)); - result = i1480_mpi_write(i1480, data_itr, data_size); - if (result < 0) - goto error_mpi_write; - } - /* Read MPI page 0, offset 6; if 0, PHY was initialized correctly. */ - result = i1480_mpi_read(i1480, &phy_stat, 0x0006, 1); - if (result < 0) { - dev_err(i1480->dev, "PHY: can't get status: %d\n", result); - goto error_mpi_status; - } - if (phy_stat != 0) { - result = -ENODEV; - dev_info(i1480->dev, "error, PHY not ready: %u\n", phy_stat); - goto error_phy_status; - } - dev_info(i1480->dev, "PHY fw '%s': uploaded\n", i1480->phy_fw_name); -error_phy_status: -error_mpi_status: -error_mpi_write: - release_firmware(fw); - if (result < 0) - dev_err(i1480->dev, "PHY fw '%s': failed to upload (%d), " - "power cycle device\n", i1480->phy_fw_name, result); -out: - return result; -} diff --git a/drivers/uwb/i1480/dfu/usb.c b/drivers/uwb/i1480/dfu/usb.c deleted file mode 100644 index 6129a8f4b5f2..000000000000 --- a/drivers/uwb/i1480/dfu/usb.c +++ /dev/null @@ -1,448 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Wireless UWB Link 1480 - * USB SKU firmware upload implementation - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * This driver will prepare the i1480 device to behave as a real - * Wireless USB HWA adaptor by uploading the firmware. - * - * When the device is connected or driver is loaded, i1480_usb_probe() - * is called--this will allocate and initialize the device structure, - * fill in the pointers to the common functions (read, write, - * wait_init_done and cmd for HWA command execution) and once that is - * done, call the common firmware uploading routine. Then clean up and - * return -ENODEV, as we don't attach to the device. - * - * The rest are the basic ops we implement that the fw upload code - * uses to do its job. All the ops in the common code are i1480->NAME, - * the functions are i1480_usb_NAME(). - */ -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/uwb.h> -#include <linux/usb/wusb.h> -#include <linux/usb/wusb-wa.h> -#include "i1480-dfu.h" - -struct i1480_usb { - struct i1480 i1480; - struct usb_device *usb_dev; - struct usb_interface *usb_iface; - struct urb *neep_urb; /* URB for reading from EP1 */ -}; - - -static -void i1480_usb_init(struct i1480_usb *i1480_usb) -{ - i1480_init(&i1480_usb->i1480); -} - - -static -int i1480_usb_create(struct i1480_usb *i1480_usb, struct usb_interface *iface) -{ - struct usb_device *usb_dev = interface_to_usbdev(iface); - int result = -ENOMEM; - - i1480_usb->usb_dev = usb_get_dev(usb_dev); /* bind the USB device */ - i1480_usb->usb_iface = usb_get_intf(iface); - usb_set_intfdata(iface, i1480_usb); /* Bind the driver to iface0 */ - i1480_usb->neep_urb = usb_alloc_urb(0, GFP_KERNEL); - if (i1480_usb->neep_urb == NULL) - goto error; - return 0; - -error: - usb_set_intfdata(iface, NULL); - usb_put_intf(iface); - usb_put_dev(usb_dev); - return result; -} - - -static -void i1480_usb_destroy(struct i1480_usb *i1480_usb) -{ - usb_kill_urb(i1480_usb->neep_urb); - usb_free_urb(i1480_usb->neep_urb); - usb_set_intfdata(i1480_usb->usb_iface, NULL); - usb_put_intf(i1480_usb->usb_iface); - usb_put_dev(i1480_usb->usb_dev); -} - - -/** - * Write a buffer to a memory address in the i1480 device - * - * @i1480: i1480 instance - * @memory_address: - * Address where to write the data buffer to. - * @buffer: Buffer to the data - * @size: Size of the buffer [has to be < 512]. - * @returns: 0 if ok, < 0 errno code on error. - * - * Data buffers to USB cannot be on the stack or in vmalloc'ed areas, - * so we copy it to the local i1480 buffer before proceeding. In any - * case, we have a max size we can send. - */ -static -int i1480_usb_write(struct i1480 *i1480, u32 memory_address, - const void *buffer, size_t size) -{ - int result = 0; - struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480); - size_t buffer_size, itr = 0; - - BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */ - while (size > 0) { - buffer_size = size < i1480->buf_size ? size : i1480->buf_size; - memcpy(i1480->cmd_buf, buffer + itr, buffer_size); - result = usb_control_msg( - i1480_usb->usb_dev, usb_sndctrlpipe(i1480_usb->usb_dev, 0), - 0xf0, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - memory_address, (memory_address >> 16), - i1480->cmd_buf, buffer_size, 100 /* FIXME: arbitrary */); - if (result < 0) - break; - itr += result; - memory_address += result; - size -= result; - } - return result; -} - - -/** - * Read a block [max size 512] of the device's memory to @i1480's buffer. - * - * @i1480: i1480 instance - * @memory_address: - * Address where to read from. - * @size: Size to read. Smaller than or equal to 512. - * @returns: >= 0 number of bytes written if ok, < 0 errno code on error. - * - * NOTE: if the memory address or block is incorrect, you might get a - * stall or a different memory read. Caller has to verify the - * memory address and size passed back in the @neh structure. - */ -static -int i1480_usb_read(struct i1480 *i1480, u32 addr, size_t size) -{ - ssize_t result = 0, bytes = 0; - size_t itr, read_size = i1480->buf_size; - struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480); - - BUG_ON(size > i1480->buf_size); - BUG_ON(size & 0x3); /* Needs to be a multiple of 4 */ - BUG_ON(read_size > 512); - - if (addr >= 0x8000d200 && addr < 0x8000d400) /* Yeah, HW quirk */ - read_size = 4; - - for (itr = 0; itr < size; itr += read_size) { - size_t itr_addr = addr + itr; - size_t itr_size = min(read_size, size - itr); - result = usb_control_msg( - i1480_usb->usb_dev, usb_rcvctrlpipe(i1480_usb->usb_dev, 0), - 0xf0, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - itr_addr, (itr_addr >> 16), - i1480->cmd_buf + itr, itr_size, - 100 /* FIXME: arbitrary */); - if (result < 0) { - dev_err(i1480->dev, "%s: USB read error: %zd\n", - __func__, result); - goto out; - } - if (result != itr_size) { - result = -EIO; - dev_err(i1480->dev, - "%s: partial read got only %zu bytes vs %zu expected\n", - __func__, result, itr_size); - goto out; - } - bytes += result; - } - result = bytes; -out: - return result; -} - - -/** - * Callback for reads on the notification/event endpoint - * - * Just enables the completion read handler. - */ -static -void i1480_usb_neep_cb(struct urb *urb) -{ - struct i1480 *i1480 = urb->context; - struct device *dev = i1480->dev; - - switch (urb->status) { - case 0: - break; - case -ECONNRESET: /* Not an error, but a controlled situation; */ - case -ENOENT: /* (we killed the URB)...so, no broadcast */ - dev_dbg(dev, "NEEP: reset/noent %d\n", urb->status); - break; - case -ESHUTDOWN: /* going away! */ - dev_dbg(dev, "NEEP: down %d\n", urb->status); - break; - default: - dev_err(dev, "NEEP: unknown status %d\n", urb->status); - break; - } - i1480->evt_result = urb->actual_length; - complete(&i1480->evt_complete); - return; -} - - -/** - * Wait for the MAC FW to initialize - * - * MAC FW sends a 0xfd/0101/00 notification to EP1 when done - * initializing. Get that notification into i1480->evt_buf; upper layer - * will verify it. - * - * Set i1480->evt_result with the result of getting the event or its - * size (if successful). - * - * Delivers the data directly to i1480->evt_buf - */ -static -int i1480_usb_wait_init_done(struct i1480 *i1480) -{ - int result; - struct device *dev = i1480->dev; - struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480); - struct usb_endpoint_descriptor *epd; - - init_completion(&i1480->evt_complete); - i1480->evt_result = -EINPROGRESS; - epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc; - usb_fill_int_urb(i1480_usb->neep_urb, i1480_usb->usb_dev, - usb_rcvintpipe(i1480_usb->usb_dev, epd->bEndpointAddress), - i1480->evt_buf, i1480->buf_size, - i1480_usb_neep_cb, i1480, epd->bInterval); - result = usb_submit_urb(i1480_usb->neep_urb, GFP_KERNEL); - if (result < 0) { - dev_err(dev, "init done: cannot submit NEEP read: %d\n", - result); - goto error_submit; - } - /* Wait for the USB callback to get the data */ - result = wait_for_completion_interruptible_timeout( - &i1480->evt_complete, HZ); - if (result <= 0) { - result = result == 0 ? -ETIMEDOUT : result; - goto error_wait; - } - usb_kill_urb(i1480_usb->neep_urb); - return 0; - -error_wait: - usb_kill_urb(i1480_usb->neep_urb); -error_submit: - i1480->evt_result = result; - return result; -} - - -/** - * Generic function for issuing commands to the i1480 - * - * @i1480: i1480 instance - * @cmd_name: Name of the command (for error messages) - * @cmd: Pointer to command buffer - * @cmd_size: Size of the command buffer - * @reply: Buffer for the reply event - * @reply_size: Expected size back (including RCEB); the reply buffer - * is assumed to be as big as this. - * @returns: >= 0 size of the returned event data if ok, - * < 0 errno code on error. - * - * Arms the NE handle, issues the command to the device and checks the - * basics of the reply event. - */ -static -int i1480_usb_cmd(struct i1480 *i1480, const char *cmd_name, size_t cmd_size) -{ - int result; - struct device *dev = i1480->dev; - struct i1480_usb *i1480_usb = container_of(i1480, struct i1480_usb, i1480); - struct usb_endpoint_descriptor *epd; - struct uwb_rccb *cmd = i1480->cmd_buf; - u8 iface_no; - - /* Post a read on the notification & event endpoint */ - iface_no = i1480_usb->usb_iface->cur_altsetting->desc.bInterfaceNumber; - epd = &i1480_usb->usb_iface->cur_altsetting->endpoint[0].desc; - usb_fill_int_urb( - i1480_usb->neep_urb, i1480_usb->usb_dev, - usb_rcvintpipe(i1480_usb->usb_dev, epd->bEndpointAddress), - i1480->evt_buf, i1480->buf_size, - i1480_usb_neep_cb, i1480, epd->bInterval); - result = usb_submit_urb(i1480_usb->neep_urb, GFP_KERNEL); - if (result < 0) { - dev_err(dev, "%s: cannot submit NEEP read: %d\n", - cmd_name, result); - goto error_submit_ep1; - } - /* Now post the command on EP0 */ - result = usb_control_msg( - i1480_usb->usb_dev, usb_sndctrlpipe(i1480_usb->usb_dev, 0), - WA_EXEC_RC_CMD, - USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS, - 0, iface_no, - cmd, cmd_size, - 100 /* FIXME: this is totally arbitrary */); - if (result < 0) { - dev_err(dev, "%s: control request failed: %d\n", - cmd_name, result); - goto error_submit_ep0; - } - return result; - -error_submit_ep0: - usb_kill_urb(i1480_usb->neep_urb); -error_submit_ep1: - return result; -} - - -/* - * Probe a i1480 device for uploading firmware. - * - * We attach only to interface #0, which is the radio control interface. - */ -static -int i1480_usb_probe(struct usb_interface *iface, const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(iface); - struct i1480_usb *i1480_usb; - struct i1480 *i1480; - struct device *dev = &iface->dev; - int result; - - result = -ENODEV; - if (iface->cur_altsetting->desc.bInterfaceNumber != 0) { - dev_dbg(dev, "not attaching to iface %d\n", - iface->cur_altsetting->desc.bInterfaceNumber); - goto error; - } - if (iface->num_altsetting > 1 && - le16_to_cpu(udev->descriptor.idProduct) == 0xbabe) { - /* Need altsetting #1 [HW QUIRK] or EP1 won't work */ - result = usb_set_interface(interface_to_usbdev(iface), 0, 1); - if (result < 0) - dev_warn(dev, - "can't set altsetting 1 on iface 0: %d\n", - result); - } - - if (iface->cur_altsetting->desc.bNumEndpoints < 1) - return -ENODEV; - - result = -ENOMEM; - i1480_usb = kzalloc(sizeof(*i1480_usb), GFP_KERNEL); - if (i1480_usb == NULL) { - dev_err(dev, "Unable to allocate instance\n"); - goto error; - } - i1480_usb_init(i1480_usb); - - i1480 = &i1480_usb->i1480; - i1480->buf_size = 512; - i1480->cmd_buf = kmalloc_array(2, i1480->buf_size, GFP_KERNEL); - if (i1480->cmd_buf == NULL) { - dev_err(dev, "Cannot allocate transfer buffers\n"); - result = -ENOMEM; - goto error_buf_alloc; - } - i1480->evt_buf = i1480->cmd_buf + i1480->buf_size; - - result = i1480_usb_create(i1480_usb, iface); - if (result < 0) { - dev_err(dev, "Cannot create instance: %d\n", result); - goto error_create; - } - - /* setup the fops and upload the firmware */ - i1480->pre_fw_name = "i1480-pre-phy-0.0.bin"; - i1480->mac_fw_name = "i1480-usb-0.0.bin"; - i1480->mac_fw_name_deprecate = "ptc-0.0.bin"; - i1480->phy_fw_name = "i1480-phy-0.0.bin"; - i1480->dev = &iface->dev; - i1480->write = i1480_usb_write; - i1480->read = i1480_usb_read; - i1480->rc_setup = NULL; - i1480->wait_init_done = i1480_usb_wait_init_done; - i1480->cmd = i1480_usb_cmd; - - result = i1480_fw_upload(&i1480_usb->i1480); /* the real thing */ - if (result >= 0) { - usb_reset_device(i1480_usb->usb_dev); - result = -ENODEV; /* we don't want to bind to the iface */ - } - i1480_usb_destroy(i1480_usb); -error_create: - kfree(i1480->cmd_buf); -error_buf_alloc: - kfree(i1480_usb); -error: - return result; -} - -MODULE_FIRMWARE("i1480-pre-phy-0.0.bin"); -MODULE_FIRMWARE("i1480-usb-0.0.bin"); -MODULE_FIRMWARE("i1480-phy-0.0.bin"); - -#define i1480_USB_DEV(v, p) \ -{ \ - .match_flags = USB_DEVICE_ID_MATCH_DEVICE \ - | USB_DEVICE_ID_MATCH_DEV_INFO \ - | USB_DEVICE_ID_MATCH_INT_INFO, \ - .idVendor = (v), \ - .idProduct = (p), \ - .bDeviceClass = 0xff, \ - .bDeviceSubClass = 0xff, \ - .bDeviceProtocol = 0xff, \ - .bInterfaceClass = 0xff, \ - .bInterfaceSubClass = 0xff, \ - .bInterfaceProtocol = 0xff, \ -} - - -/** USB device ID's that we handle */ -static const struct usb_device_id i1480_usb_id_table[] = { - i1480_USB_DEV(0x8086, 0xdf3b), - i1480_USB_DEV(0x15a9, 0x0005), - i1480_USB_DEV(0x07d1, 0x3802), - i1480_USB_DEV(0x050d, 0x305a), - i1480_USB_DEV(0x3495, 0x3007), - {}, -}; -MODULE_DEVICE_TABLE(usb, i1480_usb_id_table); - - -static struct usb_driver i1480_dfu_driver = { - .name = "i1480-dfu-usb", - .id_table = i1480_usb_id_table, - .probe = i1480_usb_probe, - .disconnect = NULL, -}; - -module_usb_driver(i1480_dfu_driver); - -MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); -MODULE_DESCRIPTION("Intel Wireless UWB Link 1480 firmware uploader for USB"); -MODULE_LICENSE("GPL"); diff --git a/drivers/uwb/i1480/i1480-est.c b/drivers/uwb/i1480/i1480-est.c deleted file mode 100644 index 1346c409d10e..000000000000 --- a/drivers/uwb/i1480/i1480-est.c +++ /dev/null @@ -1,85 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Wireless UWB Link 1480 - * Event Size tables for Wired Adaptors - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * FIXME: docs - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/uwb.h> -#include "dfu/i1480-dfu.h" - - -/** Event size table for wEvents 0x00XX */ -static struct uwb_est_entry i1480_est_fd00[] = { - /* Anybody expecting this response has to use - * neh->extra_size to specify the real size that will - * come back. */ - [i1480_EVT_CONFIRM] = { .size = sizeof(struct i1480_evt_confirm) }, - [i1480_CMD_SET_IP_MAS] = { .size = sizeof(struct i1480_evt_confirm) }, -#ifdef i1480_RCEB_EXTENDED - [0x09] = { - .size = sizeof(struct i1480_rceb), - .offset = 1 + offsetof(struct i1480_rceb, wParamLength), - }, -#endif -}; - -/** Event size table for wEvents 0x01XX */ -static struct uwb_est_entry i1480_est_fd01[] = { - [0xff & i1480_EVT_RM_INIT_DONE] = { .size = sizeof(struct i1480_rceb) }, - [0xff & i1480_EVT_DEV_ADD] = { .size = sizeof(struct i1480_rceb) + 9 }, - [0xff & i1480_EVT_DEV_RM] = { .size = sizeof(struct i1480_rceb) + 9 }, - [0xff & i1480_EVT_DEV_ID_CHANGE] = { - .size = sizeof(struct i1480_rceb) + 2 }, -}; - -static int __init i1480_est_init(void) -{ - int result = uwb_est_register(i1480_CET_VS1, 0x00, 0x8086, 0x0c3b, - i1480_est_fd00, - ARRAY_SIZE(i1480_est_fd00)); - if (result < 0) { - printk(KERN_ERR "Can't register EST table fd00: %d\n", result); - return result; - } - result = uwb_est_register(i1480_CET_VS1, 0x01, 0x8086, 0x0c3b, - i1480_est_fd01, ARRAY_SIZE(i1480_est_fd01)); - if (result < 0) { - printk(KERN_ERR "Can't register EST table fd01: %d\n", result); - return result; - } - return 0; -} -module_init(i1480_est_init); - -static void __exit i1480_est_exit(void) -{ - uwb_est_unregister(i1480_CET_VS1, 0x00, 0x8086, 0x0c3b, - i1480_est_fd00, ARRAY_SIZE(i1480_est_fd00)); - uwb_est_unregister(i1480_CET_VS1, 0x01, 0x8086, 0x0c3b, - i1480_est_fd01, ARRAY_SIZE(i1480_est_fd01)); -} -module_exit(i1480_est_exit); - -MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); -MODULE_DESCRIPTION("i1480's Vendor Specific Event Size Tables"); -MODULE_LICENSE("GPL"); - -/** - * USB device ID's that we handle - * - * [so we are loaded when this kind device is connected] - */ -static struct usb_device_id __used i1480_est_id_table[] = { - { USB_DEVICE(0x8086, 0xdf3b), }, - { USB_DEVICE(0x8086, 0x0c3b), }, - { }, -}; -MODULE_DEVICE_TABLE(usb, i1480_est_id_table); diff --git a/drivers/uwb/ie-rcv.c b/drivers/uwb/ie-rcv.c deleted file mode 100644 index 51a4706e0dd3..000000000000 --- a/drivers/uwb/ie-rcv.c +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Ultra Wide Band - * IE Received notification handling. - * - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - */ - -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/bitmap.h> -#include "uwb-internal.h" - -/* - * Process an incoming IE Received notification. - */ -int uwbd_evt_handle_rc_ie_rcv(struct uwb_event *evt) -{ - int result = -EINVAL; - struct device *dev = &evt->rc->uwb_dev.dev; - struct uwb_rc_evt_ie_rcv *iercv; - - /* Is there enough data to decode it? */ - if (evt->notif.size < sizeof(*iercv)) { - dev_err(dev, "IE Received notification: Not enough data to " - "decode (%zu vs %zu bytes needed)\n", - evt->notif.size, sizeof(*iercv)); - goto error; - } - iercv = container_of(evt->notif.rceb, struct uwb_rc_evt_ie_rcv, rceb); - - dev_dbg(dev, "IE received, element ID=%d\n", iercv->IEData[0]); - - if (iercv->IEData[0] == UWB_RELINQUISH_REQUEST_IE) { - dev_warn(dev, "unhandled Relinquish Request IE\n"); - } - - return 0; -error: - return result; -} diff --git a/drivers/uwb/ie.c b/drivers/uwb/ie.c deleted file mode 100644 index b11678dd0380..000000000000 --- a/drivers/uwb/ie.c +++ /dev/null @@ -1,366 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Ultra Wide Band - * Information Element Handling - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * Reinette Chatre <reinette.chatre@intel.com> - * - * FIXME: docs - */ - -#include <linux/slab.h> -#include <linux/export.h> -#include "uwb-internal.h" - -/** - * uwb_ie_next - get the next IE in a buffer - * @ptr: start of the buffer containing the IE data - * @len: length of the buffer - * - * Both @ptr and @len are updated so subsequent calls to uwb_ie_next() - * will get the next IE. - * - * NULL is returned (and @ptr and @len will not be updated) if there - * are no more IEs in the buffer or the buffer is too short. - */ -struct uwb_ie_hdr *uwb_ie_next(void **ptr, size_t *len) -{ - struct uwb_ie_hdr *hdr; - size_t ie_len; - - if (*len < sizeof(struct uwb_ie_hdr)) - return NULL; - - hdr = *ptr; - ie_len = sizeof(struct uwb_ie_hdr) + hdr->length; - - if (*len < ie_len) - return NULL; - - *ptr += ie_len; - *len -= ie_len; - - return hdr; -} -EXPORT_SYMBOL_GPL(uwb_ie_next); - -/** - * uwb_ie_dump_hex - print IEs to a character buffer - * @ies: the IEs to print. - * @len: length of all the IEs. - * @buf: the destination buffer. - * @size: size of @buf. - * - * Returns the number of characters written. - */ -int uwb_ie_dump_hex(const struct uwb_ie_hdr *ies, size_t len, - char *buf, size_t size) -{ - void *ptr; - const struct uwb_ie_hdr *ie; - int r = 0; - u8 *d; - - ptr = (void *)ies; - for (;;) { - ie = uwb_ie_next(&ptr, &len); - if (!ie) - break; - - r += scnprintf(buf + r, size - r, "%02x %02x", - (unsigned)ie->element_id, - (unsigned)ie->length); - d = (uint8_t *)ie + sizeof(struct uwb_ie_hdr); - while (d != ptr && r < size) - r += scnprintf(buf + r, size - r, " %02x", (unsigned)*d++); - if (r < size) - buf[r++] = '\n'; - }; - - return r; -} - -/** - * Get the IEs that a radio controller is sending in its beacon - * - * @uwb_rc: UWB Radio Controller - * @returns: Size read from the system - * - * We don't need to lock the uwb_rc's mutex because we don't modify - * anything. Once done with the iedata buffer, call - * uwb_rc_ie_release(iedata). Don't call kfree on it. - */ -static -ssize_t uwb_rc_get_ie(struct uwb_rc *uwb_rc, struct uwb_rc_evt_get_ie **pget_ie) -{ - ssize_t result; - struct device *dev = &uwb_rc->uwb_dev.dev; - struct uwb_rccb *cmd = NULL; - struct uwb_rceb *reply = NULL; - struct uwb_rc_evt_get_ie *get_ie; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - return -ENOMEM; - - cmd->bCommandType = UWB_RC_CET_GENERAL; - cmd->wCommand = cpu_to_le16(UWB_RC_CMD_GET_IE); - result = uwb_rc_vcmd(uwb_rc, "GET_IE", cmd, sizeof(*cmd), - UWB_RC_CET_GENERAL, UWB_RC_CMD_GET_IE, - &reply); - kfree(cmd); - if (result < 0) - return result; - - get_ie = container_of(reply, struct uwb_rc_evt_get_ie, rceb); - if (result < sizeof(*get_ie)) { - dev_err(dev, "not enough data returned for decoding GET IE " - "(%zu bytes received vs %zu needed)\n", - result, sizeof(*get_ie)); - return -EINVAL; - } else if (result < sizeof(*get_ie) + le16_to_cpu(get_ie->wIELength)) { - dev_err(dev, "not enough data returned for decoding GET IE " - "payload (%zu bytes received vs %zu needed)\n", result, - sizeof(*get_ie) + le16_to_cpu(get_ie->wIELength)); - return -EINVAL; - } - - *pget_ie = get_ie; - return result; -} - - -/** - * Replace all IEs currently being transmitted by a device - * - * @cmd: pointer to the SET-IE command with the IEs to set - * @size: size of @buf - */ -int uwb_rc_set_ie(struct uwb_rc *rc, struct uwb_rc_cmd_set_ie *cmd) -{ - int result; - struct device *dev = &rc->uwb_dev.dev; - struct uwb_rc_evt_set_ie reply; - - reply.rceb.bEventType = UWB_RC_CET_GENERAL; - reply.rceb.wEvent = UWB_RC_CMD_SET_IE; - result = uwb_rc_cmd(rc, "SET-IE", &cmd->rccb, - sizeof(*cmd) + le16_to_cpu(cmd->wIELength), - &reply.rceb, sizeof(reply)); - if (result < 0) - goto error_cmd; - else if (result != sizeof(reply)) { - dev_err(dev, "SET-IE: not enough data to decode reply " - "(%d bytes received vs %zu needed)\n", - result, sizeof(reply)); - result = -EIO; - } else if (reply.bResultCode != UWB_RC_RES_SUCCESS) { - dev_err(dev, "SET-IE: command execution failed: %s (%d)\n", - uwb_rc_strerror(reply.bResultCode), reply.bResultCode); - result = -EIO; - } else - result = 0; -error_cmd: - return result; -} - -/* Cleanup the whole IE management subsystem */ -void uwb_rc_ie_init(struct uwb_rc *uwb_rc) -{ - mutex_init(&uwb_rc->ies_mutex); -} - - -/** - * uwb_rc_ie_setup - setup a radio controller's IE manager - * @uwb_rc: the radio controller. - * - * The current set of IEs are obtained from the hardware with a GET-IE - * command (since the radio controller is not yet beaconing this will - * be just the hardware's MAC and PHY Capability IEs). - * - * Returns 0 on success; -ve on an error. - */ -int uwb_rc_ie_setup(struct uwb_rc *uwb_rc) -{ - struct uwb_rc_evt_get_ie *ie_info = NULL; - int capacity; - - capacity = uwb_rc_get_ie(uwb_rc, &ie_info); - if (capacity < 0) - return capacity; - - mutex_lock(&uwb_rc->ies_mutex); - - uwb_rc->ies = (struct uwb_rc_cmd_set_ie *)ie_info; - uwb_rc->ies->rccb.bCommandType = UWB_RC_CET_GENERAL; - uwb_rc->ies->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_IE); - uwb_rc->ies_capacity = capacity; - - mutex_unlock(&uwb_rc->ies_mutex); - - return 0; -} - - -/* Cleanup the whole IE management subsystem */ -void uwb_rc_ie_release(struct uwb_rc *uwb_rc) -{ - kfree(uwb_rc->ies); - uwb_rc->ies = NULL; - uwb_rc->ies_capacity = 0; -} - - -static int uwb_rc_ie_add_one(struct uwb_rc *rc, const struct uwb_ie_hdr *new_ie) -{ - struct uwb_rc_cmd_set_ie *new_ies; - void *ptr, *prev_ie; - struct uwb_ie_hdr *ie; - size_t length, new_ie_len, new_capacity, size, prev_size; - - length = le16_to_cpu(rc->ies->wIELength); - new_ie_len = sizeof(struct uwb_ie_hdr) + new_ie->length; - new_capacity = sizeof(struct uwb_rc_cmd_set_ie) + length + new_ie_len; - - if (new_capacity > rc->ies_capacity) { - new_ies = krealloc(rc->ies, new_capacity, GFP_KERNEL); - if (!new_ies) - return -ENOMEM; - rc->ies = new_ies; - } - - ptr = rc->ies->IEData; - size = length; - for (;;) { - prev_ie = ptr; - prev_size = size; - ie = uwb_ie_next(&ptr, &size); - if (!ie || ie->element_id > new_ie->element_id) - break; - } - - memmove(prev_ie + new_ie_len, prev_ie, prev_size); - memcpy(prev_ie, new_ie, new_ie_len); - rc->ies->wIELength = cpu_to_le16(length + new_ie_len); - - return 0; -} - -/** - * uwb_rc_ie_add - add new IEs to the radio controller's beacon - * @uwb_rc: the radio controller. - * @ies: the buffer containing the new IE or IEs to be added to - * the device's beacon. - * @size: length of all the IEs. - * - * According to WHCI 0.95 [4.13.6] the driver will only receive the RCEB - * after the device sent the first beacon that includes the IEs specified - * in the SET IE command. We thus cannot send this command if the device is - * not beaconing. Instead, a SET IE command will be sent later right after - * we start beaconing. - * - * Setting an IE on the device will overwrite all current IEs in device. So - * we take the current IEs being transmitted by the device, insert the - * new one, and call SET IE with all the IEs needed. - * - * Returns 0 on success; or -ENOMEM. - */ -int uwb_rc_ie_add(struct uwb_rc *uwb_rc, - const struct uwb_ie_hdr *ies, size_t size) -{ - int result = 0; - void *ptr; - const struct uwb_ie_hdr *ie; - - mutex_lock(&uwb_rc->ies_mutex); - - ptr = (void *)ies; - for (;;) { - ie = uwb_ie_next(&ptr, &size); - if (!ie) - break; - - result = uwb_rc_ie_add_one(uwb_rc, ie); - if (result < 0) - break; - } - if (result >= 0) { - if (size == 0) { - if (uwb_rc->beaconing != -1) - result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies); - } else - result = -EINVAL; - } - - mutex_unlock(&uwb_rc->ies_mutex); - - return result; -} -EXPORT_SYMBOL_GPL(uwb_rc_ie_add); - - -/* - * Remove an IE from internal cache - * - * We are dealing with our internal IE cache so no need to verify that the - * IEs are valid (it has been done already). - * - * Should be called with ies_mutex held - * - * We do not break out once an IE is found in the cache. It is currently - * possible to have more than one IE with the same ID included in the - * beacon. We don't reallocate, we just mark the size smaller. - */ -static -void uwb_rc_ie_cache_rm(struct uwb_rc *uwb_rc, enum uwb_ie to_remove) -{ - struct uwb_ie_hdr *ie; - size_t len = le16_to_cpu(uwb_rc->ies->wIELength); - void *ptr; - size_t size; - - ptr = uwb_rc->ies->IEData; - size = len; - for (;;) { - ie = uwb_ie_next(&ptr, &size); - if (!ie) - break; - if (ie->element_id == to_remove) { - len -= sizeof(struct uwb_ie_hdr) + ie->length; - memmove(ie, ptr, size); - ptr = ie; - } - } - uwb_rc->ies->wIELength = cpu_to_le16(len); -} - - -/** - * uwb_rc_ie_rm - remove an IE from the radio controller's beacon - * @uwb_rc: the radio controller. - * @element_id: the element ID of the IE to remove. - * - * Only IEs previously added with uwb_rc_ie_add() may be removed. - * - * Returns 0 on success; or -ve the SET-IE command to the radio - * controller failed. - */ -int uwb_rc_ie_rm(struct uwb_rc *uwb_rc, enum uwb_ie element_id) -{ - int result = 0; - - mutex_lock(&uwb_rc->ies_mutex); - - uwb_rc_ie_cache_rm(uwb_rc, element_id); - - if (uwb_rc->beaconing != -1) - result = uwb_rc_set_ie(uwb_rc, uwb_rc->ies); - - mutex_unlock(&uwb_rc->ies_mutex); - - return result; -} -EXPORT_SYMBOL_GPL(uwb_rc_ie_rm); diff --git a/drivers/uwb/lc-dev.c b/drivers/uwb/lc-dev.c deleted file mode 100644 index 3e5c07fd6b10..000000000000 --- a/drivers/uwb/lc-dev.c +++ /dev/null @@ -1,457 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Ultra Wide Band - * Life cycle of devices - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * FIXME: docs - */ -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/device.h> -#include <linux/export.h> -#include <linux/err.h> -#include <linux/kdev_t.h> -#include <linux/random.h> -#include <linux/stat.h> -#include "uwb-internal.h" - -/* We initialize addresses to 0xff (invalid, as it is bcast) */ -static inline void uwb_dev_addr_init(struct uwb_dev_addr *addr) -{ - memset(&addr->data, 0xff, sizeof(addr->data)); -} - -static inline void uwb_mac_addr_init(struct uwb_mac_addr *addr) -{ - memset(&addr->data, 0xff, sizeof(addr->data)); -} - -/* - * Add callback @new to be called when an event occurs in @rc. - */ -int uwb_notifs_register(struct uwb_rc *rc, struct uwb_notifs_handler *new) -{ - if (mutex_lock_interruptible(&rc->notifs_chain.mutex)) - return -ERESTARTSYS; - list_add(&new->list_node, &rc->notifs_chain.list); - mutex_unlock(&rc->notifs_chain.mutex); - return 0; -} -EXPORT_SYMBOL_GPL(uwb_notifs_register); - -/* - * Remove event handler (callback) - */ -int uwb_notifs_deregister(struct uwb_rc *rc, struct uwb_notifs_handler *entry) -{ - if (mutex_lock_interruptible(&rc->notifs_chain.mutex)) - return -ERESTARTSYS; - list_del(&entry->list_node); - mutex_unlock(&rc->notifs_chain.mutex); - return 0; -} -EXPORT_SYMBOL_GPL(uwb_notifs_deregister); - -/* - * Notify all event handlers of a given event on @rc - * - * We are called with a valid reference to the device, or NULL if the - * event is not for a particular event (e.g., a BG join event). - */ -void uwb_notify(struct uwb_rc *rc, struct uwb_dev *uwb_dev, enum uwb_notifs event) -{ - struct uwb_notifs_handler *handler; - if (mutex_lock_interruptible(&rc->notifs_chain.mutex)) - return; - if (!list_empty(&rc->notifs_chain.list)) { - list_for_each_entry(handler, &rc->notifs_chain.list, list_node) { - handler->cb(handler->data, uwb_dev, event); - } - } - mutex_unlock(&rc->notifs_chain.mutex); -} - -/* - * Release the backing device of a uwb_dev that has been dynamically allocated. - */ -static void uwb_dev_sys_release(struct device *dev) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - - uwb_bce_put(uwb_dev->bce); - memset(uwb_dev, 0x69, sizeof(*uwb_dev)); - kfree(uwb_dev); -} - -/* - * Initialize a UWB device instance - * - * Alloc, zero and call this function. - */ -void uwb_dev_init(struct uwb_dev *uwb_dev) -{ - mutex_init(&uwb_dev->mutex); - device_initialize(&uwb_dev->dev); - uwb_dev->dev.release = uwb_dev_sys_release; - uwb_dev_addr_init(&uwb_dev->dev_addr); - uwb_mac_addr_init(&uwb_dev->mac_addr); - bitmap_fill(uwb_dev->streams, UWB_NUM_GLOBAL_STREAMS); -} - -static ssize_t uwb_dev_EUI_48_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - char addr[UWB_ADDR_STRSIZE]; - - uwb_mac_addr_print(addr, sizeof(addr), &uwb_dev->mac_addr); - return sprintf(buf, "%s\n", addr); -} -static DEVICE_ATTR(EUI_48, S_IRUGO, uwb_dev_EUI_48_show, NULL); - -static ssize_t uwb_dev_DevAddr_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - char addr[UWB_ADDR_STRSIZE]; - - uwb_dev_addr_print(addr, sizeof(addr), &uwb_dev->dev_addr); - return sprintf(buf, "%s\n", addr); -} -static DEVICE_ATTR(DevAddr, S_IRUGO, uwb_dev_DevAddr_show, NULL); - -/* - * Show the BPST of this device. - * - * Calculated from the receive time of the device's beacon and it's - * slot number. - */ -static ssize_t uwb_dev_BPST_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - struct uwb_beca_e *bce; - struct uwb_beacon_frame *bf; - u16 bpst; - - bce = uwb_dev->bce; - mutex_lock(&bce->mutex); - bf = (struct uwb_beacon_frame *)bce->be->BeaconInfo; - bpst = bce->be->wBPSTOffset - - (u16)(bf->Beacon_Slot_Number * UWB_BEACON_SLOT_LENGTH_US); - mutex_unlock(&bce->mutex); - - return sprintf(buf, "%d\n", bpst); -} -static DEVICE_ATTR(BPST, S_IRUGO, uwb_dev_BPST_show, NULL); - -/* - * Show the IEs a device is beaconing - * - * We need to access the beacon cache, so we just lock it really - * quick, print the IEs and unlock. - * - * We have a reference on the cache entry, so that should be - * quite safe. - */ -static ssize_t uwb_dev_IEs_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - - return uwb_bce_print_IEs(uwb_dev, uwb_dev->bce, buf, PAGE_SIZE); -} -static DEVICE_ATTR(IEs, S_IRUGO | S_IWUSR, uwb_dev_IEs_show, NULL); - -static ssize_t uwb_dev_LQE_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - struct uwb_beca_e *bce = uwb_dev->bce; - size_t result; - - mutex_lock(&bce->mutex); - result = stats_show(&uwb_dev->bce->lqe_stats, buf); - mutex_unlock(&bce->mutex); - return result; -} - -static ssize_t uwb_dev_LQE_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - struct uwb_beca_e *bce = uwb_dev->bce; - ssize_t result; - - mutex_lock(&bce->mutex); - result = stats_store(&uwb_dev->bce->lqe_stats, buf, size); - mutex_unlock(&bce->mutex); - return result; -} -static DEVICE_ATTR(LQE, S_IRUGO | S_IWUSR, uwb_dev_LQE_show, uwb_dev_LQE_store); - -static ssize_t uwb_dev_RSSI_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - struct uwb_beca_e *bce = uwb_dev->bce; - size_t result; - - mutex_lock(&bce->mutex); - result = stats_show(&uwb_dev->bce->rssi_stats, buf); - mutex_unlock(&bce->mutex); - return result; -} - -static ssize_t uwb_dev_RSSI_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - struct uwb_beca_e *bce = uwb_dev->bce; - ssize_t result; - - mutex_lock(&bce->mutex); - result = stats_store(&uwb_dev->bce->rssi_stats, buf, size); - mutex_unlock(&bce->mutex); - return result; -} -static DEVICE_ATTR(RSSI, S_IRUGO | S_IWUSR, uwb_dev_RSSI_show, uwb_dev_RSSI_store); - - -static struct attribute *uwb_dev_attrs[] = { - &dev_attr_EUI_48.attr, - &dev_attr_DevAddr.attr, - &dev_attr_BPST.attr, - &dev_attr_IEs.attr, - &dev_attr_LQE.attr, - &dev_attr_RSSI.attr, - NULL, -}; -ATTRIBUTE_GROUPS(uwb_dev); - -/* UWB bus type. */ -struct bus_type uwb_bus_type = { - .name = "uwb", - .dev_groups = uwb_dev_groups, -}; - -/** - * Device SYSFS registration - */ -static int __uwb_dev_sys_add(struct uwb_dev *uwb_dev, struct device *parent_dev) -{ - struct device *dev; - - dev = &uwb_dev->dev; - dev->parent = parent_dev; - dev_set_drvdata(dev, uwb_dev); - - return device_add(dev); -} - - -static void __uwb_dev_sys_rm(struct uwb_dev *uwb_dev) -{ - dev_set_drvdata(&uwb_dev->dev, NULL); - device_del(&uwb_dev->dev); -} - - -/** - * Register and initialize a new UWB device - * - * Did you call uwb_dev_init() on it? - * - * @parent_rc: is the parent radio controller who has the link to the - * device. When registering the UWB device that is a UWB - * Radio Controller, we point back to it. - * - * If registering the device that is part of a radio, caller has set - * rc->uwb_dev->dev. Otherwise it is to be left NULL--a new one will - * be allocated. - */ -int uwb_dev_add(struct uwb_dev *uwb_dev, struct device *parent_dev, - struct uwb_rc *parent_rc) -{ - int result; - struct device *dev; - - BUG_ON(uwb_dev == NULL); - BUG_ON(parent_dev == NULL); - BUG_ON(parent_rc == NULL); - - mutex_lock(&uwb_dev->mutex); - dev = &uwb_dev->dev; - uwb_dev->rc = parent_rc; - result = __uwb_dev_sys_add(uwb_dev, parent_dev); - if (result < 0) - printk(KERN_ERR "UWB: unable to register dev %s with sysfs: %d\n", - dev_name(dev), result); - mutex_unlock(&uwb_dev->mutex); - return result; -} - - -void uwb_dev_rm(struct uwb_dev *uwb_dev) -{ - mutex_lock(&uwb_dev->mutex); - __uwb_dev_sys_rm(uwb_dev); - mutex_unlock(&uwb_dev->mutex); -} - - -static -int __uwb_dev_try_get(struct device *dev, void *__target_uwb_dev) -{ - struct uwb_dev *target_uwb_dev = __target_uwb_dev; - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - if (uwb_dev == target_uwb_dev) { - uwb_dev_get(uwb_dev); - return 1; - } else - return 0; -} - - -/** - * Given a UWB device descriptor, validate and refcount it - * - * @returns NULL if the device does not exist or is quiescing; the ptr to - * it otherwise. - */ -struct uwb_dev *uwb_dev_try_get(struct uwb_rc *rc, struct uwb_dev *uwb_dev) -{ - if (uwb_dev_for_each(rc, __uwb_dev_try_get, uwb_dev)) - return uwb_dev; - else - return NULL; -} -EXPORT_SYMBOL_GPL(uwb_dev_try_get); - - -/** - * Remove a device from the system [grunt for other functions] - */ -int __uwb_dev_offair(struct uwb_dev *uwb_dev, struct uwb_rc *rc) -{ - struct device *dev = &uwb_dev->dev; - char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE]; - - uwb_mac_addr_print(macbuf, sizeof(macbuf), &uwb_dev->mac_addr); - uwb_dev_addr_print(devbuf, sizeof(devbuf), &uwb_dev->dev_addr); - dev_info(dev, "uwb device (mac %s dev %s) disconnected from %s %s\n", - macbuf, devbuf, - uwb_dev->dev.bus->name, - rc ? dev_name(&(rc->uwb_dev.dev)) : ""); - uwb_dev_rm(uwb_dev); - list_del(&uwb_dev->bce->node); - uwb_bce_put(uwb_dev->bce); - uwb_dev_put(uwb_dev); /* for the creation in _onair() */ - - return 0; -} - - -/** - * A device went off the air, clean up after it! - * - * This is called by the UWB Daemon (through the beacon purge function - * uwb_bcn_cache_purge) when it is detected that a device has been in - * radio silence for a while. - * - * If this device is actually a local radio controller we don't need - * to go through the offair process, as it is not registered as that. - * - * NOTE: uwb_bcn_cache.mutex is held! - */ -void uwbd_dev_offair(struct uwb_beca_e *bce) -{ - struct uwb_dev *uwb_dev; - - uwb_dev = bce->uwb_dev; - if (uwb_dev) { - uwb_notify(uwb_dev->rc, uwb_dev, UWB_NOTIF_OFFAIR); - __uwb_dev_offair(uwb_dev, uwb_dev->rc); - } -} - - -/** - * A device went on the air, start it up! - * - * This is called by the UWB Daemon when it is detected that a device - * has popped up in the radio range of the radio controller. - * - * It will just create the freaking device, register the beacon and - * stuff and yatla, done. - * - * - * NOTE: uwb_beca.mutex is held, bce->mutex is held - */ -void uwbd_dev_onair(struct uwb_rc *rc, struct uwb_beca_e *bce) -{ - int result; - struct device *dev = &rc->uwb_dev.dev; - struct uwb_dev *uwb_dev; - char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE]; - - uwb_mac_addr_print(macbuf, sizeof(macbuf), bce->mac_addr); - uwb_dev_addr_print(devbuf, sizeof(devbuf), &bce->dev_addr); - uwb_dev = kzalloc(sizeof(struct uwb_dev), GFP_KERNEL); - if (uwb_dev == NULL) { - dev_err(dev, "new device %s: Cannot allocate memory\n", - macbuf); - return; - } - uwb_dev_init(uwb_dev); /* This sets refcnt to one, we own it */ - uwb_dev->dev.bus = &uwb_bus_type; - uwb_dev->mac_addr = *bce->mac_addr; - uwb_dev->dev_addr = bce->dev_addr; - dev_set_name(&uwb_dev->dev, "%s", macbuf); - - /* plug the beacon cache */ - bce->uwb_dev = uwb_dev; - uwb_dev->bce = bce; - uwb_bce_get(bce); /* released in uwb_dev_sys_release() */ - - result = uwb_dev_add(uwb_dev, &rc->uwb_dev.dev, rc); - if (result < 0) { - dev_err(dev, "new device %s: cannot instantiate device\n", - macbuf); - goto error_dev_add; - } - - dev_info(dev, "uwb device (mac %s dev %s) connected to %s %s\n", - macbuf, devbuf, uwb_dev->dev.bus->name, - dev_name(&(rc->uwb_dev.dev))); - uwb_notify(rc, uwb_dev, UWB_NOTIF_ONAIR); - return; - -error_dev_add: - bce->uwb_dev = NULL; - uwb_bce_put(bce); - kfree(uwb_dev); - return; -} - -/** - * Iterate over the list of UWB devices, calling a @function on each - * - * See docs for bus_for_each().... - * - * @rc: radio controller for the devices. - * @function: function to call. - * @priv: data to pass to @function. - * @returns: 0 if no invocation of function() returned a value - * different to zero. That value otherwise. - */ -int uwb_dev_for_each(struct uwb_rc *rc, uwb_dev_for_each_f function, void *priv) -{ - return device_for_each_child(&rc->uwb_dev.dev, priv, function); -} -EXPORT_SYMBOL_GPL(uwb_dev_for_each); diff --git a/drivers/uwb/lc-rc.c b/drivers/uwb/lc-rc.c deleted file mode 100644 index ee31b221cdc2..000000000000 --- a/drivers/uwb/lc-rc.c +++ /dev/null @@ -1,569 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Ultra Wide Band - * Life cycle of radio controllers - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * FIXME: docs - * - * A UWB radio controller is also a UWB device, so it embeds one... - * - * List of RCs comes from the 'struct class uwb_rc_class'. - */ - -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/device.h> -#include <linux/err.h> -#include <linux/random.h> -#include <linux/kdev_t.h> -#include <linux/etherdevice.h> -#include <linux/usb.h> -#include <linux/slab.h> -#include <linux/export.h> - -#include "uwb-internal.h" - -static int uwb_rc_index_match(struct device *dev, const void *data) -{ - const int *index = data; - struct uwb_rc *rc = dev_get_drvdata(dev); - - if (rc->index == *index) - return 1; - return 0; -} - -static struct uwb_rc *uwb_rc_find_by_index(int index) -{ - struct device *dev; - struct uwb_rc *rc = NULL; - - dev = class_find_device(&uwb_rc_class, NULL, &index, uwb_rc_index_match); - if (dev) { - rc = dev_get_drvdata(dev); - put_device(dev); - } - - return rc; -} - -static int uwb_rc_new_index(void) -{ - int index = 0; - - for (;;) { - if (!uwb_rc_find_by_index(index)) - return index; - if (++index < 0) - index = 0; - } -} - -/** - * Release the backing device of a uwb_rc that has been dynamically allocated. - */ -static void uwb_rc_sys_release(struct device *dev) -{ - struct uwb_dev *uwb_dev = container_of(dev, struct uwb_dev, dev); - struct uwb_rc *rc = container_of(uwb_dev, struct uwb_rc, uwb_dev); - - uwb_rc_ie_release(rc); - kfree(rc); -} - - -void uwb_rc_init(struct uwb_rc *rc) -{ - struct uwb_dev *uwb_dev = &rc->uwb_dev; - - uwb_dev_init(uwb_dev); - rc->uwb_dev.dev.class = &uwb_rc_class; - rc->uwb_dev.dev.release = uwb_rc_sys_release; - uwb_rc_neh_create(rc); - rc->beaconing = -1; - rc->scan_type = UWB_SCAN_DISABLED; - INIT_LIST_HEAD(&rc->notifs_chain.list); - mutex_init(&rc->notifs_chain.mutex); - INIT_LIST_HEAD(&rc->uwb_beca.list); - mutex_init(&rc->uwb_beca.mutex); - uwb_drp_avail_init(rc); - uwb_rc_ie_init(rc); - uwb_rsv_init(rc); - uwb_rc_pal_init(rc); -} -EXPORT_SYMBOL_GPL(uwb_rc_init); - - -struct uwb_rc *uwb_rc_alloc(void) -{ - struct uwb_rc *rc; - rc = kzalloc(sizeof(*rc), GFP_KERNEL); - if (rc == NULL) - return NULL; - uwb_rc_init(rc); - return rc; -} -EXPORT_SYMBOL_GPL(uwb_rc_alloc); - -/* - * Show the ASIE that is broadcast in the UWB beacon by this uwb_rc device. - */ -static ssize_t ASIE_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - struct uwb_rc *rc = uwb_dev->rc; - struct uwb_ie_hdr *ie; - void *ptr; - size_t len; - int result = 0; - - /* init empty buffer. */ - result = scnprintf(buf, PAGE_SIZE, "\n"); - mutex_lock(&rc->ies_mutex); - /* walk IEData looking for an ASIE. */ - ptr = rc->ies->IEData; - len = le16_to_cpu(rc->ies->wIELength); - for (;;) { - ie = uwb_ie_next(&ptr, &len); - if (!ie) - break; - if (ie->element_id == UWB_APP_SPEC_IE) { - result = uwb_ie_dump_hex(ie, - ie->length + sizeof(struct uwb_ie_hdr), - buf, PAGE_SIZE); - break; - } - } - mutex_unlock(&rc->ies_mutex); - - return result; -} - -/* - * Update the ASIE that is broadcast in the UWB beacon by this uwb_rc device. - */ -static ssize_t ASIE_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - struct uwb_rc *rc = uwb_dev->rc; - char ie_buf[255]; - int result, ie_len = 0; - const char *cur_ptr = buf; - struct uwb_ie_hdr *ie; - - /* empty string means clear the ASIE. */ - if (strlen(buf) <= 1) { - uwb_rc_ie_rm(rc, UWB_APP_SPEC_IE); - return size; - } - - /* if non-empty string, convert string of hex chars to binary. */ - while (ie_len < sizeof(ie_buf)) { - int char_count; - - if (sscanf(cur_ptr, " %02hhX %n", - &(ie_buf[ie_len]), &char_count) > 0) { - ++ie_len; - /* skip chars read from cur_ptr. */ - cur_ptr += char_count; - } else { - break; - } - } - - /* validate IE length and type. */ - if (ie_len < sizeof(struct uwb_ie_hdr)) { - dev_err(dev, "%s: Invalid ASIE size %d.\n", __func__, ie_len); - return -EINVAL; - } - - ie = (struct uwb_ie_hdr *)ie_buf; - if (ie->element_id != UWB_APP_SPEC_IE) { - dev_err(dev, "%s: Invalid IE element type size = 0x%02X.\n", - __func__, ie->element_id); - return -EINVAL; - } - - /* bounds check length field from user. */ - if (ie->length > (ie_len - sizeof(struct uwb_ie_hdr))) - ie->length = ie_len - sizeof(struct uwb_ie_hdr); - - /* - * Valid ASIE received. Remove current ASIE then add the new one using - * uwb_rc_ie_add. - */ - uwb_rc_ie_rm(rc, UWB_APP_SPEC_IE); - - result = uwb_rc_ie_add(rc, ie, ie->length + sizeof(struct uwb_ie_hdr)); - - return result >= 0 ? size : result; -} -static DEVICE_ATTR_RW(ASIE); - -static struct attribute *rc_attrs[] = { - &dev_attr_mac_address.attr, - &dev_attr_scan.attr, - &dev_attr_beacon.attr, - &dev_attr_ASIE.attr, - NULL, -}; - -static const struct attribute_group rc_attr_group = { - .attrs = rc_attrs, -}; - -/* - * Registration of sysfs specific stuff - */ -static int uwb_rc_sys_add(struct uwb_rc *rc) -{ - return sysfs_create_group(&rc->uwb_dev.dev.kobj, &rc_attr_group); -} - - -static void __uwb_rc_sys_rm(struct uwb_rc *rc) -{ - sysfs_remove_group(&rc->uwb_dev.dev.kobj, &rc_attr_group); -} - -/** - * uwb_rc_mac_addr_setup - get an RC's EUI-48 address or set it - * @rc: the radio controller. - * - * If the EUI-48 address is 00:00:00:00:00:00 or FF:FF:FF:FF:FF:FF - * then a random locally administered EUI-48 is generated and set on - * the device. The probability of address collisions is sufficiently - * unlikely (1/2^40 = 9.1e-13) that they're not checked for. - */ -static -int uwb_rc_mac_addr_setup(struct uwb_rc *rc) -{ - int result; - struct device *dev = &rc->uwb_dev.dev; - struct uwb_dev *uwb_dev = &rc->uwb_dev; - char devname[UWB_ADDR_STRSIZE]; - struct uwb_mac_addr addr; - - result = uwb_rc_mac_addr_get(rc, &addr); - if (result < 0) { - dev_err(dev, "cannot retrieve UWB EUI-48 address: %d\n", result); - return result; - } - - if (uwb_mac_addr_unset(&addr) || uwb_mac_addr_bcast(&addr)) { - addr.data[0] = 0x02; /* locally administered and unicast */ - get_random_bytes(&addr.data[1], sizeof(addr.data)-1); - - result = uwb_rc_mac_addr_set(rc, &addr); - if (result < 0) { - uwb_mac_addr_print(devname, sizeof(devname), &addr); - dev_err(dev, "cannot set EUI-48 address %s: %d\n", - devname, result); - return result; - } - } - uwb_dev->mac_addr = addr; - return 0; -} - - - -static int uwb_rc_setup(struct uwb_rc *rc) -{ - int result; - struct device *dev = &rc->uwb_dev.dev; - - result = uwb_radio_setup(rc); - if (result < 0) { - dev_err(dev, "cannot setup UWB radio: %d\n", result); - goto error; - } - result = uwb_rc_mac_addr_setup(rc); - if (result < 0) { - dev_err(dev, "cannot setup UWB MAC address: %d\n", result); - goto error; - } - result = uwb_rc_dev_addr_assign(rc); - if (result < 0) { - dev_err(dev, "cannot assign UWB DevAddr: %d\n", result); - goto error; - } - result = uwb_rc_ie_setup(rc); - if (result < 0) { - dev_err(dev, "cannot setup IE subsystem: %d\n", result); - goto error_ie_setup; - } - result = uwb_rsv_setup(rc); - if (result < 0) { - dev_err(dev, "cannot setup reservation subsystem: %d\n", result); - goto error_rsv_setup; - } - uwb_dbg_add_rc(rc); - return 0; - -error_rsv_setup: - uwb_rc_ie_release(rc); -error_ie_setup: -error: - return result; -} - - -/** - * Register a new UWB radio controller - * - * Did you call uwb_rc_init() on your rc? - * - * We assume that this is being called with a > 0 refcount on - * it [through ops->{get|put}_device(). We'll take our own, though. - * - * @parent_dev is our real device, the one that provides the actual UWB device - */ -int uwb_rc_add(struct uwb_rc *rc, struct device *parent_dev, void *priv) -{ - int result; - struct device *dev; - char macbuf[UWB_ADDR_STRSIZE], devbuf[UWB_ADDR_STRSIZE]; - - rc->index = uwb_rc_new_index(); - - dev = &rc->uwb_dev.dev; - dev_set_name(dev, "uwb%d", rc->index); - - rc->priv = priv; - - init_waitqueue_head(&rc->uwbd.wq); - INIT_LIST_HEAD(&rc->uwbd.event_list); - spin_lock_init(&rc->uwbd.event_list_lock); - - uwbd_start(rc); - - result = rc->start(rc); - if (result < 0) - goto error_rc_start; - - result = uwb_rc_setup(rc); - if (result < 0) { - dev_err(dev, "cannot setup UWB radio controller: %d\n", result); - goto error_rc_setup; - } - - result = uwb_dev_add(&rc->uwb_dev, parent_dev, rc); - if (result < 0 && result != -EADDRNOTAVAIL) - goto error_dev_add; - - result = uwb_rc_sys_add(rc); - if (result < 0) { - dev_err(parent_dev, "cannot register UWB radio controller " - "dev attributes: %d\n", result); - goto error_sys_add; - } - - uwb_mac_addr_print(macbuf, sizeof(macbuf), &rc->uwb_dev.mac_addr); - uwb_dev_addr_print(devbuf, sizeof(devbuf), &rc->uwb_dev.dev_addr); - dev_info(dev, - "new uwb radio controller (mac %s dev %s) on %s %s\n", - macbuf, devbuf, parent_dev->bus->name, dev_name(parent_dev)); - rc->ready = 1; - return 0; - -error_sys_add: - uwb_dev_rm(&rc->uwb_dev); -error_dev_add: -error_rc_setup: - rc->stop(rc); -error_rc_start: - uwbd_stop(rc); - return result; -} -EXPORT_SYMBOL_GPL(uwb_rc_add); - - -static int uwb_dev_offair_helper(struct device *dev, void *priv) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - - return __uwb_dev_offair(uwb_dev, uwb_dev->rc); -} - -/* - * Remove a Radio Controller; stop beaconing/scanning, disconnect all children - */ -void uwb_rc_rm(struct uwb_rc *rc) -{ - rc->ready = 0; - - uwb_dbg_del_rc(rc); - uwb_rsv_remove_all(rc); - uwb_radio_shutdown(rc); - - rc->stop(rc); - - uwbd_stop(rc); - uwb_rc_neh_destroy(rc); - - uwb_dev_lock(&rc->uwb_dev); - rc->priv = NULL; - rc->cmd = NULL; - uwb_dev_unlock(&rc->uwb_dev); - mutex_lock(&rc->uwb_beca.mutex); - uwb_dev_for_each(rc, uwb_dev_offair_helper, NULL); - __uwb_rc_sys_rm(rc); - mutex_unlock(&rc->uwb_beca.mutex); - uwb_rsv_cleanup(rc); - uwb_beca_release(rc); - uwb_dev_rm(&rc->uwb_dev); -} -EXPORT_SYMBOL_GPL(uwb_rc_rm); - -static int find_rc_try_get(struct device *dev, const void *data) -{ - const struct uwb_rc *target_rc = data; - struct uwb_rc *rc = dev_get_drvdata(dev); - - if (rc == NULL) { - WARN_ON(1); - return 0; - } - if (rc == target_rc) { - if (rc->ready == 0) - return 0; - else - return 1; - } - return 0; -} - -/** - * Given a radio controller descriptor, validate and refcount it - * - * @returns NULL if the rc does not exist or is quiescing; the ptr to - * it otherwise. - */ -struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *target_rc) -{ - struct device *dev; - struct uwb_rc *rc = NULL; - - dev = class_find_device(&uwb_rc_class, NULL, target_rc, - find_rc_try_get); - if (dev) { - rc = dev_get_drvdata(dev); - __uwb_rc_get(rc); - put_device(dev); - } - - return rc; -} -EXPORT_SYMBOL_GPL(__uwb_rc_try_get); - -/* - * RC get for external refcount acquirers... - * - * Increments the refcount of the device and it's backend modules - */ -static inline struct uwb_rc *uwb_rc_get(struct uwb_rc *rc) -{ - if (rc->ready == 0) - return NULL; - uwb_dev_get(&rc->uwb_dev); - return rc; -} - -static int find_rc_grandpa(struct device *dev, const void *data) -{ - const struct device *grandpa_dev = data; - struct uwb_rc *rc = dev_get_drvdata(dev); - - if (rc->uwb_dev.dev.parent->parent == grandpa_dev) { - rc = uwb_rc_get(rc); - return 1; - } - return 0; -} - -/** - * Locate and refcount a radio controller given a common grand-parent - * - * @grandpa_dev Pointer to the 'grandparent' device structure. - * @returns NULL If the rc does not exist or is quiescing; the ptr to - * it otherwise, properly referenced. - * - * The Radio Control interface (or the UWB Radio Controller) is always - * an interface of a device. The parent is the interface, the - * grandparent is the device that encapsulates the interface. - * - * There is no need to lock around as the "grandpa" would be - * refcounted by the target, and to remove the referemes, the - * uwb_rc_class->sem would have to be taken--we hold it, ergo we - * should be safe. - */ -struct uwb_rc *uwb_rc_get_by_grandpa(const struct device *grandpa_dev) -{ - struct device *dev; - struct uwb_rc *rc = NULL; - - dev = class_find_device(&uwb_rc_class, NULL, grandpa_dev, - find_rc_grandpa); - if (dev) { - rc = dev_get_drvdata(dev); - put_device(dev); - } - - return rc; -} -EXPORT_SYMBOL_GPL(uwb_rc_get_by_grandpa); - -/** - * Find a radio controller by device address - * - * @returns the pointer to the radio controller, properly referenced - */ -static int find_rc_dev(struct device *dev, const void *data) -{ - const struct uwb_dev_addr *addr = data; - struct uwb_rc *rc = dev_get_drvdata(dev); - - if (rc == NULL) { - WARN_ON(1); - return 0; - } - if (!uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, addr)) { - rc = uwb_rc_get(rc); - return 1; - } - return 0; -} - -struct uwb_rc *uwb_rc_get_by_dev(const struct uwb_dev_addr *addr) -{ - struct device *dev; - struct uwb_rc *rc = NULL; - - dev = class_find_device(&uwb_rc_class, NULL, addr, find_rc_dev); - if (dev) { - rc = dev_get_drvdata(dev); - put_device(dev); - } - - return rc; -} -EXPORT_SYMBOL_GPL(uwb_rc_get_by_dev); - -/** - * Drop a reference on a radio controller - * - * This is the version that should be done by entities external to the - * UWB Radio Control stack (ie: clients of the API). - */ -void uwb_rc_put(struct uwb_rc *rc) -{ - __uwb_rc_put(rc); -} -EXPORT_SYMBOL_GPL(uwb_rc_put); diff --git a/drivers/uwb/neh.c b/drivers/uwb/neh.c deleted file mode 100644 index 1695584be412..000000000000 --- a/drivers/uwb/neh.c +++ /dev/null @@ -1,606 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * WUSB Wire Adapter: Radio Control Interface (WUSB[8]) - * Notification and Event Handling - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * The RC interface of the Host Wire Adapter (USB dongle) or WHCI PCI - * card delivers a stream of notifications and events to the - * notification end event endpoint or area. This code takes care of - * getting a buffer with that data, breaking it up in separate - * notifications and events and then deliver those. - * - * Events are answers to commands and they carry a context ID that - * associates them to the command. Notifications are that, - * notifications, they come out of the blue and have a context ID of - * zero. Think of the context ID kind of like a handler. The - * uwb_rc_neh_* code deals with managing context IDs. - * - * This is why you require a handle to operate on a UWB host. When you - * open a handle a context ID is assigned to you. - * - * So, as it is done is: - * - * 1. Add an event handler [uwb_rc_neh_add()] (assigns a ctx id) - * 2. Issue command [rc->cmd(rc, ...)] - * 3. Arm the timeout timer [uwb_rc_neh_arm()] - * 4, Release the reference to the neh [uwb_rc_neh_put()] - * 5. Wait for the callback - * 6. Command result (RCEB) is passed to the callback - * - * If (2) fails, you should remove the handle [uwb_rc_neh_rm()] - * instead of arming the timer. - * - * Handles are for using in *serialized* code, single thread. - * - * When the notification/event comes, the IRQ handler/endpoint - * callback passes the data read to uwb_rc_neh_grok() which will break - * it up in a discrete series of events, look up who is listening for - * them and execute the pertinent callbacks. - * - * If the reader detects an error while reading the data stream, call - * uwb_rc_neh_error(). - * - * CONSTRAINTS/ASSUMPTIONS: - * - * - Most notifications/events are small (less thank .5k), copying - * around is ok. - * - * - Notifications/events are ALWAYS smaller than PAGE_SIZE - * - * - Notifications/events always come in a single piece (ie: a buffer - * will always contain entire notifications/events). - * - * - we cannot know in advance how long each event is (because they - * lack a length field in their header--smart move by the standards - * body, btw). So we need a facility to get the event size given the - * header. This is what the EST code does (notif/Event Size - * Tables), check nest.c--as well, you can associate the size to - * the handle [w/ neh->extra_size()]. - * - * - Most notifications/events are fixed size; only a few are variable - * size (NEST takes care of that). - * - * - Listeners of events expect them, so they usually provide a - * buffer, as they know the size. Listeners to notifications don't, - * so we allocate their buffers dynamically. - */ -#include <linux/kernel.h> -#include <linux/timer.h> -#include <linux/slab.h> -#include <linux/err.h> -#include <linux/export.h> - -#include "uwb-internal.h" - -/* - * UWB Radio Controller Notification/Event Handle - * - * Represents an entity waiting for an event coming from the UWB Radio - * Controller with a given context id (context) and type (evt_type and - * evt). On reception of the notification/event, the callback (cb) is - * called with the event. - * - * If the timer expires before the event is received, the callback is - * called with -ETIMEDOUT as the event size. - */ -struct uwb_rc_neh { - struct kref kref; - - struct uwb_rc *rc; - u8 evt_type; - __le16 evt; - u8 context; - u8 completed; - uwb_rc_cmd_cb_f cb; - void *arg; - - struct timer_list timer; - struct list_head list_node; -}; - -static void uwb_rc_neh_timer(struct timer_list *t); - -static void uwb_rc_neh_release(struct kref *kref) -{ - struct uwb_rc_neh *neh = container_of(kref, struct uwb_rc_neh, kref); - - kfree(neh); -} - -static void uwb_rc_neh_get(struct uwb_rc_neh *neh) -{ - kref_get(&neh->kref); -} - -/** - * uwb_rc_neh_put - release reference to a neh - * @neh: the neh - */ -void uwb_rc_neh_put(struct uwb_rc_neh *neh) -{ - kref_put(&neh->kref, uwb_rc_neh_release); -} - - -/** - * Assigns @neh a context id from @rc's pool - * - * @rc: UWB Radio Controller descriptor; @rc->neh_lock taken - * @neh: Notification/Event Handle - * @returns 0 if context id was assigned ok; < 0 errno on error (if - * all the context IDs are taken). - * - * (assumes @wa is locked). - * - * NOTE: WUSB spec reserves context ids 0x00 for notifications and - * 0xff is invalid, so they must not be used. Initialization - * fills up those two in the bitmap so they are not allocated. - * - * We spread the allocation around to reduce the possibility of two - * consecutive opened @neh's getting the same context ID assigned (to - * avoid surprises with late events that timed out long time ago). So - * first we search from where @rc->ctx_roll is, if not found, we - * search from zero. - */ -static -int __uwb_rc_ctx_get(struct uwb_rc *rc, struct uwb_rc_neh *neh) -{ - int result; - result = find_next_zero_bit(rc->ctx_bm, UWB_RC_CTX_MAX, - rc->ctx_roll++); - if (result < UWB_RC_CTX_MAX) - goto found; - result = find_first_zero_bit(rc->ctx_bm, UWB_RC_CTX_MAX); - if (result < UWB_RC_CTX_MAX) - goto found; - return -ENFILE; -found: - set_bit(result, rc->ctx_bm); - neh->context = result; - return 0; -} - - -/** Releases @neh's context ID back to @rc (@rc->neh_lock is locked). */ -static -void __uwb_rc_ctx_put(struct uwb_rc *rc, struct uwb_rc_neh *neh) -{ - struct device *dev = &rc->uwb_dev.dev; - if (neh->context == 0) - return; - if (test_bit(neh->context, rc->ctx_bm) == 0) { - dev_err(dev, "context %u not set in bitmap\n", - neh->context); - WARN_ON(1); - } - clear_bit(neh->context, rc->ctx_bm); - neh->context = 0; -} - -/** - * uwb_rc_neh_add - add a neh for a radio controller command - * @rc: the radio controller - * @cmd: the radio controller command - * @expected_type: the type of the expected response event - * @expected_event: the expected event ID - * @cb: callback for when the event is received - * @arg: argument for the callback - * - * Creates a neh and adds it to the list of those waiting for an - * event. A context ID will be assigned to the command. - */ -struct uwb_rc_neh *uwb_rc_neh_add(struct uwb_rc *rc, struct uwb_rccb *cmd, - u8 expected_type, u16 expected_event, - uwb_rc_cmd_cb_f cb, void *arg) -{ - int result; - unsigned long flags; - struct device *dev = &rc->uwb_dev.dev; - struct uwb_rc_neh *neh; - - neh = kzalloc(sizeof(*neh), GFP_KERNEL); - if (neh == NULL) { - result = -ENOMEM; - goto error_kzalloc; - } - - kref_init(&neh->kref); - INIT_LIST_HEAD(&neh->list_node); - timer_setup(&neh->timer, uwb_rc_neh_timer, 0); - - neh->rc = rc; - neh->evt_type = expected_type; - neh->evt = cpu_to_le16(expected_event); - neh->cb = cb; - neh->arg = arg; - - spin_lock_irqsave(&rc->neh_lock, flags); - result = __uwb_rc_ctx_get(rc, neh); - if (result >= 0) { - cmd->bCommandContext = neh->context; - list_add_tail(&neh->list_node, &rc->neh_list); - uwb_rc_neh_get(neh); - } - spin_unlock_irqrestore(&rc->neh_lock, flags); - if (result < 0) - goto error_ctx_get; - - return neh; - -error_ctx_get: - kfree(neh); -error_kzalloc: - dev_err(dev, "cannot open handle to radio controller: %d\n", result); - return ERR_PTR(result); -} - -static void __uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh) -{ - __uwb_rc_ctx_put(rc, neh); - list_del(&neh->list_node); -} - -/** - * uwb_rc_neh_rm - remove a neh. - * @rc: the radio controller - * @neh: the neh to remove - * - * Remove an active neh immediately instead of waiting for the event - * (or a time out). - */ -void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh) -{ - unsigned long flags; - - spin_lock_irqsave(&rc->neh_lock, flags); - __uwb_rc_neh_rm(rc, neh); - spin_unlock_irqrestore(&rc->neh_lock, flags); - - del_timer_sync(&neh->timer); - uwb_rc_neh_put(neh); -} - -/** - * uwb_rc_neh_arm - arm an event handler timeout timer - * - * @rc: UWB Radio Controller - * @neh: Notification/event handler for @rc - * - * The timer is only armed if the neh is active. - */ -void uwb_rc_neh_arm(struct uwb_rc *rc, struct uwb_rc_neh *neh) -{ - unsigned long flags; - - spin_lock_irqsave(&rc->neh_lock, flags); - if (neh->context) - mod_timer(&neh->timer, - jiffies + msecs_to_jiffies(UWB_RC_CMD_TIMEOUT_MS)); - spin_unlock_irqrestore(&rc->neh_lock, flags); -} - -static void uwb_rc_neh_cb(struct uwb_rc_neh *neh, struct uwb_rceb *rceb, size_t size) -{ - (*neh->cb)(neh->rc, neh->arg, rceb, size); - uwb_rc_neh_put(neh); -} - -static bool uwb_rc_neh_match(struct uwb_rc_neh *neh, const struct uwb_rceb *rceb) -{ - return neh->evt_type == rceb->bEventType - && neh->evt == rceb->wEvent - && neh->context == rceb->bEventContext; -} - -/** - * Find the handle waiting for a RC Radio Control Event - * - * @rc: UWB Radio Controller - * @rceb: Pointer to the RCEB buffer - * @event_size: Pointer to the size of the RCEB buffer. Might be - * adjusted to take into account the @neh->extra_size - * settings. - * - * If the listener has no buffer (NULL buffer), one is allocated for - * the right size (the amount of data received). @neh->ptr will point - * to the event payload, which always starts with a 'struct - * uwb_rceb'. kfree() it when done. - */ -static -struct uwb_rc_neh *uwb_rc_neh_lookup(struct uwb_rc *rc, - const struct uwb_rceb *rceb) -{ - struct uwb_rc_neh *neh = NULL, *h; - unsigned long flags; - - spin_lock_irqsave(&rc->neh_lock, flags); - - list_for_each_entry(h, &rc->neh_list, list_node) { - if (uwb_rc_neh_match(h, rceb)) { - neh = h; - break; - } - } - - if (neh) - __uwb_rc_neh_rm(rc, neh); - - spin_unlock_irqrestore(&rc->neh_lock, flags); - - return neh; -} - - -/* - * Process notifications coming from the radio control interface - * - * @rc: UWB Radio Control Interface descriptor - * @neh: Notification/Event Handler @neh->ptr points to - * @uwb_evt->buffer. - * - * This function is called by the event/notif handling subsystem when - * notifications arrive (hwarc_probe() arms a notification/event handle - * that calls back this function for every received notification; this - * function then will rearm itself). - * - * Notification data buffers are dynamically allocated by the NEH - * handling code in neh.c [uwb_rc_neh_lookup()]. What is actually - * allocated is space to contain the notification data. - * - * Buffers are prefixed with a Radio Control Event Block (RCEB) as - * defined by the WUSB Wired-Adapter Radio Control interface. We - * just use it for the notification code. - * - * On each case statement we just transcode endianess of the different - * fields. We declare a pointer to a RCI definition of an event, and - * then to a UWB definition of the same event (which are the same, - * remember). Event if we use different pointers - */ -static -void uwb_rc_notif(struct uwb_rc *rc, struct uwb_rceb *rceb, ssize_t size) -{ - struct device *dev = &rc->uwb_dev.dev; - struct uwb_event *uwb_evt; - - if (size == -ESHUTDOWN) - return; - if (size < 0) { - dev_err(dev, "ignoring event with error code %zu\n", - size); - return; - } - - uwb_evt = kzalloc(sizeof(*uwb_evt), GFP_ATOMIC); - if (unlikely(uwb_evt == NULL)) { - dev_err(dev, "no memory to queue event 0x%02x/%04x/%02x\n", - rceb->bEventType, le16_to_cpu(rceb->wEvent), - rceb->bEventContext); - return; - } - uwb_evt->rc = __uwb_rc_get(rc); /* will be put by uwbd's uwbd_event_handle() */ - uwb_evt->ts_jiffies = jiffies; - uwb_evt->type = UWB_EVT_TYPE_NOTIF; - uwb_evt->notif.size = size; - uwb_evt->notif.rceb = rceb; - - uwbd_event_queue(uwb_evt); -} - -static void uwb_rc_neh_grok_event(struct uwb_rc *rc, struct uwb_rceb *rceb, size_t size) -{ - struct device *dev = &rc->uwb_dev.dev; - struct uwb_rc_neh *neh; - struct uwb_rceb *notif; - unsigned long flags; - - if (rceb->bEventContext == 0) { - notif = kmalloc(size, GFP_ATOMIC); - if (notif) { - memcpy(notif, rceb, size); - uwb_rc_notif(rc, notif, size); - } else - dev_err(dev, "event 0x%02x/%04x/%02x (%zu bytes): no memory\n", - rceb->bEventType, le16_to_cpu(rceb->wEvent), - rceb->bEventContext, size); - } else { - neh = uwb_rc_neh_lookup(rc, rceb); - if (neh) { - spin_lock_irqsave(&rc->neh_lock, flags); - /* to guard against a timeout */ - neh->completed = 1; - del_timer(&neh->timer); - spin_unlock_irqrestore(&rc->neh_lock, flags); - uwb_rc_neh_cb(neh, rceb, size); - } else - dev_warn(dev, "event 0x%02x/%04x/%02x (%zu bytes): nobody cared\n", - rceb->bEventType, le16_to_cpu(rceb->wEvent), - rceb->bEventContext, size); - } -} - -/** - * Given a buffer with one or more UWB RC events/notifications, break - * them up and dispatch them. - * - * @rc: UWB Radio Controller - * @buf: Buffer with the stream of notifications/events - * @buf_size: Amount of data in the buffer - * - * Note each notification/event starts always with a 'struct - * uwb_rceb', so the minimum size if 4 bytes. - * - * The device may pass us events formatted differently than expected. - * These are first filtered, potentially creating a new event in a new - * memory location. If a new event is created by the filter it is also - * freed here. - * - * For each notif/event, tries to guess the size looking at the EST - * tables, then looks for a neh that is waiting for that event and if - * found, copies the payload to the neh's buffer and calls it back. If - * not, the data is ignored. - * - * Note that if we can't find a size description in the EST tables, we - * still might find a size in the 'neh' handle in uwb_rc_neh_lookup(). - * - * Assumptions: - * - * @rc->neh_lock is NOT taken - * - * We keep track of various sizes here: - * size: contains the size of the buffer that is processed for the - * incoming event. this buffer may contain events that are not - * formatted as WHCI. - * real_size: the actual space taken by this event in the buffer. - * We need to keep track of the real size of an event to be able to - * advance the buffer correctly. - * event_size: the size of the event as expected by the core layer - * [OR] the size of the event after filtering. if the filtering - * created a new event in a new memory location then this is - * effectively the size of a new event buffer - */ -void uwb_rc_neh_grok(struct uwb_rc *rc, void *buf, size_t buf_size) -{ - struct device *dev = &rc->uwb_dev.dev; - void *itr; - struct uwb_rceb *rceb; - size_t size, real_size, event_size; - int needtofree; - - itr = buf; - size = buf_size; - while (size > 0) { - if (size < sizeof(*rceb)) { - dev_err(dev, "not enough data in event buffer to " - "process incoming events (%zu left, minimum is " - "%zu)\n", size, sizeof(*rceb)); - break; - } - - rceb = itr; - if (rc->filter_event) { - needtofree = rc->filter_event(rc, &rceb, size, - &real_size, &event_size); - if (needtofree < 0 && needtofree != -ENOANO) { - dev_err(dev, "BUG: Unable to filter event " - "(0x%02x/%04x/%02x) from " - "device. \n", rceb->bEventType, - le16_to_cpu(rceb->wEvent), - rceb->bEventContext); - break; - } - } else - needtofree = -ENOANO; - /* do real processing if there was no filtering or the - * filtering didn't act */ - if (needtofree == -ENOANO) { - ssize_t ret = uwb_est_find_size(rc, rceb, size); - if (ret < 0) - break; - if (ret > size) { - dev_err(dev, "BUG: hw sent incomplete event " - "0x%02x/%04x/%02x (%zd bytes), only got " - "%zu bytes. We don't handle that.\n", - rceb->bEventType, le16_to_cpu(rceb->wEvent), - rceb->bEventContext, ret, size); - break; - } - real_size = event_size = ret; - } - uwb_rc_neh_grok_event(rc, rceb, event_size); - - if (needtofree == 1) - kfree(rceb); - - itr += real_size; - size -= real_size; - } -} -EXPORT_SYMBOL_GPL(uwb_rc_neh_grok); - - -/** - * The entity that reads from the device notification/event channel has - * detected an error. - * - * @rc: UWB Radio Controller - * @error: Errno error code - * - */ -void uwb_rc_neh_error(struct uwb_rc *rc, int error) -{ - struct uwb_rc_neh *neh; - unsigned long flags; - - for (;;) { - spin_lock_irqsave(&rc->neh_lock, flags); - if (list_empty(&rc->neh_list)) { - spin_unlock_irqrestore(&rc->neh_lock, flags); - break; - } - neh = list_first_entry(&rc->neh_list, struct uwb_rc_neh, list_node); - __uwb_rc_neh_rm(rc, neh); - spin_unlock_irqrestore(&rc->neh_lock, flags); - - del_timer_sync(&neh->timer); - uwb_rc_neh_cb(neh, NULL, error); - } -} -EXPORT_SYMBOL_GPL(uwb_rc_neh_error); - - -static void uwb_rc_neh_timer(struct timer_list *t) -{ - struct uwb_rc_neh *neh = from_timer(neh, t, timer); - struct uwb_rc *rc = neh->rc; - unsigned long flags; - - spin_lock_irqsave(&rc->neh_lock, flags); - if (neh->completed) { - spin_unlock_irqrestore(&rc->neh_lock, flags); - return; - } - if (neh->context) - __uwb_rc_neh_rm(rc, neh); - else - neh = NULL; - spin_unlock_irqrestore(&rc->neh_lock, flags); - - if (neh) - uwb_rc_neh_cb(neh, NULL, -ETIMEDOUT); -} - -/** Initializes the @rc's neh subsystem - */ -void uwb_rc_neh_create(struct uwb_rc *rc) -{ - spin_lock_init(&rc->neh_lock); - INIT_LIST_HEAD(&rc->neh_list); - set_bit(0, rc->ctx_bm); /* 0 is reserved (see [WUSB] table 8-65) */ - set_bit(0xff, rc->ctx_bm); /* and 0xff is invalid */ - rc->ctx_roll = 1; -} - - -/** Release's the @rc's neh subsystem */ -void uwb_rc_neh_destroy(struct uwb_rc *rc) -{ - unsigned long flags; - struct uwb_rc_neh *neh; - - for (;;) { - spin_lock_irqsave(&rc->neh_lock, flags); - if (list_empty(&rc->neh_list)) { - spin_unlock_irqrestore(&rc->neh_lock, flags); - break; - } - neh = list_first_entry(&rc->neh_list, struct uwb_rc_neh, list_node); - __uwb_rc_neh_rm(rc, neh); - spin_unlock_irqrestore(&rc->neh_lock, flags); - - del_timer_sync(&neh->timer); - uwb_rc_neh_put(neh); - } -} diff --git a/drivers/uwb/pal.c b/drivers/uwb/pal.c deleted file mode 100644 index 765fd426dbd1..000000000000 --- a/drivers/uwb/pal.c +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * UWB PAL support. - * - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - */ -#include <linux/kernel.h> -#include <linux/debugfs.h> -#include <linux/uwb.h> -#include <linux/export.h> - -#include "uwb-internal.h" - -/** - * uwb_pal_init - initialize a UWB PAL - * @pal: the PAL to initialize - */ -void uwb_pal_init(struct uwb_pal *pal) -{ - INIT_LIST_HEAD(&pal->node); -} -EXPORT_SYMBOL_GPL(uwb_pal_init); - -/** - * uwb_pal_register - register a UWB PAL - * @pal: the PAL - * - * The PAL must be initialized with uwb_pal_init(). - */ -int uwb_pal_register(struct uwb_pal *pal) -{ - struct uwb_rc *rc = pal->rc; - int ret; - - if (pal->device) { - /* create a link to the uwb_rc in the PAL device's directory. */ - ret = sysfs_create_link(&pal->device->kobj, - &rc->uwb_dev.dev.kobj, "uwb_rc"); - if (ret < 0) - return ret; - /* create a link to the PAL in the UWB device's directory. */ - ret = sysfs_create_link(&rc->uwb_dev.dev.kobj, - &pal->device->kobj, pal->name); - if (ret < 0) { - sysfs_remove_link(&pal->device->kobj, "uwb_rc"); - return ret; - } - } - - pal->debugfs_dir = uwb_dbg_create_pal_dir(pal); - - mutex_lock(&rc->uwb_dev.mutex); - list_add(&pal->node, &rc->pals); - mutex_unlock(&rc->uwb_dev.mutex); - - return 0; -} -EXPORT_SYMBOL_GPL(uwb_pal_register); - -static int find_rc(struct device *dev, const void *data) -{ - const struct uwb_rc *target_rc = data; - struct uwb_rc *rc = dev_get_drvdata(dev); - - if (rc == NULL) { - WARN_ON(1); - return 0; - } - if (rc == target_rc) { - if (rc->ready == 0) - return 0; - else - return 1; - } - return 0; -} - -/** - * Given a radio controller descriptor see if it is registered. - * - * @returns false if the rc does not exist or is quiescing; true otherwise. - */ -static bool uwb_rc_class_device_exists(struct uwb_rc *target_rc) -{ - struct device *dev; - - dev = class_find_device(&uwb_rc_class, NULL, target_rc, find_rc); - - put_device(dev); - - return (dev != NULL); -} - -/** - * uwb_pal_unregister - unregister a UWB PAL - * @pal: the PAL - */ -void uwb_pal_unregister(struct uwb_pal *pal) -{ - struct uwb_rc *rc = pal->rc; - - uwb_radio_stop(pal); - - mutex_lock(&rc->uwb_dev.mutex); - list_del(&pal->node); - mutex_unlock(&rc->uwb_dev.mutex); - - debugfs_remove(pal->debugfs_dir); - - if (pal->device) { - /* remove link to the PAL in the UWB device's directory. */ - if (uwb_rc_class_device_exists(rc)) - sysfs_remove_link(&rc->uwb_dev.dev.kobj, pal->name); - - /* remove link to uwb_rc in the PAL device's directory. */ - sysfs_remove_link(&pal->device->kobj, "uwb_rc"); - } -} -EXPORT_SYMBOL_GPL(uwb_pal_unregister); - -/** - * uwb_rc_pal_init - initialize the PAL related parts of a radio controller - * @rc: the radio controller - */ -void uwb_rc_pal_init(struct uwb_rc *rc) -{ - INIT_LIST_HEAD(&rc->pals); -} diff --git a/drivers/uwb/radio.c b/drivers/uwb/radio.c deleted file mode 100644 index 240dd755927e..000000000000 --- a/drivers/uwb/radio.c +++ /dev/null @@ -1,196 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * UWB radio (channel) management. - * - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - */ -#include <linux/kernel.h> -#include <linux/uwb.h> -#include <linux/export.h> - -#include "uwb-internal.h" - - -static int uwb_radio_select_channel(struct uwb_rc *rc) -{ - /* - * Default to channel 9 (BG1, TFC1) unless the user has - * selected a specific channel or there are no active PALs. - */ - if (rc->active_pals == 0) - return -1; - if (rc->beaconing_forced) - return rc->beaconing_forced; - return 9; -} - - -/* - * Notify all active PALs that the channel has changed. - */ -static void uwb_radio_channel_changed(struct uwb_rc *rc, int channel) -{ - struct uwb_pal *pal; - - list_for_each_entry(pal, &rc->pals, node) { - if (pal->channel && channel != pal->channel) { - pal->channel = channel; - if (pal->channel_changed) - pal->channel_changed(pal, pal->channel); - } - } -} - -/* - * Change to a new channel and notify any active PALs of the new - * channel. - * - * When stopping the radio, PALs need to be notified first so they can - * terminate any active reservations. - */ -static int uwb_radio_change_channel(struct uwb_rc *rc, int channel) -{ - int ret = 0; - struct device *dev = &rc->uwb_dev.dev; - - dev_dbg(dev, "%s: channel = %d, rc->beaconing = %d\n", __func__, - channel, rc->beaconing); - - if (channel == -1) - uwb_radio_channel_changed(rc, channel); - - if (channel != rc->beaconing) { - if (rc->beaconing != -1 && channel != -1) { - /* - * FIXME: should signal the channel change - * with a Channel Change IE. - */ - ret = uwb_radio_change_channel(rc, -1); - if (ret < 0) - return ret; - } - ret = uwb_rc_beacon(rc, channel, 0); - } - - if (channel != -1) - uwb_radio_channel_changed(rc, rc->beaconing); - - return ret; -} - -/** - * uwb_radio_start - request that the radio be started - * @pal: the PAL making the request. - * - * If the radio is not already active, a suitable channel is selected - * and beacons are started. - */ -int uwb_radio_start(struct uwb_pal *pal) -{ - struct uwb_rc *rc = pal->rc; - int ret = 0; - - mutex_lock(&rc->uwb_dev.mutex); - - if (!pal->channel) { - pal->channel = -1; - rc->active_pals++; - ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc)); - } - - mutex_unlock(&rc->uwb_dev.mutex); - return ret; -} -EXPORT_SYMBOL_GPL(uwb_radio_start); - -/** - * uwb_radio_stop - request that the radio be stopped. - * @pal: the PAL making the request. - * - * Stops the radio if no other PAL is making use of it. - */ -void uwb_radio_stop(struct uwb_pal *pal) -{ - struct uwb_rc *rc = pal->rc; - - mutex_lock(&rc->uwb_dev.mutex); - - if (pal->channel) { - rc->active_pals--; - uwb_radio_change_channel(rc, uwb_radio_select_channel(rc)); - pal->channel = 0; - } - - mutex_unlock(&rc->uwb_dev.mutex); -} -EXPORT_SYMBOL_GPL(uwb_radio_stop); - -/* - * uwb_radio_force_channel - force a specific channel to be used - * @rc: the radio controller. - * @channel: the channel to use; -1 to force the radio to stop; 0 to - * use the default channel selection algorithm. - */ -int uwb_radio_force_channel(struct uwb_rc *rc, int channel) -{ - int ret = 0; - - mutex_lock(&rc->uwb_dev.mutex); - - rc->beaconing_forced = channel; - ret = uwb_radio_change_channel(rc, uwb_radio_select_channel(rc)); - - mutex_unlock(&rc->uwb_dev.mutex); - return ret; -} - -/* - * uwb_radio_setup - setup the radio manager - * @rc: the radio controller. - * - * The radio controller is reset to ensure it's in a known state - * before it's used. - */ -int uwb_radio_setup(struct uwb_rc *rc) -{ - return uwb_rc_reset(rc); -} - -/* - * uwb_radio_reset_state - reset any radio manager state - * @rc: the radio controller. - * - * All internal radio manager state is reset to values corresponding - * to a reset radio controller. - */ -void uwb_radio_reset_state(struct uwb_rc *rc) -{ - struct uwb_pal *pal; - - mutex_lock(&rc->uwb_dev.mutex); - - list_for_each_entry(pal, &rc->pals, node) { - if (pal->channel) { - pal->channel = -1; - if (pal->channel_changed) - pal->channel_changed(pal, -1); - } - } - - rc->beaconing = -1; - rc->scanning = -1; - - mutex_unlock(&rc->uwb_dev.mutex); -} - -/* - * uwb_radio_shutdown - shutdown the radio manager - * @rc: the radio controller. - * - * The radio controller is reset. - */ -void uwb_radio_shutdown(struct uwb_rc *rc) -{ - uwb_radio_reset_state(rc); - uwb_rc_reset(rc); -} diff --git a/drivers/uwb/reset.c b/drivers/uwb/reset.c deleted file mode 100644 index 8fc7c14d903e..000000000000 --- a/drivers/uwb/reset.c +++ /dev/null @@ -1,379 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Ultra Wide Band - * UWB basic command support and radio reset - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * FIXME: - * - * - docs - * - * - Now we are serializing (using the uwb_dev->mutex) the command - * execution; it should be parallelized as much as possible some - * day. - */ -#include <linux/kernel.h> -#include <linux/err.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/export.h> - -#include "uwb-internal.h" - -/** - * Command result codes (WUSB1.0[T8-69]) - */ -static -const char *__strerror[] = { - "success", - "failure", - "hardware failure", - "no more slots", - "beacon is too large", - "invalid parameter", - "unsupported power level", - "time out (wa) or invalid ie data (whci)", - "beacon size exceeded", - "cancelled", - "invalid state", - "invalid size", - "ack not received", - "no more asie notification", -}; - - -/** Return a string matching the given error code */ -const char *uwb_rc_strerror(unsigned code) -{ - if (code == 255) - return "time out"; - if (code >= ARRAY_SIZE(__strerror)) - return "unknown error"; - return __strerror[code]; -} - -int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name, - struct uwb_rccb *cmd, size_t cmd_size, - u8 expected_type, u16 expected_event, - uwb_rc_cmd_cb_f cb, void *arg) -{ - struct device *dev = &rc->uwb_dev.dev; - struct uwb_rc_neh *neh; - int needtofree = 0; - int result; - - uwb_dev_lock(&rc->uwb_dev); /* Protect against rc->priv being removed */ - if (rc->priv == NULL) { - uwb_dev_unlock(&rc->uwb_dev); - return -ESHUTDOWN; - } - - if (rc->filter_cmd) { - needtofree = rc->filter_cmd(rc, &cmd, &cmd_size); - if (needtofree < 0 && needtofree != -ENOANO) { - dev_err(dev, "%s: filter error: %d\n", - cmd_name, needtofree); - uwb_dev_unlock(&rc->uwb_dev); - return needtofree; - } - } - - neh = uwb_rc_neh_add(rc, cmd, expected_type, expected_event, cb, arg); - if (IS_ERR(neh)) { - result = PTR_ERR(neh); - uwb_dev_unlock(&rc->uwb_dev); - goto out; - } - - result = rc->cmd(rc, cmd, cmd_size); - uwb_dev_unlock(&rc->uwb_dev); - if (result < 0) - uwb_rc_neh_rm(rc, neh); - else - uwb_rc_neh_arm(rc, neh); - uwb_rc_neh_put(neh); -out: - if (needtofree == 1) - kfree(cmd); - return result < 0 ? result : 0; -} -EXPORT_SYMBOL_GPL(uwb_rc_cmd_async); - -struct uwb_rc_cmd_done_params { - struct completion completion; - struct uwb_rceb *reply; - ssize_t reply_size; -}; - -static void uwb_rc_cmd_done(struct uwb_rc *rc, void *arg, - struct uwb_rceb *reply, ssize_t reply_size) -{ - struct uwb_rc_cmd_done_params *p = (struct uwb_rc_cmd_done_params *)arg; - - if (reply_size > 0) { - if (p->reply) - reply_size = min(p->reply_size, reply_size); - else - p->reply = kmalloc(reply_size, GFP_ATOMIC); - - if (p->reply) - memcpy(p->reply, reply, reply_size); - else - reply_size = -ENOMEM; - } - p->reply_size = reply_size; - complete(&p->completion); -} - - -/** - * Generic function for issuing commands to the Radio Control Interface - * - * @rc: UWB Radio Control descriptor - * @cmd_name: Name of the command being issued (for error messages) - * @cmd: Pointer to rccb structure containing the command; - * normally you embed this structure as the first member of - * the full command structure. - * @cmd_size: Size of the whole command buffer pointed to by @cmd. - * @reply: Pointer to where to store the reply - * @reply_size: @reply's size - * @expected_type: Expected type in the return event - * @expected_event: Expected event code in the return event - * @preply: Here a pointer to where the event data is received will - * be stored. Once done with the data, free with kfree(). - * - * This function is generic; it works for commands that return a fixed - * and known size or for commands that return a variable amount of data. - * - * If a buffer is provided, that is used, although it could be chopped - * to the maximum size of the buffer. If the buffer is NULL, then one - * be allocated in *preply with the whole contents of the reply. - * - * @rc needs to be referenced - */ -static -ssize_t __uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name, - struct uwb_rccb *cmd, size_t cmd_size, - struct uwb_rceb *reply, size_t reply_size, - u8 expected_type, u16 expected_event, - struct uwb_rceb **preply) -{ - ssize_t result = 0; - struct device *dev = &rc->uwb_dev.dev; - struct uwb_rc_cmd_done_params params; - - init_completion(¶ms.completion); - params.reply = reply; - params.reply_size = reply_size; - - result = uwb_rc_cmd_async(rc, cmd_name, cmd, cmd_size, - expected_type, expected_event, - uwb_rc_cmd_done, ¶ms); - if (result) - return result; - - wait_for_completion(¶ms.completion); - - if (preply) - *preply = params.reply; - - if (params.reply_size < 0) - dev_err(dev, "%s: confirmation event 0x%02x/%04x/%02x " - "reception failed: %d\n", cmd_name, - expected_type, expected_event, cmd->bCommandContext, - (int)params.reply_size); - return params.reply_size; -} - - -/** - * Generic function for issuing commands to the Radio Control Interface - * - * @rc: UWB Radio Control descriptor - * @cmd_name: Name of the command being issued (for error messages) - * @cmd: Pointer to rccb structure containing the command; - * normally you embed this structure as the first member of - * the full command structure. - * @cmd_size: Size of the whole command buffer pointed to by @cmd. - * @reply: Pointer to the beginning of the confirmation event - * buffer. Normally bigger than an 'struct hwarc_rceb'. - * You need to fill out reply->bEventType and reply->wEvent (in - * cpu order) as the function will use them to verify the - * confirmation event. - * @reply_size: Size of the reply buffer - * - * The function checks that the length returned in the reply is at - * least as big as @reply_size; if not, it will be deemed an error and - * -EIO returned. - * - * @rc needs to be referenced - */ -ssize_t uwb_rc_cmd(struct uwb_rc *rc, const char *cmd_name, - struct uwb_rccb *cmd, size_t cmd_size, - struct uwb_rceb *reply, size_t reply_size) -{ - struct device *dev = &rc->uwb_dev.dev; - ssize_t result; - - result = __uwb_rc_cmd(rc, cmd_name, - cmd, cmd_size, reply, reply_size, - reply->bEventType, reply->wEvent, NULL); - - if (result > 0 && result < reply_size) { - dev_err(dev, "%s: not enough data returned for decoding reply " - "(%zu bytes received vs at least %zu needed)\n", - cmd_name, result, reply_size); - result = -EIO; - } - return result; -} -EXPORT_SYMBOL_GPL(uwb_rc_cmd); - - -/** - * Generic function for issuing commands to the Radio Control - * Interface that return an unknown amount of data - * - * @rc: UWB Radio Control descriptor - * @cmd_name: Name of the command being issued (for error messages) - * @cmd: Pointer to rccb structure containing the command; - * normally you embed this structure as the first member of - * the full command structure. - * @cmd_size: Size of the whole command buffer pointed to by @cmd. - * @expected_type: Expected type in the return event - * @expected_event: Expected event code in the return event - * @preply: Here a pointer to where the event data is received will - * be stored. Once done with the data, free with kfree(). - * - * The function checks that the length returned in the reply is at - * least as big as a 'struct uwb_rceb *'; if not, it will be deemed an - * error and -EIO returned. - * - * @rc needs to be referenced - */ -ssize_t uwb_rc_vcmd(struct uwb_rc *rc, const char *cmd_name, - struct uwb_rccb *cmd, size_t cmd_size, - u8 expected_type, u16 expected_event, - struct uwb_rceb **preply) -{ - return __uwb_rc_cmd(rc, cmd_name, cmd, cmd_size, NULL, 0, - expected_type, expected_event, preply); -} -EXPORT_SYMBOL_GPL(uwb_rc_vcmd); - - -/** - * Reset a UWB Host Controller (and all radio settings) - * - * @rc: Host Controller descriptor - * @returns: 0 if ok, < 0 errno code on error - * - * We put the command on kmalloc'ed memory as some arches cannot do - * USB from the stack. The reply event is copied from an stage buffer, - * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details. - */ -int uwb_rc_reset(struct uwb_rc *rc) -{ - int result = -ENOMEM; - struct uwb_rc_evt_confirm reply; - struct uwb_rccb *cmd; - size_t cmd_size = sizeof(*cmd); - - mutex_lock(&rc->uwb_dev.mutex); - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - goto error_kzalloc; - cmd->bCommandType = UWB_RC_CET_GENERAL; - cmd->wCommand = cpu_to_le16(UWB_RC_CMD_RESET); - reply.rceb.bEventType = UWB_RC_CET_GENERAL; - reply.rceb.wEvent = UWB_RC_CMD_RESET; - result = uwb_rc_cmd(rc, "RESET", cmd, cmd_size, - &reply.rceb, sizeof(reply)); - if (result < 0) - goto error_cmd; - if (reply.bResultCode != UWB_RC_RES_SUCCESS) { - dev_err(&rc->uwb_dev.dev, - "RESET: command execution failed: %s (%d)\n", - uwb_rc_strerror(reply.bResultCode), reply.bResultCode); - result = -EIO; - } -error_cmd: - kfree(cmd); -error_kzalloc: - mutex_unlock(&rc->uwb_dev.mutex); - return result; -} - -int uwbd_msg_handle_reset(struct uwb_event *evt) -{ - struct uwb_rc *rc = evt->rc; - int ret; - - dev_info(&rc->uwb_dev.dev, "resetting radio controller\n"); - ret = rc->reset(rc); - if (ret < 0) { - dev_err(&rc->uwb_dev.dev, "failed to reset hardware: %d\n", ret); - goto error; - } - return 0; -error: - /* Nothing can be done except try the reset again. Wait a bit - to avoid reset loops during probe() or remove(). */ - msleep(1000); - uwb_rc_reset_all(rc); - return ret; -} - -/** - * uwb_rc_reset_all - request a reset of the radio controller and PALs - * @rc: the radio controller of the hardware device to be reset. - * - * The full hardware reset of the radio controller and all the PALs - * will be scheduled. - */ -void uwb_rc_reset_all(struct uwb_rc *rc) -{ - struct uwb_event *evt; - - evt = kzalloc(sizeof(struct uwb_event), GFP_ATOMIC); - if (unlikely(evt == NULL)) - return; - - evt->rc = __uwb_rc_get(rc); /* will be put by uwbd's uwbd_event_handle() */ - evt->ts_jiffies = jiffies; - evt->type = UWB_EVT_TYPE_MSG; - evt->message = UWB_EVT_MSG_RESET; - - uwbd_event_queue(evt); -} -EXPORT_SYMBOL_GPL(uwb_rc_reset_all); - -void uwb_rc_pre_reset(struct uwb_rc *rc) -{ - rc->stop(rc); - uwbd_flush(rc); - - uwb_radio_reset_state(rc); - uwb_rsv_remove_all(rc); -} -EXPORT_SYMBOL_GPL(uwb_rc_pre_reset); - -int uwb_rc_post_reset(struct uwb_rc *rc) -{ - int ret; - - ret = rc->start(rc); - if (ret) - goto out; - ret = uwb_rc_mac_addr_set(rc, &rc->uwb_dev.mac_addr); - if (ret) - goto out; - ret = uwb_rc_dev_addr_set(rc, &rc->uwb_dev.dev_addr); - if (ret) - goto out; -out: - return ret; -} -EXPORT_SYMBOL_GPL(uwb_rc_post_reset); diff --git a/drivers/uwb/rsv.c b/drivers/uwb/rsv.c deleted file mode 100644 index ec924deb0a32..000000000000 --- a/drivers/uwb/rsv.c +++ /dev/null @@ -1,1000 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * UWB reservation management. - * - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - */ -#include <linux/kernel.h> -#include <linux/uwb.h> -#include <linux/slab.h> -#include <linux/random.h> -#include <linux/export.h> - -#include "uwb-internal.h" - -static void uwb_rsv_timer(struct timer_list *t); - -static const char *rsv_states[] = { - [UWB_RSV_STATE_NONE] = "none ", - [UWB_RSV_STATE_O_INITIATED] = "o initiated ", - [UWB_RSV_STATE_O_PENDING] = "o pending ", - [UWB_RSV_STATE_O_MODIFIED] = "o modified ", - [UWB_RSV_STATE_O_ESTABLISHED] = "o established ", - [UWB_RSV_STATE_O_TO_BE_MOVED] = "o to be moved ", - [UWB_RSV_STATE_O_MOVE_EXPANDING] = "o move expanding", - [UWB_RSV_STATE_O_MOVE_COMBINING] = "o move combining", - [UWB_RSV_STATE_O_MOVE_REDUCING] = "o move reducing ", - [UWB_RSV_STATE_T_ACCEPTED] = "t accepted ", - [UWB_RSV_STATE_T_CONFLICT] = "t conflict ", - [UWB_RSV_STATE_T_PENDING] = "t pending ", - [UWB_RSV_STATE_T_DENIED] = "t denied ", - [UWB_RSV_STATE_T_RESIZED] = "t resized ", - [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = "t expanding acc ", - [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = "t expanding conf", - [UWB_RSV_STATE_T_EXPANDING_PENDING] = "t expanding pend", - [UWB_RSV_STATE_T_EXPANDING_DENIED] = "t expanding den ", -}; - -static const char *rsv_types[] = { - [UWB_DRP_TYPE_ALIEN_BP] = "alien-bp", - [UWB_DRP_TYPE_HARD] = "hard", - [UWB_DRP_TYPE_SOFT] = "soft", - [UWB_DRP_TYPE_PRIVATE] = "private", - [UWB_DRP_TYPE_PCA] = "pca", -}; - -bool uwb_rsv_has_two_drp_ies(struct uwb_rsv *rsv) -{ - static const bool has_two_drp_ies[] = { - [UWB_RSV_STATE_O_INITIATED] = false, - [UWB_RSV_STATE_O_PENDING] = false, - [UWB_RSV_STATE_O_MODIFIED] = false, - [UWB_RSV_STATE_O_ESTABLISHED] = false, - [UWB_RSV_STATE_O_TO_BE_MOVED] = false, - [UWB_RSV_STATE_O_MOVE_COMBINING] = false, - [UWB_RSV_STATE_O_MOVE_REDUCING] = false, - [UWB_RSV_STATE_O_MOVE_EXPANDING] = true, - [UWB_RSV_STATE_T_ACCEPTED] = false, - [UWB_RSV_STATE_T_CONFLICT] = false, - [UWB_RSV_STATE_T_PENDING] = false, - [UWB_RSV_STATE_T_DENIED] = false, - [UWB_RSV_STATE_T_RESIZED] = false, - [UWB_RSV_STATE_T_EXPANDING_ACCEPTED] = true, - [UWB_RSV_STATE_T_EXPANDING_CONFLICT] = true, - [UWB_RSV_STATE_T_EXPANDING_PENDING] = true, - [UWB_RSV_STATE_T_EXPANDING_DENIED] = true, - }; - - return has_two_drp_ies[rsv->state]; -} - -/** - * uwb_rsv_state_str - return a string for a reservation state - * @state: the reservation state. - */ -const char *uwb_rsv_state_str(enum uwb_rsv_state state) -{ - if (state < UWB_RSV_STATE_NONE || state >= UWB_RSV_STATE_LAST) - return "unknown"; - return rsv_states[state]; -} -EXPORT_SYMBOL_GPL(uwb_rsv_state_str); - -/** - * uwb_rsv_type_str - return a string for a reservation type - * @type: the reservation type - */ -const char *uwb_rsv_type_str(enum uwb_drp_type type) -{ - if (type < UWB_DRP_TYPE_ALIEN_BP || type > UWB_DRP_TYPE_PCA) - return "invalid"; - return rsv_types[type]; -} -EXPORT_SYMBOL_GPL(uwb_rsv_type_str); - -void uwb_rsv_dump(char *text, struct uwb_rsv *rsv) -{ - struct device *dev = &rsv->rc->uwb_dev.dev; - struct uwb_dev_addr devaddr; - char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE]; - - uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr); - if (rsv->target.type == UWB_RSV_TARGET_DEV) - devaddr = rsv->target.dev->dev_addr; - else - devaddr = rsv->target.devaddr; - uwb_dev_addr_print(target, sizeof(target), &devaddr); - - dev_dbg(dev, "rsv %s %s -> %s: %s\n", - text, owner, target, uwb_rsv_state_str(rsv->state)); -} - -static void uwb_rsv_release(struct kref *kref) -{ - struct uwb_rsv *rsv = container_of(kref, struct uwb_rsv, kref); - - kfree(rsv); -} - -void uwb_rsv_get(struct uwb_rsv *rsv) -{ - kref_get(&rsv->kref); -} - -void uwb_rsv_put(struct uwb_rsv *rsv) -{ - kref_put(&rsv->kref, uwb_rsv_release); -} - -/* - * Get a free stream index for a reservation. - * - * If the target is a DevAddr (e.g., a WUSB cluster reservation) then - * the stream is allocated from a pool of per-RC stream indexes, - * otherwise a unique stream index for the target is selected. - */ -static int uwb_rsv_get_stream(struct uwb_rsv *rsv) -{ - struct uwb_rc *rc = rsv->rc; - struct device *dev = &rc->uwb_dev.dev; - unsigned long *streams_bm; - int stream; - - switch (rsv->target.type) { - case UWB_RSV_TARGET_DEV: - streams_bm = rsv->target.dev->streams; - break; - case UWB_RSV_TARGET_DEVADDR: - streams_bm = rc->uwb_dev.streams; - break; - default: - return -EINVAL; - } - - stream = find_first_zero_bit(streams_bm, UWB_NUM_STREAMS); - if (stream >= UWB_NUM_STREAMS) { - dev_err(dev, "%s: no available stream found\n", __func__); - return -EBUSY; - } - - rsv->stream = stream; - set_bit(stream, streams_bm); - - dev_dbg(dev, "get stream %d\n", rsv->stream); - - return 0; -} - -static void uwb_rsv_put_stream(struct uwb_rsv *rsv) -{ - struct uwb_rc *rc = rsv->rc; - struct device *dev = &rc->uwb_dev.dev; - unsigned long *streams_bm; - - switch (rsv->target.type) { - case UWB_RSV_TARGET_DEV: - streams_bm = rsv->target.dev->streams; - break; - case UWB_RSV_TARGET_DEVADDR: - streams_bm = rc->uwb_dev.streams; - break; - default: - return; - } - - clear_bit(rsv->stream, streams_bm); - - dev_dbg(dev, "put stream %d\n", rsv->stream); -} - -void uwb_rsv_backoff_win_timer(struct timer_list *t) -{ - struct uwb_drp_backoff_win *bow = from_timer(bow, t, timer); - struct uwb_rc *rc = container_of(bow, struct uwb_rc, bow); - struct device *dev = &rc->uwb_dev.dev; - - bow->can_reserve_extra_mases = true; - if (bow->total_expired <= 4) { - bow->total_expired++; - } else { - /* after 4 backoff window has expired we can exit from - * the backoff procedure */ - bow->total_expired = 0; - bow->window = UWB_DRP_BACKOFF_WIN_MIN >> 1; - } - dev_dbg(dev, "backoff_win_timer total_expired=%d, n=%d\n", bow->total_expired, bow->n); - - /* try to relocate all the "to be moved" relocations */ - uwb_rsv_handle_drp_avail_change(rc); -} - -void uwb_rsv_backoff_win_increment(struct uwb_rc *rc) -{ - struct uwb_drp_backoff_win *bow = &rc->bow; - struct device *dev = &rc->uwb_dev.dev; - unsigned timeout_us; - - dev_dbg(dev, "backoff_win_increment: window=%d\n", bow->window); - - bow->can_reserve_extra_mases = false; - - if((bow->window << 1) == UWB_DRP_BACKOFF_WIN_MAX) - return; - - bow->window <<= 1; - bow->n = prandom_u32() & (bow->window - 1); - dev_dbg(dev, "new_window=%d, n=%d\n", bow->window, bow->n); - - /* reset the timer associated variables */ - timeout_us = bow->n * UWB_SUPERFRAME_LENGTH_US; - bow->total_expired = 0; - mod_timer(&bow->timer, jiffies + usecs_to_jiffies(timeout_us)); -} - -static void uwb_rsv_stroke_timer(struct uwb_rsv *rsv) -{ - int sframes = UWB_MAX_LOST_BEACONS; - - /* - * Multicast reservations can become established within 1 - * super frame and should not be terminated if no response is - * received. - */ - if (rsv->state == UWB_RSV_STATE_NONE) { - sframes = 0; - } else if (rsv->is_multicast) { - if (rsv->state == UWB_RSV_STATE_O_INITIATED - || rsv->state == UWB_RSV_STATE_O_MOVE_EXPANDING - || rsv->state == UWB_RSV_STATE_O_MOVE_COMBINING - || rsv->state == UWB_RSV_STATE_O_MOVE_REDUCING) - sframes = 1; - if (rsv->state == UWB_RSV_STATE_O_ESTABLISHED) - sframes = 0; - - } - - if (sframes > 0) { - /* - * Add an additional 2 superframes to account for the - * time to send the SET DRP IE command. - */ - unsigned timeout_us = (sframes + 2) * UWB_SUPERFRAME_LENGTH_US; - mod_timer(&rsv->timer, jiffies + usecs_to_jiffies(timeout_us)); - } else - del_timer(&rsv->timer); -} - -/* - * Update a reservations state, and schedule an update of the - * transmitted DRP IEs. - */ -static void uwb_rsv_state_update(struct uwb_rsv *rsv, - enum uwb_rsv_state new_state) -{ - rsv->state = new_state; - rsv->ie_valid = false; - - uwb_rsv_dump("SU", rsv); - - uwb_rsv_stroke_timer(rsv); - uwb_rsv_sched_update(rsv->rc); -} - -static void uwb_rsv_callback(struct uwb_rsv *rsv) -{ - if (rsv->callback) - rsv->callback(rsv); -} - -void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state) -{ - struct uwb_rsv_move *mv = &rsv->mv; - - if (rsv->state == new_state) { - switch (rsv->state) { - case UWB_RSV_STATE_O_ESTABLISHED: - case UWB_RSV_STATE_O_MOVE_EXPANDING: - case UWB_RSV_STATE_O_MOVE_COMBINING: - case UWB_RSV_STATE_O_MOVE_REDUCING: - case UWB_RSV_STATE_T_ACCEPTED: - case UWB_RSV_STATE_T_EXPANDING_ACCEPTED: - case UWB_RSV_STATE_T_RESIZED: - case UWB_RSV_STATE_NONE: - uwb_rsv_stroke_timer(rsv); - break; - default: - /* Expecting a state transition so leave timer - as-is. */ - break; - } - return; - } - - uwb_rsv_dump("SC", rsv); - - switch (new_state) { - case UWB_RSV_STATE_NONE: - uwb_rsv_state_update(rsv, UWB_RSV_STATE_NONE); - uwb_rsv_remove(rsv); - uwb_rsv_callback(rsv); - break; - case UWB_RSV_STATE_O_INITIATED: - uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_INITIATED); - break; - case UWB_RSV_STATE_O_PENDING: - uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_PENDING); - break; - case UWB_RSV_STATE_O_MODIFIED: - /* in the companion there are the MASes to drop */ - bitmap_andnot(rsv->mas.bm, rsv->mas.bm, mv->companion_mas.bm, UWB_NUM_MAS); - uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MODIFIED); - break; - case UWB_RSV_STATE_O_ESTABLISHED: - if (rsv->state == UWB_RSV_STATE_O_MODIFIED - || rsv->state == UWB_RSV_STATE_O_MOVE_REDUCING) { - uwb_drp_avail_release(rsv->rc, &mv->companion_mas); - rsv->needs_release_companion_mas = false; - } - uwb_drp_avail_reserve(rsv->rc, &rsv->mas); - uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_ESTABLISHED); - uwb_rsv_callback(rsv); - break; - case UWB_RSV_STATE_O_MOVE_EXPANDING: - rsv->needs_release_companion_mas = true; - uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING); - break; - case UWB_RSV_STATE_O_MOVE_COMBINING: - rsv->needs_release_companion_mas = false; - uwb_drp_avail_reserve(rsv->rc, &mv->companion_mas); - bitmap_or(rsv->mas.bm, rsv->mas.bm, mv->companion_mas.bm, UWB_NUM_MAS); - rsv->mas.safe += mv->companion_mas.safe; - rsv->mas.unsafe += mv->companion_mas.unsafe; - uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_COMBINING); - break; - case UWB_RSV_STATE_O_MOVE_REDUCING: - bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS); - rsv->needs_release_companion_mas = true; - rsv->mas.safe = mv->final_mas.safe; - rsv->mas.unsafe = mv->final_mas.unsafe; - bitmap_copy(rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS); - bitmap_copy(rsv->mas.unsafe_bm, mv->final_mas.unsafe_bm, UWB_NUM_MAS); - uwb_rsv_state_update(rsv, UWB_RSV_STATE_O_MOVE_REDUCING); - break; - case UWB_RSV_STATE_T_ACCEPTED: - case UWB_RSV_STATE_T_RESIZED: - rsv->needs_release_companion_mas = false; - uwb_drp_avail_reserve(rsv->rc, &rsv->mas); - uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_ACCEPTED); - uwb_rsv_callback(rsv); - break; - case UWB_RSV_STATE_T_DENIED: - uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_DENIED); - break; - case UWB_RSV_STATE_T_CONFLICT: - uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_CONFLICT); - break; - case UWB_RSV_STATE_T_PENDING: - uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_PENDING); - break; - case UWB_RSV_STATE_T_EXPANDING_ACCEPTED: - rsv->needs_release_companion_mas = true; - uwb_drp_avail_reserve(rsv->rc, &mv->companion_mas); - uwb_rsv_state_update(rsv, UWB_RSV_STATE_T_EXPANDING_ACCEPTED); - break; - default: - dev_err(&rsv->rc->uwb_dev.dev, "unhandled state: %s (%d)\n", - uwb_rsv_state_str(new_state), new_state); - } -} - -static void uwb_rsv_handle_timeout_work(struct work_struct *work) -{ - struct uwb_rsv *rsv = container_of(work, struct uwb_rsv, - handle_timeout_work); - struct uwb_rc *rc = rsv->rc; - - mutex_lock(&rc->rsvs_mutex); - - uwb_rsv_dump("TO", rsv); - - switch (rsv->state) { - case UWB_RSV_STATE_O_INITIATED: - if (rsv->is_multicast) { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); - goto unlock; - } - break; - case UWB_RSV_STATE_O_MOVE_EXPANDING: - if (rsv->is_multicast) { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING); - goto unlock; - } - break; - case UWB_RSV_STATE_O_MOVE_COMBINING: - if (rsv->is_multicast) { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING); - goto unlock; - } - break; - case UWB_RSV_STATE_O_MOVE_REDUCING: - if (rsv->is_multicast) { - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED); - goto unlock; - } - break; - case UWB_RSV_STATE_O_ESTABLISHED: - if (rsv->is_multicast) - goto unlock; - break; - case UWB_RSV_STATE_T_EXPANDING_ACCEPTED: - /* - * The time out could be for the main or of the - * companion DRP, assume it's for the companion and - * drop that first. A further time out is required to - * drop the main. - */ - uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED); - uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas); - goto unlock; - case UWB_RSV_STATE_NONE: - goto unlock; - default: - break; - } - - uwb_rsv_remove(rsv); - -unlock: - mutex_unlock(&rc->rsvs_mutex); -} - -static struct uwb_rsv *uwb_rsv_alloc(struct uwb_rc *rc) -{ - struct uwb_rsv *rsv; - - rsv = kzalloc(sizeof(struct uwb_rsv), GFP_KERNEL); - if (!rsv) - return NULL; - - INIT_LIST_HEAD(&rsv->rc_node); - INIT_LIST_HEAD(&rsv->pal_node); - kref_init(&rsv->kref); - timer_setup(&rsv->timer, uwb_rsv_timer, 0); - - rsv->rc = rc; - INIT_WORK(&rsv->handle_timeout_work, uwb_rsv_handle_timeout_work); - - return rsv; -} - -/** - * uwb_rsv_create - allocate and initialize a UWB reservation structure - * @rc: the radio controller - * @cb: callback to use when the reservation completes or terminates - * @pal_priv: data private to the PAL to be passed in the callback - * - * The callback is called when the state of the reservation changes from: - * - * - pending to accepted - * - pending to denined - * - accepted to terminated - * - pending to terminated - */ -struct uwb_rsv *uwb_rsv_create(struct uwb_rc *rc, uwb_rsv_cb_f cb, void *pal_priv) -{ - struct uwb_rsv *rsv; - - rsv = uwb_rsv_alloc(rc); - if (!rsv) - return NULL; - - rsv->callback = cb; - rsv->pal_priv = pal_priv; - - return rsv; -} -EXPORT_SYMBOL_GPL(uwb_rsv_create); - -void uwb_rsv_remove(struct uwb_rsv *rsv) -{ - uwb_rsv_dump("RM", rsv); - - if (rsv->state != UWB_RSV_STATE_NONE) - uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); - - if (rsv->needs_release_companion_mas) - uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas); - uwb_drp_avail_release(rsv->rc, &rsv->mas); - - if (uwb_rsv_is_owner(rsv)) - uwb_rsv_put_stream(rsv); - - uwb_dev_put(rsv->owner); - if (rsv->target.type == UWB_RSV_TARGET_DEV) - uwb_dev_put(rsv->target.dev); - - list_del_init(&rsv->rc_node); - uwb_rsv_put(rsv); -} - -/** - * uwb_rsv_destroy - free a UWB reservation structure - * @rsv: the reservation to free - * - * The reservation must already be terminated. - */ -void uwb_rsv_destroy(struct uwb_rsv *rsv) -{ - uwb_rsv_put(rsv); -} -EXPORT_SYMBOL_GPL(uwb_rsv_destroy); - -/** - * usb_rsv_establish - start a reservation establishment - * @rsv: the reservation - * - * The PAL should fill in @rsv's owner, target, type, max_mas, - * min_mas, max_interval and is_multicast fields. If the target is a - * uwb_dev it must be referenced. - * - * The reservation's callback will be called when the reservation is - * accepted, denied or times out. - */ -int uwb_rsv_establish(struct uwb_rsv *rsv) -{ - struct uwb_rc *rc = rsv->rc; - struct uwb_mas_bm available; - struct device *dev = &rc->uwb_dev.dev; - int ret; - - mutex_lock(&rc->rsvs_mutex); - ret = uwb_rsv_get_stream(rsv); - if (ret) { - dev_err(dev, "%s: uwb_rsv_get_stream failed: %d\n", - __func__, ret); - goto out; - } - - rsv->tiebreaker = prandom_u32() & 1; - /* get available mas bitmap */ - uwb_drp_available(rc, &available); - - ret = uwb_rsv_find_best_allocation(rsv, &available, &rsv->mas); - if (ret == UWB_RSV_ALLOC_NOT_FOUND) { - ret = -EBUSY; - uwb_rsv_put_stream(rsv); - dev_err(dev, "%s: uwb_rsv_find_best_allocation failed: %d\n", - __func__, ret); - goto out; - } - - ret = uwb_drp_avail_reserve_pending(rc, &rsv->mas); - if (ret != 0) { - uwb_rsv_put_stream(rsv); - dev_err(dev, "%s: uwb_drp_avail_reserve_pending failed: %d\n", - __func__, ret); - goto out; - } - - uwb_rsv_get(rsv); - list_add_tail(&rsv->rc_node, &rc->reservations); - rsv->owner = &rc->uwb_dev; - uwb_dev_get(rsv->owner); - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_INITIATED); -out: - mutex_unlock(&rc->rsvs_mutex); - return ret; -} -EXPORT_SYMBOL_GPL(uwb_rsv_establish); - -/** - * uwb_rsv_modify - modify an already established reservation - * @rsv: the reservation to modify - * @max_mas: new maximum MAS to reserve - * @min_mas: new minimum MAS to reserve - * @max_interval: new max_interval to use - * - * FIXME: implement this once there are PALs that use it. - */ -int uwb_rsv_modify(struct uwb_rsv *rsv, int max_mas, int min_mas, int max_interval) -{ - return -ENOSYS; -} -EXPORT_SYMBOL_GPL(uwb_rsv_modify); - -/* - * move an already established reservation (rc->rsvs_mutex must to be - * taken when tis function is called) - */ -int uwb_rsv_try_move(struct uwb_rsv *rsv, struct uwb_mas_bm *available) -{ - struct uwb_rc *rc = rsv->rc; - struct uwb_drp_backoff_win *bow = &rc->bow; - struct device *dev = &rc->uwb_dev.dev; - struct uwb_rsv_move *mv; - int ret = 0; - - if (bow->can_reserve_extra_mases == false) - return -EBUSY; - - mv = &rsv->mv; - - if (uwb_rsv_find_best_allocation(rsv, available, &mv->final_mas) == UWB_RSV_ALLOC_FOUND) { - - if (!bitmap_equal(rsv->mas.bm, mv->final_mas.bm, UWB_NUM_MAS)) { - /* We want to move the reservation */ - bitmap_andnot(mv->companion_mas.bm, mv->final_mas.bm, rsv->mas.bm, UWB_NUM_MAS); - uwb_drp_avail_reserve_pending(rc, &mv->companion_mas); - uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING); - } - } else { - dev_dbg(dev, "new allocation not found\n"); - } - - return ret; -} - -/* It will try to move every reservation in state O_ESTABLISHED giving - * to the MAS allocator algorithm an availability that is the real one - * plus the allocation already established from the reservation. */ -void uwb_rsv_handle_drp_avail_change(struct uwb_rc *rc) -{ - struct uwb_drp_backoff_win *bow = &rc->bow; - struct uwb_rsv *rsv; - struct uwb_mas_bm mas; - - if (bow->can_reserve_extra_mases == false) - return; - - list_for_each_entry(rsv, &rc->reservations, rc_node) { - if (rsv->state == UWB_RSV_STATE_O_ESTABLISHED || - rsv->state == UWB_RSV_STATE_O_TO_BE_MOVED) { - uwb_drp_available(rc, &mas); - bitmap_or(mas.bm, mas.bm, rsv->mas.bm, UWB_NUM_MAS); - uwb_rsv_try_move(rsv, &mas); - } - } - -} - -/** - * uwb_rsv_terminate - terminate an established reservation - * @rsv: the reservation to terminate - * - * A reservation is terminated by removing the DRP IE from the beacon, - * the other end will consider the reservation to be terminated when - * it does not see the DRP IE for at least mMaxLostBeacons. - * - * If applicable, the reference to the target uwb_dev will be released. - */ -void uwb_rsv_terminate(struct uwb_rsv *rsv) -{ - struct uwb_rc *rc = rsv->rc; - - mutex_lock(&rc->rsvs_mutex); - - if (rsv->state != UWB_RSV_STATE_NONE) - uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); - - mutex_unlock(&rc->rsvs_mutex); -} -EXPORT_SYMBOL_GPL(uwb_rsv_terminate); - -/** - * uwb_rsv_accept - accept a new reservation from a peer - * @rsv: the reservation - * @cb: call back for reservation changes - * @pal_priv: data to be passed in the above call back - * - * Reservation requests from peers are denied unless a PAL accepts it - * by calling this function. - * - * The PAL call uwb_rsv_destroy() for all accepted reservations before - * calling uwb_pal_unregister(). - */ -void uwb_rsv_accept(struct uwb_rsv *rsv, uwb_rsv_cb_f cb, void *pal_priv) -{ - uwb_rsv_get(rsv); - - rsv->callback = cb; - rsv->pal_priv = pal_priv; - rsv->state = UWB_RSV_STATE_T_ACCEPTED; -} -EXPORT_SYMBOL_GPL(uwb_rsv_accept); - -/* - * Is a received DRP IE for this reservation? - */ -static bool uwb_rsv_match(struct uwb_rsv *rsv, struct uwb_dev *src, - struct uwb_ie_drp *drp_ie) -{ - struct uwb_dev_addr *rsv_src; - int stream; - - stream = uwb_ie_drp_stream_index(drp_ie); - - if (rsv->stream != stream) - return false; - - switch (rsv->target.type) { - case UWB_RSV_TARGET_DEVADDR: - return rsv->stream == stream; - case UWB_RSV_TARGET_DEV: - if (uwb_ie_drp_owner(drp_ie)) - rsv_src = &rsv->owner->dev_addr; - else - rsv_src = &rsv->target.dev->dev_addr; - return uwb_dev_addr_cmp(&src->dev_addr, rsv_src) == 0; - } - return false; -} - -static struct uwb_rsv *uwb_rsv_new_target(struct uwb_rc *rc, - struct uwb_dev *src, - struct uwb_ie_drp *drp_ie) -{ - struct uwb_rsv *rsv; - struct uwb_pal *pal; - enum uwb_rsv_state state; - - rsv = uwb_rsv_alloc(rc); - if (!rsv) - return NULL; - - rsv->rc = rc; - rsv->owner = src; - uwb_dev_get(rsv->owner); - rsv->target.type = UWB_RSV_TARGET_DEV; - rsv->target.dev = &rc->uwb_dev; - uwb_dev_get(&rc->uwb_dev); - rsv->type = uwb_ie_drp_type(drp_ie); - rsv->stream = uwb_ie_drp_stream_index(drp_ie); - uwb_drp_ie_to_bm(&rsv->mas, drp_ie); - - /* - * See if any PALs are interested in this reservation. If not, - * deny the request. - */ - rsv->state = UWB_RSV_STATE_T_DENIED; - mutex_lock(&rc->uwb_dev.mutex); - list_for_each_entry(pal, &rc->pals, node) { - if (pal->new_rsv) - pal->new_rsv(pal, rsv); - if (rsv->state == UWB_RSV_STATE_T_ACCEPTED) - break; - } - mutex_unlock(&rc->uwb_dev.mutex); - - list_add_tail(&rsv->rc_node, &rc->reservations); - state = rsv->state; - rsv->state = UWB_RSV_STATE_NONE; - - /* FIXME: do something sensible here */ - if (state == UWB_RSV_STATE_T_ACCEPTED - && uwb_drp_avail_reserve_pending(rc, &rsv->mas) == -EBUSY) { - /* FIXME: do something sensible here */ - } else { - uwb_rsv_set_state(rsv, state); - } - - return rsv; -} - -/** - * uwb_rsv_get_usable_mas - get the bitmap of the usable MAS of a reservations - * @rsv: the reservation. - * @mas: returns the available MAS. - * - * The usable MAS of a reservation may be less than the negotiated MAS - * if alien BPs are present. - */ -void uwb_rsv_get_usable_mas(struct uwb_rsv *rsv, struct uwb_mas_bm *mas) -{ - bitmap_zero(mas->bm, UWB_NUM_MAS); - bitmap_andnot(mas->bm, rsv->mas.bm, rsv->rc->cnflt_alien_bitmap.bm, UWB_NUM_MAS); -} -EXPORT_SYMBOL_GPL(uwb_rsv_get_usable_mas); - -/** - * uwb_rsv_find - find a reservation for a received DRP IE. - * @rc: the radio controller - * @src: source of the DRP IE - * @drp_ie: the DRP IE - * - * If the reservation cannot be found and the DRP IE is from a peer - * attempting to establish a new reservation, create a new reservation - * and add it to the list. - */ -struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src, - struct uwb_ie_drp *drp_ie) -{ - struct uwb_rsv *rsv; - - list_for_each_entry(rsv, &rc->reservations, rc_node) { - if (uwb_rsv_match(rsv, src, drp_ie)) - return rsv; - } - - if (uwb_ie_drp_owner(drp_ie)) - return uwb_rsv_new_target(rc, src, drp_ie); - - return NULL; -} - -/* - * Go through all the reservations and check for timeouts and (if - * necessary) update their DRP IEs. - * - * FIXME: look at building the SET_DRP_IE command here rather than - * having to rescan the list in uwb_rc_send_all_drp_ie(). - */ -static bool uwb_rsv_update_all(struct uwb_rc *rc) -{ - struct uwb_rsv *rsv, *t; - bool ie_updated = false; - - list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) { - if (!rsv->ie_valid) { - uwb_drp_ie_update(rsv); - ie_updated = true; - } - } - - return ie_updated; -} - -void uwb_rsv_queue_update(struct uwb_rc *rc) -{ - unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE; - - queue_delayed_work(rc->rsv_workq, &rc->rsv_update_work, usecs_to_jiffies(delay_us)); -} - -/** - * uwb_rsv_sched_update - schedule an update of the DRP IEs - * @rc: the radio controller. - * - * To improve performance and ensure correctness with [ECMA-368] the - * number of SET-DRP-IE commands that are done are limited. - * - * DRP IEs update come from two sources: DRP events from the hardware - * which all occur at the beginning of the superframe ('syncronous' - * events) and reservation establishment/termination requests from - * PALs or timers ('asynchronous' events). - * - * A delayed work ensures that all the synchronous events result in - * one SET-DRP-IE command. - * - * Additional logic (the set_drp_ie_pending and rsv_updated_postponed - * flags) will prevent an asynchrous event starting a SET-DRP-IE - * command if one is currently awaiting a response. - * - * FIXME: this does leave a window where an asynchrous event can delay - * the SET-DRP-IE for a synchronous event by one superframe. - */ -void uwb_rsv_sched_update(struct uwb_rc *rc) -{ - spin_lock_irq(&rc->rsvs_lock); - if (!delayed_work_pending(&rc->rsv_update_work)) { - if (rc->set_drp_ie_pending > 0) { - rc->set_drp_ie_pending++; - goto unlock; - } - uwb_rsv_queue_update(rc); - } -unlock: - spin_unlock_irq(&rc->rsvs_lock); -} - -/* - * Update DRP IEs and, if necessary, the DRP Availability IE and send - * the updated IEs to the radio controller. - */ -static void uwb_rsv_update_work(struct work_struct *work) -{ - struct uwb_rc *rc = container_of(work, struct uwb_rc, - rsv_update_work.work); - bool ie_updated; - - mutex_lock(&rc->rsvs_mutex); - - ie_updated = uwb_rsv_update_all(rc); - - if (!rc->drp_avail.ie_valid) { - uwb_drp_avail_ie_update(rc); - ie_updated = true; - } - - if (ie_updated && (rc->set_drp_ie_pending == 0)) - uwb_rc_send_all_drp_ie(rc); - - mutex_unlock(&rc->rsvs_mutex); -} - -static void uwb_rsv_alien_bp_work(struct work_struct *work) -{ - struct uwb_rc *rc = container_of(work, struct uwb_rc, - rsv_alien_bp_work.work); - struct uwb_rsv *rsv; - - mutex_lock(&rc->rsvs_mutex); - - list_for_each_entry(rsv, &rc->reservations, rc_node) { - if (rsv->type != UWB_DRP_TYPE_ALIEN_BP) { - uwb_rsv_callback(rsv); - } - } - - mutex_unlock(&rc->rsvs_mutex); -} - -static void uwb_rsv_timer(struct timer_list *t) -{ - struct uwb_rsv *rsv = from_timer(rsv, t, timer); - - queue_work(rsv->rc->rsv_workq, &rsv->handle_timeout_work); -} - -/** - * uwb_rsv_remove_all - remove all reservations - * @rc: the radio controller - * - * A DRP IE update is not done. - */ -void uwb_rsv_remove_all(struct uwb_rc *rc) -{ - struct uwb_rsv *rsv, *t; - - mutex_lock(&rc->rsvs_mutex); - list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) { - if (rsv->state != UWB_RSV_STATE_NONE) - uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE); - del_timer_sync(&rsv->timer); - } - /* Cancel any postponed update. */ - rc->set_drp_ie_pending = 0; - mutex_unlock(&rc->rsvs_mutex); - - cancel_delayed_work_sync(&rc->rsv_update_work); - flush_workqueue(rc->rsv_workq); - - mutex_lock(&rc->rsvs_mutex); - list_for_each_entry_safe(rsv, t, &rc->reservations, rc_node) { - uwb_rsv_remove(rsv); - } - mutex_unlock(&rc->rsvs_mutex); -} - -void uwb_rsv_init(struct uwb_rc *rc) -{ - INIT_LIST_HEAD(&rc->reservations); - INIT_LIST_HEAD(&rc->cnflt_alien_list); - mutex_init(&rc->rsvs_mutex); - spin_lock_init(&rc->rsvs_lock); - INIT_DELAYED_WORK(&rc->rsv_update_work, uwb_rsv_update_work); - INIT_DELAYED_WORK(&rc->rsv_alien_bp_work, uwb_rsv_alien_bp_work); - rc->bow.can_reserve_extra_mases = true; - rc->bow.total_expired = 0; - rc->bow.window = UWB_DRP_BACKOFF_WIN_MIN >> 1; - timer_setup(&rc->bow.timer, uwb_rsv_backoff_win_timer, 0); - - bitmap_complement(rc->uwb_dev.streams, rc->uwb_dev.streams, UWB_NUM_STREAMS); -} - -int uwb_rsv_setup(struct uwb_rc *rc) -{ - char name[16]; - - snprintf(name, sizeof(name), "%s_rsvd", dev_name(&rc->uwb_dev.dev)); - rc->rsv_workq = create_singlethread_workqueue(name); - if (rc->rsv_workq == NULL) - return -ENOMEM; - - return 0; -} - -void uwb_rsv_cleanup(struct uwb_rc *rc) -{ - uwb_rsv_remove_all(rc); - destroy_workqueue(rc->rsv_workq); -} diff --git a/drivers/uwb/scan.c b/drivers/uwb/scan.c deleted file mode 100644 index ffc3f452302d..000000000000 --- a/drivers/uwb/scan.c +++ /dev/null @@ -1,120 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Ultra Wide Band - * Scanning management - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * FIXME: docs - * FIXME: there are issues here on how BEACON and SCAN on USB RCI deal - * with each other. Currently seems that START_BEACON while - * SCAN_ONLY will cancel the scan, so we need to update the - * state here. Clarification request sent by email on - * 10/05/2005. - * 10/28/2005 No clear answer heard--maybe we'll hack the API - * so that when we start beaconing, if the HC is - * scanning in a mode not compatible with beaconing - * we just fail. - */ - -#include <linux/device.h> -#include <linux/err.h> -#include <linux/slab.h> -#include <linux/stat.h> -#include "uwb-internal.h" - - -/** - * Start/stop scanning in a radio controller - * - * @rc: UWB Radio Controller - * @channel: Channel to scan; encodings in WUSB1.0[Table 5.12] - * @type: Type of scanning to do. - * @bpst_offset: value at which to start scanning (if type == - * UWB_SCAN_ONLY_STARTTIME) - * @returns: 0 if ok, < 0 errno code on error - * - * We put the command on kmalloc'ed memory as some arches cannot do - * USB from the stack. The reply event is copied from an stage buffer, - * so it can be in the stack. See WUSB1.0[8.6.2.4] for more details. - */ -int uwb_rc_scan(struct uwb_rc *rc, - unsigned channel, enum uwb_scan_type type, - unsigned bpst_offset) -{ - int result; - struct uwb_rc_cmd_scan *cmd; - struct uwb_rc_evt_confirm reply; - - result = -ENOMEM; - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (cmd == NULL) - goto error_kzalloc; - mutex_lock(&rc->uwb_dev.mutex); - cmd->rccb.bCommandType = UWB_RC_CET_GENERAL; - cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SCAN); - cmd->bChannelNumber = channel; - cmd->bScanState = type; - cmd->wStartTime = cpu_to_le16(bpst_offset); - reply.rceb.bEventType = UWB_RC_CET_GENERAL; - reply.rceb.wEvent = UWB_RC_CMD_SCAN; - result = uwb_rc_cmd(rc, "SCAN", &cmd->rccb, sizeof(*cmd), - &reply.rceb, sizeof(reply)); - if (result < 0) - goto error_cmd; - if (reply.bResultCode != UWB_RC_RES_SUCCESS) { - dev_err(&rc->uwb_dev.dev, - "SCAN: command execution failed: %s (%d)\n", - uwb_rc_strerror(reply.bResultCode), reply.bResultCode); - result = -EIO; - goto error_cmd; - } - rc->scanning = channel; - rc->scan_type = type; -error_cmd: - mutex_unlock(&rc->uwb_dev.mutex); - kfree(cmd); -error_kzalloc: - return result; -} - -/* - * Print scanning state - */ -static ssize_t uwb_rc_scan_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - struct uwb_rc *rc = uwb_dev->rc; - ssize_t result; - - mutex_lock(&rc->uwb_dev.mutex); - result = sprintf(buf, "%d %d\n", rc->scanning, rc->scan_type); - mutex_unlock(&rc->uwb_dev.mutex); - return result; -} - -/* - * - */ -static ssize_t uwb_rc_scan_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct uwb_dev *uwb_dev = to_uwb_dev(dev); - struct uwb_rc *rc = uwb_dev->rc; - unsigned channel; - unsigned type; - unsigned bpst_offset = 0; - ssize_t result = -EINVAL; - - result = sscanf(buf, "%u %u %u\n", &channel, &type, &bpst_offset); - if (result >= 2 && type < UWB_SCAN_TOP) - result = uwb_rc_scan(rc, channel, type, bpst_offset); - - return result < 0 ? result : size; -} - -/** Radio Control sysfs interface (declaration) */ -DEVICE_ATTR(scan, S_IRUGO | S_IWUSR, uwb_rc_scan_show, uwb_rc_scan_store); diff --git a/drivers/uwb/umc-bus.c b/drivers/uwb/umc-bus.c deleted file mode 100644 index 0fdc38078eee..000000000000 --- a/drivers/uwb/umc-bus.c +++ /dev/null @@ -1,211 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Bus for UWB Multi-interface Controller capabilities. - * - * Copyright (C) 2007 Cambridge Silicon Radio Ltd. - */ -#include <linux/kernel.h> -#include <linux/sysfs.h> -#include <linux/workqueue.h> -#include <linux/module.h> -#include <linux/uwb/umc.h> -#include <linux/pci.h> - -static int umc_bus_pre_reset_helper(struct device *dev, void *data) -{ - int ret = 0; - - if (dev->driver) { - struct umc_dev *umc = to_umc_dev(dev); - struct umc_driver *umc_drv = to_umc_driver(dev->driver); - - if (umc_drv->pre_reset) - ret = umc_drv->pre_reset(umc); - else - device_release_driver(dev); - } - return ret; -} - -static int umc_bus_post_reset_helper(struct device *dev, void *data) -{ - int ret = 0; - - if (dev->driver) { - struct umc_dev *umc = to_umc_dev(dev); - struct umc_driver *umc_drv = to_umc_driver(dev->driver); - - if (umc_drv->post_reset) - ret = umc_drv->post_reset(umc); - } else - ret = device_attach(dev); - - return ret; -} - -/** - * umc_controller_reset - reset the whole UMC controller - * @umc: the UMC device for the radio controller. - * - * Drivers or all capabilities of the controller will have their - * pre_reset methods called or be unbound from their device. Then all - * post_reset methods will be called or the drivers will be rebound. - * - * Radio controllers must provide pre_reset and post_reset methods and - * reset the hardware in their start method. - * - * If this is called while a probe() or remove() is in progress it - * will return -EAGAIN and not perform the reset. - */ -int umc_controller_reset(struct umc_dev *umc) -{ - struct device *parent = umc->dev.parent; - int ret = 0; - - if (!device_trylock(parent)) - return -EAGAIN; - ret = device_for_each_child(parent, parent, umc_bus_pre_reset_helper); - if (ret >= 0) - ret = device_for_each_child(parent, parent, umc_bus_post_reset_helper); - device_unlock(parent); - - return ret; -} -EXPORT_SYMBOL_GPL(umc_controller_reset); - -/** - * umc_match_pci_id - match a UMC driver to a UMC device's parent PCI device. - * @umc_drv: umc driver with match_data pointing to a zero-terminated - * table of pci_device_id's. - * @umc: umc device whose parent is to be matched. - */ -int umc_match_pci_id(struct umc_driver *umc_drv, struct umc_dev *umc) -{ - const struct pci_device_id *id_table = umc_drv->match_data; - struct pci_dev *pci; - - if (!dev_is_pci(umc->dev.parent)) - return 0; - - pci = to_pci_dev(umc->dev.parent); - return pci_match_id(id_table, pci) != NULL; -} -EXPORT_SYMBOL_GPL(umc_match_pci_id); - -static int umc_bus_rescan_helper(struct device *dev, void *data) -{ - int ret = 0; - - if (!dev->driver) - ret = device_attach(dev); - - return ret; -} - -static void umc_bus_rescan(struct device *parent) -{ - int err; - - /* - * We can't use bus_rescan_devices() here as it deadlocks when - * it tries to retake the dev->parent semaphore. - */ - err = device_for_each_child(parent, NULL, umc_bus_rescan_helper); - if (err < 0) - printk(KERN_WARNING "%s: rescan of bus failed: %d\n", - KBUILD_MODNAME, err); -} - -static int umc_bus_match(struct device *dev, struct device_driver *drv) -{ - struct umc_dev *umc = to_umc_dev(dev); - struct umc_driver *umc_driver = to_umc_driver(drv); - - if (umc->cap_id == umc_driver->cap_id) { - if (umc_driver->match) - return umc_driver->match(umc_driver, umc); - else - return 1; - } - return 0; -} - -static int umc_device_probe(struct device *dev) -{ - struct umc_dev *umc; - struct umc_driver *umc_driver; - int err; - - umc_driver = to_umc_driver(dev->driver); - umc = to_umc_dev(dev); - - get_device(dev); - err = umc_driver->probe(umc); - if (err) - put_device(dev); - else - umc_bus_rescan(dev->parent); - - return err; -} - -static int umc_device_remove(struct device *dev) -{ - struct umc_dev *umc; - struct umc_driver *umc_driver; - - umc_driver = to_umc_driver(dev->driver); - umc = to_umc_dev(dev); - - umc_driver->remove(umc); - put_device(dev); - return 0; -} - -static ssize_t capability_id_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct umc_dev *umc = to_umc_dev(dev); - - return sprintf(buf, "0x%02x\n", umc->cap_id); -} -static DEVICE_ATTR_RO(capability_id); - -static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct umc_dev *umc = to_umc_dev(dev); - - return sprintf(buf, "0x%04x\n", umc->version); -} -static DEVICE_ATTR_RO(version); - -static struct attribute *umc_dev_attrs[] = { - &dev_attr_capability_id.attr, - &dev_attr_version.attr, - NULL, -}; -ATTRIBUTE_GROUPS(umc_dev); - -struct bus_type umc_bus_type = { - .name = "umc", - .match = umc_bus_match, - .probe = umc_device_probe, - .remove = umc_device_remove, - .dev_groups = umc_dev_groups, -}; -EXPORT_SYMBOL_GPL(umc_bus_type); - -static int __init umc_bus_init(void) -{ - return bus_register(&umc_bus_type); -} -module_init(umc_bus_init); - -static void __exit umc_bus_exit(void) -{ - bus_unregister(&umc_bus_type); -} -module_exit(umc_bus_exit); - -MODULE_DESCRIPTION("UWB Multi-interface Controller capability bus"); -MODULE_AUTHOR("Cambridge Silicon Radio Ltd."); -MODULE_LICENSE("GPL"); diff --git a/drivers/uwb/umc-dev.c b/drivers/uwb/umc-dev.c deleted file mode 100644 index c845ca414bb2..000000000000 --- a/drivers/uwb/umc-dev.c +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * UWB Multi-interface Controller device management. - * - * Copyright (C) 2007 Cambridge Silicon Radio Ltd. - */ -#include <linux/kernel.h> -#include <linux/export.h> -#include <linux/slab.h> -#include <linux/uwb/umc.h> - -static void umc_device_release(struct device *dev) -{ - struct umc_dev *umc = to_umc_dev(dev); - - kfree(umc); -} - -/** - * umc_device_create - allocate a child UMC device - * @parent: parent of the new UMC device. - * @n: index of the new device. - * - * The new UMC device will have a bus ID of the parent with '-n' - * appended. - */ -struct umc_dev *umc_device_create(struct device *parent, int n) -{ - struct umc_dev *umc; - - umc = kzalloc(sizeof(struct umc_dev), GFP_KERNEL); - if (umc) { - dev_set_name(&umc->dev, "%s-%d", dev_name(parent), n); - umc->dev.parent = parent; - umc->dev.bus = &umc_bus_type; - umc->dev.release = umc_device_release; - - umc->dev.dma_mask = parent->dma_mask; - } - return umc; -} -EXPORT_SYMBOL_GPL(umc_device_create); - -/** - * umc_device_register - register a UMC device - * @umc: pointer to the UMC device - * - * The memory resource for the UMC device is acquired and the device - * registered with the system. - */ -int umc_device_register(struct umc_dev *umc) -{ - int err; - - err = request_resource(umc->resource.parent, &umc->resource); - if (err < 0) { - dev_err(&umc->dev, "can't allocate resource range %pR: %d\n", - &umc->resource, err); - goto error_request_resource; - } - - err = device_register(&umc->dev); - if (err < 0) - goto error_device_register; - return 0; - -error_device_register: - put_device(&umc->dev); - release_resource(&umc->resource); -error_request_resource: - return err; -} -EXPORT_SYMBOL_GPL(umc_device_register); - -/** - * umc_device_unregister - unregister a UMC device - * @umc: pointer to the UMC device - * - * First we unregister the device, make sure the driver can do it's - * resource release thing and then we try to release any left over - * resources. We take a ref to the device, to make sure it doesn't - * disappear under our feet. - */ -void umc_device_unregister(struct umc_dev *umc) -{ - struct device *dev; - if (!umc) - return; - dev = get_device(&umc->dev); - device_unregister(&umc->dev); - release_resource(&umc->resource); - put_device(dev); -} -EXPORT_SYMBOL_GPL(umc_device_unregister); diff --git a/drivers/uwb/umc-drv.c b/drivers/uwb/umc-drv.c deleted file mode 100644 index b141d520efbf..000000000000 --- a/drivers/uwb/umc-drv.c +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * UWB Multi-interface Controller driver management. - * - * Copyright (C) 2007 Cambridge Silicon Radio Ltd. - */ -#include <linux/kernel.h> -#include <linux/export.h> -#include <linux/uwb/umc.h> - -int __umc_driver_register(struct umc_driver *umc_drv, struct module *module, - const char *mod_name) -{ - umc_drv->driver.name = umc_drv->name; - umc_drv->driver.owner = module; - umc_drv->driver.mod_name = mod_name; - umc_drv->driver.bus = &umc_bus_type; - - return driver_register(&umc_drv->driver); -} -EXPORT_SYMBOL_GPL(__umc_driver_register); - -/** - * umc_driver_register - unregister a UMC capabiltity driver. - * @umc_drv: pointer to the driver. - */ -void umc_driver_unregister(struct umc_driver *umc_drv) -{ - driver_unregister(&umc_drv->driver); -} -EXPORT_SYMBOL_GPL(umc_driver_unregister); diff --git a/drivers/uwb/uwb-debug.c b/drivers/uwb/uwb-debug.c deleted file mode 100644 index 5457b6d42387..000000000000 --- a/drivers/uwb/uwb-debug.c +++ /dev/null @@ -1,355 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Ultra Wide Band - * Debug support - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * Copyright (C) 2008 Cambridge Silicon Radio Ltd. - * - * FIXME: doc - */ - -#include <linux/spinlock.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/notifier.h> -#include <linux/device.h> -#include <linux/debugfs.h> -#include <linux/uaccess.h> -#include <linux/seq_file.h> - -#include <linux/uwb/debug-cmd.h> - -#include "uwb-internal.h" - -/* - * Debug interface - * - * Per radio controller debugfs files (in uwb/uwbN/): - * - * command: Flexible command interface (see <linux/uwb/debug-cmd.h>). - * - * reservations: information on reservations. - * - * accept: Set to true (Y or 1) to accept reservation requests from - * peers. - * - * drp_avail: DRP availability information. - */ - -struct uwb_dbg { - struct uwb_pal pal; - - bool accept; - struct list_head rsvs; - - struct dentry *root_d; - struct dentry *command_f; - struct dentry *reservations_f; - struct dentry *accept_f; - struct dentry *drp_avail_f; - spinlock_t list_lock; -}; - -static struct dentry *root_dir; - -static void uwb_dbg_rsv_cb(struct uwb_rsv *rsv) -{ - struct uwb_dbg *dbg = rsv->pal_priv; - - uwb_rsv_dump("debug", rsv); - - if (rsv->state == UWB_RSV_STATE_NONE) { - spin_lock(&dbg->list_lock); - list_del(&rsv->pal_node); - spin_unlock(&dbg->list_lock); - uwb_rsv_destroy(rsv); - } -} - -static int cmd_rsv_establish(struct uwb_rc *rc, - struct uwb_dbg_cmd_rsv_establish *cmd) -{ - struct uwb_mac_addr macaddr; - struct uwb_rsv *rsv; - struct uwb_dev *target; - int ret; - - memcpy(&macaddr, cmd->target, sizeof(macaddr)); - target = uwb_dev_get_by_macaddr(rc, &macaddr); - if (target == NULL) - return -ENODEV; - - rsv = uwb_rsv_create(rc, uwb_dbg_rsv_cb, rc->dbg); - if (rsv == NULL) { - uwb_dev_put(target); - return -ENOMEM; - } - - rsv->target.type = UWB_RSV_TARGET_DEV; - rsv->target.dev = target; - rsv->type = cmd->type; - rsv->max_mas = cmd->max_mas; - rsv->min_mas = cmd->min_mas; - rsv->max_interval = cmd->max_interval; - - ret = uwb_rsv_establish(rsv); - if (ret) - uwb_rsv_destroy(rsv); - else { - spin_lock(&(rc->dbg)->list_lock); - list_add_tail(&rsv->pal_node, &rc->dbg->rsvs); - spin_unlock(&(rc->dbg)->list_lock); - } - return ret; -} - -static int cmd_rsv_terminate(struct uwb_rc *rc, - struct uwb_dbg_cmd_rsv_terminate *cmd) -{ - struct uwb_rsv *rsv, *found = NULL; - int i = 0; - - spin_lock(&(rc->dbg)->list_lock); - - list_for_each_entry(rsv, &rc->dbg->rsvs, pal_node) { - if (i == cmd->index) { - found = rsv; - uwb_rsv_get(found); - break; - } - i++; - } - - spin_unlock(&(rc->dbg)->list_lock); - - if (!found) - return -EINVAL; - - uwb_rsv_terminate(found); - uwb_rsv_put(found); - - return 0; -} - -static int cmd_ie_add(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_add) -{ - return uwb_rc_ie_add(rc, - (const struct uwb_ie_hdr *) ie_to_add->data, - ie_to_add->len); -} - -static int cmd_ie_rm(struct uwb_rc *rc, struct uwb_dbg_cmd_ie *ie_to_rm) -{ - return uwb_rc_ie_rm(rc, ie_to_rm->data[0]); -} - -static ssize_t command_write(struct file *file, const char __user *buf, - size_t len, loff_t *off) -{ - struct uwb_rc *rc = file->private_data; - struct uwb_dbg_cmd cmd; - int ret = 0; - - if (len != sizeof(struct uwb_dbg_cmd)) - return -EINVAL; - - if (copy_from_user(&cmd, buf, len) != 0) - return -EFAULT; - - switch (cmd.type) { - case UWB_DBG_CMD_RSV_ESTABLISH: - ret = cmd_rsv_establish(rc, &cmd.rsv_establish); - break; - case UWB_DBG_CMD_RSV_TERMINATE: - ret = cmd_rsv_terminate(rc, &cmd.rsv_terminate); - break; - case UWB_DBG_CMD_IE_ADD: - ret = cmd_ie_add(rc, &cmd.ie_add); - break; - case UWB_DBG_CMD_IE_RM: - ret = cmd_ie_rm(rc, &cmd.ie_rm); - break; - case UWB_DBG_CMD_RADIO_START: - ret = uwb_radio_start(&rc->dbg->pal); - break; - case UWB_DBG_CMD_RADIO_STOP: - uwb_radio_stop(&rc->dbg->pal); - break; - default: - return -EINVAL; - } - - return ret < 0 ? ret : len; -} - -static const struct file_operations command_fops = { - .open = simple_open, - .write = command_write, - .read = NULL, - .llseek = no_llseek, - .owner = THIS_MODULE, -}; - -static int reservations_show(struct seq_file *s, void *p) -{ - struct uwb_rc *rc = s->private; - struct uwb_rsv *rsv; - - mutex_lock(&rc->rsvs_mutex); - - list_for_each_entry(rsv, &rc->reservations, rc_node) { - struct uwb_dev_addr devaddr; - char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE]; - bool is_owner; - - uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr); - if (rsv->target.type == UWB_RSV_TARGET_DEV) { - devaddr = rsv->target.dev->dev_addr; - is_owner = &rc->uwb_dev == rsv->owner; - } else { - devaddr = rsv->target.devaddr; - is_owner = true; - } - uwb_dev_addr_print(target, sizeof(target), &devaddr); - - seq_printf(s, "%c %s -> %s: %s\n", - is_owner ? 'O' : 'T', - owner, target, uwb_rsv_state_str(rsv->state)); - seq_printf(s, " stream: %d type: %s\n", - rsv->stream, uwb_rsv_type_str(rsv->type)); - seq_printf(s, " %*pb\n", UWB_NUM_MAS, rsv->mas.bm); - } - - mutex_unlock(&rc->rsvs_mutex); - - return 0; -} -DEFINE_SHOW_ATTRIBUTE(reservations); - -static int drp_avail_show(struct seq_file *s, void *p) -{ - struct uwb_rc *rc = s->private; - - seq_printf(s, "global: %*pb\n", UWB_NUM_MAS, rc->drp_avail.global); - seq_printf(s, "local: %*pb\n", UWB_NUM_MAS, rc->drp_avail.local); - seq_printf(s, "pending: %*pb\n", UWB_NUM_MAS, rc->drp_avail.pending); - - return 0; -} -DEFINE_SHOW_ATTRIBUTE(drp_avail); - -static void uwb_dbg_channel_changed(struct uwb_pal *pal, int channel) -{ - struct device *dev = &pal->rc->uwb_dev.dev; - - if (channel > 0) - dev_info(dev, "debug: channel %d started\n", channel); - else - dev_info(dev, "debug: channel stopped\n"); -} - -static void uwb_dbg_new_rsv(struct uwb_pal *pal, struct uwb_rsv *rsv) -{ - struct uwb_dbg *dbg = container_of(pal, struct uwb_dbg, pal); - - if (dbg->accept) { - spin_lock(&dbg->list_lock); - list_add_tail(&rsv->pal_node, &dbg->rsvs); - spin_unlock(&dbg->list_lock); - uwb_rsv_accept(rsv, uwb_dbg_rsv_cb, dbg); - } -} - -/** - * uwb_dbg_add_rc - add a debug interface for a radio controller - * @rc: the radio controller - */ -void uwb_dbg_add_rc(struct uwb_rc *rc) -{ - rc->dbg = kzalloc(sizeof(struct uwb_dbg), GFP_KERNEL); - if (rc->dbg == NULL) - return; - - INIT_LIST_HEAD(&rc->dbg->rsvs); - spin_lock_init(&(rc->dbg)->list_lock); - - uwb_pal_init(&rc->dbg->pal); - rc->dbg->pal.rc = rc; - rc->dbg->pal.channel_changed = uwb_dbg_channel_changed; - rc->dbg->pal.new_rsv = uwb_dbg_new_rsv; - uwb_pal_register(&rc->dbg->pal); - - if (root_dir) { - rc->dbg->root_d = debugfs_create_dir(dev_name(&rc->uwb_dev.dev), - root_dir); - rc->dbg->command_f = debugfs_create_file("command", 0200, - rc->dbg->root_d, rc, - &command_fops); - rc->dbg->reservations_f = debugfs_create_file("reservations", 0444, - rc->dbg->root_d, rc, - &reservations_fops); - rc->dbg->accept_f = debugfs_create_bool("accept", 0644, - rc->dbg->root_d, - &rc->dbg->accept); - rc->dbg->drp_avail_f = debugfs_create_file("drp_avail", 0444, - rc->dbg->root_d, rc, - &drp_avail_fops); - } -} - -/** - * uwb_dbg_del_rc - remove a radio controller's debug interface - * @rc: the radio controller - */ -void uwb_dbg_del_rc(struct uwb_rc *rc) -{ - struct uwb_rsv *rsv, *t; - - if (rc->dbg == NULL) - return; - - list_for_each_entry_safe(rsv, t, &rc->dbg->rsvs, pal_node) { - uwb_rsv_terminate(rsv); - } - - uwb_pal_unregister(&rc->dbg->pal); - - if (root_dir) { - debugfs_remove(rc->dbg->drp_avail_f); - debugfs_remove(rc->dbg->accept_f); - debugfs_remove(rc->dbg->reservations_f); - debugfs_remove(rc->dbg->command_f); - debugfs_remove(rc->dbg->root_d); - } -} - -/** - * uwb_dbg_exit - initialize the debug interface sub-module - */ -void uwb_dbg_init(void) -{ - root_dir = debugfs_create_dir("uwb", NULL); -} - -/** - * uwb_dbg_exit - clean-up the debug interface sub-module - */ -void uwb_dbg_exit(void) -{ - debugfs_remove(root_dir); -} - -/** - * uwb_dbg_create_pal_dir - create a debugfs directory for a PAL - * @pal: The PAL. - */ -struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal) -{ - struct uwb_rc *rc = pal->rc; - - if (root_dir && rc->dbg && rc->dbg->root_d && pal->name) - return debugfs_create_dir(pal->name, rc->dbg->root_d); - return NULL; -} diff --git a/drivers/uwb/uwb-internal.h b/drivers/uwb/uwb-internal.h deleted file mode 100644 index 00de0a5333d2..000000000000 --- a/drivers/uwb/uwb-internal.h +++ /dev/null @@ -1,366 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Ultra Wide Band - * UWB internal API - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * This contains most of the internal API for UWB. This is stuff used - * across the stack that of course, is of no interest to the rest. - * - * Some parts might end up going public (like uwb_rc_*())... - */ - -#ifndef __UWB_INTERNAL_H__ -#define __UWB_INTERNAL_H__ - -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/uwb.h> -#include <linux/mutex.h> - -struct uwb_beca_e; - -/* General device API */ -extern void uwb_dev_init(struct uwb_dev *uwb_dev); -extern int __uwb_dev_offair(struct uwb_dev *, struct uwb_rc *); -extern int uwb_dev_add(struct uwb_dev *uwb_dev, struct device *parent_dev, - struct uwb_rc *parent_rc); -extern void uwb_dev_rm(struct uwb_dev *uwb_dev); -extern void uwbd_dev_onair(struct uwb_rc *, struct uwb_beca_e *); -extern void uwbd_dev_offair(struct uwb_beca_e *); -void uwb_notify(struct uwb_rc *rc, struct uwb_dev *uwb_dev, enum uwb_notifs event); - -/* General UWB Radio Controller Internal API */ -extern struct uwb_rc *__uwb_rc_try_get(struct uwb_rc *); -static inline struct uwb_rc *__uwb_rc_get(struct uwb_rc *rc) -{ - uwb_dev_get(&rc->uwb_dev); - return rc; -} - -static inline void __uwb_rc_put(struct uwb_rc *rc) -{ - if (rc) - uwb_dev_put(&rc->uwb_dev); -} - -extern int uwb_rc_reset(struct uwb_rc *rc); -extern int uwb_rc_beacon(struct uwb_rc *rc, - int channel, unsigned bpst_offset); -extern int uwb_rc_scan(struct uwb_rc *rc, - unsigned channel, enum uwb_scan_type type, - unsigned bpst_offset); -extern int uwb_rc_send_all_drp_ie(struct uwb_rc *rc); - -void uwb_rc_ie_init(struct uwb_rc *); -int uwb_rc_ie_setup(struct uwb_rc *); -void uwb_rc_ie_release(struct uwb_rc *); -int uwb_ie_dump_hex(const struct uwb_ie_hdr *ies, size_t len, - char *buf, size_t size); -int uwb_rc_set_ie(struct uwb_rc *, struct uwb_rc_cmd_set_ie *); - - -extern const char *uwb_rc_strerror(unsigned code); - -/* - * Time to wait for a response to an RC command. - * - * Some commands can take a long time to response. e.g., START_BEACON - * may scan for several superframes before joining an existing beacon - * group and this can take around 600 ms. - */ -#define UWB_RC_CMD_TIMEOUT_MS 1000 /* ms */ - -/* - * Notification/Event Handlers - */ - -struct uwb_rc_neh; - -extern int uwb_rc_cmd_async(struct uwb_rc *rc, const char *cmd_name, - struct uwb_rccb *cmd, size_t cmd_size, - u8 expected_type, u16 expected_event, - uwb_rc_cmd_cb_f cb, void *arg); - - -void uwb_rc_neh_create(struct uwb_rc *rc); -void uwb_rc_neh_destroy(struct uwb_rc *rc); - -struct uwb_rc_neh *uwb_rc_neh_add(struct uwb_rc *rc, struct uwb_rccb *cmd, - u8 expected_type, u16 expected_event, - uwb_rc_cmd_cb_f cb, void *arg); -void uwb_rc_neh_rm(struct uwb_rc *rc, struct uwb_rc_neh *neh); -void uwb_rc_neh_arm(struct uwb_rc *rc, struct uwb_rc_neh *neh); -void uwb_rc_neh_put(struct uwb_rc_neh *neh); - -/* Event size tables */ -extern int uwb_est_create(void); -extern void uwb_est_destroy(void); - -/* - * UWB conflicting alien reservations - */ -struct uwb_cnflt_alien { - struct uwb_rc *rc; - struct list_head rc_node; - struct uwb_mas_bm mas; - struct timer_list timer; - struct work_struct cnflt_update_work; -}; - -enum uwb_uwb_rsv_alloc_result { - UWB_RSV_ALLOC_FOUND = 0, - UWB_RSV_ALLOC_NOT_FOUND, -}; - -enum uwb_rsv_mas_status { - UWB_RSV_MAS_NOT_AVAIL = 1, - UWB_RSV_MAS_SAFE, - UWB_RSV_MAS_UNSAFE, -}; - -struct uwb_rsv_col_set_info { - unsigned char start_col; - unsigned char interval; - unsigned char safe_mas_per_col; - unsigned char unsafe_mas_per_col; -}; - -struct uwb_rsv_col_info { - unsigned char max_avail_safe; - unsigned char max_avail_unsafe; - unsigned char highest_mas[UWB_MAS_PER_ZONE]; - struct uwb_rsv_col_set_info csi; -}; - -struct uwb_rsv_row_info { - unsigned char avail[UWB_MAS_PER_ZONE]; - unsigned char free_rows; - unsigned char used_rows; -}; - -/* - * UWB find allocation - */ -struct uwb_rsv_alloc_info { - unsigned char bm[UWB_MAS_PER_ZONE * UWB_NUM_ZONES]; - struct uwb_rsv_col_info ci[UWB_NUM_ZONES]; - struct uwb_rsv_row_info ri; - struct uwb_mas_bm *not_available; - struct uwb_mas_bm *result; - int min_mas; - int max_mas; - int max_interval; - int total_allocated_mases; - int safe_allocated_mases; - int unsafe_allocated_mases; - int interval; -}; - -int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv, - struct uwb_mas_bm *available, - struct uwb_mas_bm *result); -void uwb_rsv_handle_drp_avail_change(struct uwb_rc *rc); -/* - * UWB Events & management daemon - */ - -/** - * enum uwb_event_type - types of UWB management daemon events - * - * The UWB management daemon (uwbd) can receive two types of events: - * UWB_EVT_TYPE_NOTIF - notification from the radio controller. - * UWB_EVT_TYPE_MSG - a simple message. - */ -enum uwb_event_type { - UWB_EVT_TYPE_NOTIF, - UWB_EVT_TYPE_MSG, -}; - -/** - * struct uwb_event_notif - an event for a radio controller notification - * @size: Size of the buffer (ie: Guaranteed to contain at least - * a full 'struct uwb_rceb') - * @rceb: Pointer to a kmalloced() event payload - */ -struct uwb_event_notif { - size_t size; - struct uwb_rceb *rceb; -}; - -/** - * enum uwb_event_message - an event for a message for asynchronous processing - * - * UWB_EVT_MSG_RESET - reset the radio controller and all PAL hardware. - */ -enum uwb_event_message { - UWB_EVT_MSG_RESET, -}; - -/** - * UWB Event - * @rc: Radio controller that emitted the event (referenced) - * @ts_jiffies: Timestamp, when was it received - * @type: This event's type. - */ -struct uwb_event { - struct list_head list_node; - struct uwb_rc *rc; - unsigned long ts_jiffies; - enum uwb_event_type type; - union { - struct uwb_event_notif notif; - enum uwb_event_message message; - }; -}; - -extern void uwbd_start(struct uwb_rc *rc); -extern void uwbd_stop(struct uwb_rc *rc); -extern struct uwb_event *uwb_event_alloc(size_t, gfp_t gfp_mask); -extern void uwbd_event_queue(struct uwb_event *); -void uwbd_flush(struct uwb_rc *rc); - -/* UWB event handlers */ -extern int uwbd_evt_handle_rc_ie_rcv(struct uwb_event *); -extern int uwbd_evt_handle_rc_beacon(struct uwb_event *); -extern int uwbd_evt_handle_rc_beacon_size(struct uwb_event *); -extern int uwbd_evt_handle_rc_bpoie_change(struct uwb_event *); -extern int uwbd_evt_handle_rc_bp_slot_change(struct uwb_event *); -extern int uwbd_evt_handle_rc_drp(struct uwb_event *); -extern int uwbd_evt_handle_rc_drp_avail(struct uwb_event *); - -int uwbd_msg_handle_reset(struct uwb_event *evt); - - -/* - * Address management - */ -int uwb_rc_dev_addr_assign(struct uwb_rc *rc); -int uwbd_evt_handle_rc_dev_addr_conflict(struct uwb_event *evt); - -/* - * UWB Beacon Cache - * - * Each beacon we received is kept in a cache--when we receive that - * beacon consistently, that means there is a new device that we have - * to add to the system. - */ - -extern unsigned long beacon_timeout_ms; - -/** - * Beacon cache entry - * - * @jiffies_refresh: last time a beacon was received that refreshed - * this cache entry. - * @uwb_dev: device connected to this beacon. This pointer is not - * safe, you need to get it with uwb_dev_try_get() - * - * @hits: how many time we have seen this beacon since last time we - * cleared it - */ -struct uwb_beca_e { - struct mutex mutex; - struct kref refcnt; - struct list_head node; - struct uwb_mac_addr *mac_addr; - struct uwb_dev_addr dev_addr; - u8 hits; - unsigned long ts_jiffies; - struct uwb_dev *uwb_dev; - struct uwb_rc_evt_beacon *be; - struct stats lqe_stats, rssi_stats; /* radio statistics */ -}; -struct uwb_beacon_frame; -extern ssize_t uwb_bce_print_IEs(struct uwb_dev *, struct uwb_beca_e *, - char *, size_t); - -extern void uwb_bce_kfree(struct kref *_bce); -static inline void uwb_bce_get(struct uwb_beca_e *bce) -{ - kref_get(&bce->refcnt); -} -static inline void uwb_bce_put(struct uwb_beca_e *bce) -{ - kref_put(&bce->refcnt, uwb_bce_kfree); -} -extern void uwb_beca_purge(struct uwb_rc *rc); -extern void uwb_beca_release(struct uwb_rc *rc); - -struct uwb_dev *uwb_dev_get_by_devaddr(struct uwb_rc *rc, - const struct uwb_dev_addr *devaddr); -struct uwb_dev *uwb_dev_get_by_macaddr(struct uwb_rc *rc, - const struct uwb_mac_addr *macaddr); - -int uwb_radio_setup(struct uwb_rc *rc); -void uwb_radio_reset_state(struct uwb_rc *rc); -void uwb_radio_shutdown(struct uwb_rc *rc); -int uwb_radio_force_channel(struct uwb_rc *rc, int channel); - -/* -- UWB Sysfs representation */ -extern struct class uwb_rc_class; -extern struct bus_type uwb_bus_type; -extern struct device_attribute dev_attr_mac_address; -extern struct device_attribute dev_attr_beacon; -extern struct device_attribute dev_attr_scan; - -/* -- DRP Bandwidth allocator: bandwidth allocations, reservations, DRP */ -void uwb_rsv_init(struct uwb_rc *rc); -int uwb_rsv_setup(struct uwb_rc *rc); -void uwb_rsv_cleanup(struct uwb_rc *rc); -void uwb_rsv_remove_all(struct uwb_rc *rc); -void uwb_rsv_get(struct uwb_rsv *rsv); -void uwb_rsv_put(struct uwb_rsv *rsv); -bool uwb_rsv_has_two_drp_ies(struct uwb_rsv *rsv); -void uwb_rsv_dump(char *text, struct uwb_rsv *rsv); -int uwb_rsv_try_move(struct uwb_rsv *rsv, struct uwb_mas_bm *available); -void uwb_rsv_backoff_win_timer(struct timer_list *t); -void uwb_rsv_backoff_win_increment(struct uwb_rc *rc); -int uwb_rsv_status(struct uwb_rsv *rsv); -int uwb_rsv_companion_status(struct uwb_rsv *rsv); - -void uwb_rsv_set_state(struct uwb_rsv *rsv, enum uwb_rsv_state new_state); -void uwb_rsv_remove(struct uwb_rsv *rsv); -struct uwb_rsv *uwb_rsv_find(struct uwb_rc *rc, struct uwb_dev *src, - struct uwb_ie_drp *drp_ie); -void uwb_rsv_sched_update(struct uwb_rc *rc); -void uwb_rsv_queue_update(struct uwb_rc *rc); - -int uwb_drp_ie_update(struct uwb_rsv *rsv); -void uwb_drp_ie_to_bm(struct uwb_mas_bm *bm, const struct uwb_ie_drp *drp_ie); - -void uwb_drp_avail_init(struct uwb_rc *rc); -void uwb_drp_available(struct uwb_rc *rc, struct uwb_mas_bm *avail); -int uwb_drp_avail_reserve_pending(struct uwb_rc *rc, struct uwb_mas_bm *mas); -void uwb_drp_avail_reserve(struct uwb_rc *rc, struct uwb_mas_bm *mas); -void uwb_drp_avail_release(struct uwb_rc *rc, struct uwb_mas_bm *mas); -void uwb_drp_avail_ie_update(struct uwb_rc *rc); - -/* -- PAL support */ -void uwb_rc_pal_init(struct uwb_rc *rc); - -/* -- Misc */ - -extern ssize_t uwb_mac_frame_hdr_print(char *, size_t, - const struct uwb_mac_frame_hdr *); - -/* -- Debug interface */ -void uwb_dbg_init(void); -void uwb_dbg_exit(void); -void uwb_dbg_add_rc(struct uwb_rc *rc); -void uwb_dbg_del_rc(struct uwb_rc *rc); -struct dentry *uwb_dbg_create_pal_dir(struct uwb_pal *pal); - -static inline void uwb_dev_lock(struct uwb_dev *uwb_dev) -{ - device_lock(&uwb_dev->dev); -} - -static inline void uwb_dev_unlock(struct uwb_dev *uwb_dev) -{ - device_unlock(&uwb_dev->dev); -} - -#endif /* #ifndef __UWB_INTERNAL_H__ */ diff --git a/drivers/uwb/uwbd.c b/drivers/uwb/uwbd.c deleted file mode 100644 index dc5c743d4f5f..000000000000 --- a/drivers/uwb/uwbd.c +++ /dev/null @@ -1,356 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Ultra Wide Band - * Neighborhood Management Daemon - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * This daemon takes care of maintaing information that describes the - * UWB neighborhood that the radios in this machine can see. It also - * keeps a tab of which devices are visible, makes sure each HC sits - * on a different channel to avoid interfering, etc. - * - * Different drivers (radio controller, device, any API in general) - * communicate with this daemon through an event queue. Daemon wakes - * up, takes a list of events and handles them one by one; handling - * function is extracted from a table based on the event's type and - * subtype. Events are freed only if the handling function says so. - * - * . Lock protecting the event list has to be an spinlock and locked - * with IRQSAVE because it might be called from an interrupt - * context (ie: when events arrive and the notification drops - * down from the ISR). - * - * . UWB radio controller drivers queue events to the daemon using - * uwbd_event_queue(). They just get the event, chew it to make it - * look like UWBD likes it and pass it in a buffer allocated with - * uwb_event_alloc(). - * - * EVENTS - * - * Events have a type, a subtype, a length, some other stuff and the - * data blob, which depends on the event. The header is 'struct - * uwb_event'; for payloads, see 'struct uwbd_evt_*'. - * - * EVENT HANDLER TABLES - * - * To find a handling function for an event, the type is used to index - * a subtype-table in the type-table. The subtype-table is indexed - * with the subtype to get the function that handles the event. Start - * with the main type-table 'uwbd_evt_type_handler'. - * - * DEVICES - * - * Devices are created when a bunch of beacons have been received and - * it is stablished that the device has stable radio presence. CREATED - * only, not configured. Devices are ONLY configured when an - * Application-Specific IE Probe is receieved, in which the device - * declares which Protocol ID it groks. Then the device is CONFIGURED - * (and the driver->probe() stuff of the device model is invoked). - * - * Devices are considered disconnected when a certain number of - * beacons are not received in an amount of time. - * - * Handler functions are called normally uwbd_evt_handle_*(). - */ -#include <linux/kthread.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/freezer.h> - -#include "uwb-internal.h" - -/* - * UWBD Event handler function signature - * - * Return !0 if the event needs not to be freed (ie the handler - * takes/took care of it). 0 means the daemon code will free the - * event. - * - * @evt->rc is already referenced and guaranteed to exist. See - * uwb_evt_handle(). - */ -typedef int (*uwbd_evt_handler_f)(struct uwb_event *); - -/** - * Properties of a UWBD event - * - * @handler: the function that will handle this event - * @name: text name of event - */ -struct uwbd_event { - uwbd_evt_handler_f handler; - const char *name; -}; - -/* Table of handlers for and properties of the UWBD Radio Control Events */ -static struct uwbd_event uwbd_urc_events[] = { - [UWB_RC_EVT_IE_RCV] = { - .handler = uwbd_evt_handle_rc_ie_rcv, - .name = "IE_RECEIVED" - }, - [UWB_RC_EVT_BEACON] = { - .handler = uwbd_evt_handle_rc_beacon, - .name = "BEACON_RECEIVED" - }, - [UWB_RC_EVT_BEACON_SIZE] = { - .handler = uwbd_evt_handle_rc_beacon_size, - .name = "BEACON_SIZE_CHANGE" - }, - [UWB_RC_EVT_BPOIE_CHANGE] = { - .handler = uwbd_evt_handle_rc_bpoie_change, - .name = "BPOIE_CHANGE" - }, - [UWB_RC_EVT_BP_SLOT_CHANGE] = { - .handler = uwbd_evt_handle_rc_bp_slot_change, - .name = "BP_SLOT_CHANGE" - }, - [UWB_RC_EVT_DRP_AVAIL] = { - .handler = uwbd_evt_handle_rc_drp_avail, - .name = "DRP_AVAILABILITY_CHANGE" - }, - [UWB_RC_EVT_DRP] = { - .handler = uwbd_evt_handle_rc_drp, - .name = "DRP" - }, - [UWB_RC_EVT_DEV_ADDR_CONFLICT] = { - .handler = uwbd_evt_handle_rc_dev_addr_conflict, - .name = "DEV_ADDR_CONFLICT", - }, -}; - - - -struct uwbd_evt_type_handler { - const char *name; - struct uwbd_event *uwbd_events; - size_t size; -}; - -/* Table of handlers for each UWBD Event type. */ -static struct uwbd_evt_type_handler uwbd_urc_evt_type_handlers[] = { - [UWB_RC_CET_GENERAL] = { - .name = "URC", - .uwbd_events = uwbd_urc_events, - .size = ARRAY_SIZE(uwbd_urc_events), - }, -}; - -static const struct uwbd_event uwbd_message_handlers[] = { - [UWB_EVT_MSG_RESET] = { - .handler = uwbd_msg_handle_reset, - .name = "reset", - }, -}; - -/* - * Handle an URC event passed to the UWB Daemon - * - * @evt: the event to handle - * @returns: 0 if the event can be kfreed, !0 on the contrary - * (somebody else took ownership) [coincidentally, returning - * a <0 errno code will free it :)]. - * - * Looks up the two indirection tables (one for the type, one for the - * subtype) to decide which function handles it and then calls the - * handler. - * - * The event structure passed to the event handler has the radio - * controller in @evt->rc referenced. The reference will be dropped - * once the handler returns, so if it needs it for longer (async), - * it'll need to take another one. - */ -static -int uwbd_event_handle_urc(struct uwb_event *evt) -{ - int result = -EINVAL; - struct uwbd_evt_type_handler *type_table; - uwbd_evt_handler_f handler; - u8 type, context; - u16 event; - - type = evt->notif.rceb->bEventType; - event = le16_to_cpu(evt->notif.rceb->wEvent); - context = evt->notif.rceb->bEventContext; - - if (type >= ARRAY_SIZE(uwbd_urc_evt_type_handlers)) - goto out; - type_table = &uwbd_urc_evt_type_handlers[type]; - if (type_table->uwbd_events == NULL) - goto out; - if (event >= type_table->size) - goto out; - handler = type_table->uwbd_events[event].handler; - if (handler == NULL) - goto out; - - result = (*handler)(evt); -out: - if (result < 0) - dev_err(&evt->rc->uwb_dev.dev, - "UWBD: event 0x%02x/%04x/%02x, handling failed: %d\n", - type, event, context, result); - return result; -} - -static void uwbd_event_handle_message(struct uwb_event *evt) -{ - struct uwb_rc *rc; - int result; - - rc = evt->rc; - - if (evt->message < 0 || evt->message >= ARRAY_SIZE(uwbd_message_handlers)) { - dev_err(&rc->uwb_dev.dev, "UWBD: invalid message type %d\n", evt->message); - return; - } - - result = uwbd_message_handlers[evt->message].handler(evt); - if (result < 0) - dev_err(&rc->uwb_dev.dev, "UWBD: '%s' message failed: %d\n", - uwbd_message_handlers[evt->message].name, result); -} - -static void uwbd_event_handle(struct uwb_event *evt) -{ - struct uwb_rc *rc; - int should_keep; - - rc = evt->rc; - - if (rc->ready) { - switch (evt->type) { - case UWB_EVT_TYPE_NOTIF: - should_keep = uwbd_event_handle_urc(evt); - if (should_keep <= 0) - kfree(evt->notif.rceb); - break; - case UWB_EVT_TYPE_MSG: - uwbd_event_handle_message(evt); - break; - default: - dev_err(&rc->uwb_dev.dev, "UWBD: invalid event type %d\n", evt->type); - break; - } - } - - __uwb_rc_put(rc); /* for the __uwb_rc_get() in uwb_rc_notif_cb() */ -} - -/** - * UWB Daemon - * - * Listens to all UWB notifications and takes care to track the state - * of the UWB neighbourhood for the kernel. When we do a run, we - * spinlock, move the list to a private copy and release the - * lock. Hold it as little as possible. Not a conflict: it is - * guaranteed we own the events in the private list. - * - * FIXME: should change so we don't have a 1HZ timer all the time, but - * only if there are devices. - */ -static int uwbd(void *param) -{ - struct uwb_rc *rc = param; - unsigned long flags; - struct uwb_event *evt; - int should_stop = 0; - - while (1) { - wait_event_interruptible_timeout( - rc->uwbd.wq, - !list_empty(&rc->uwbd.event_list) - || (should_stop = kthread_should_stop()), - HZ); - if (should_stop) - break; - - spin_lock_irqsave(&rc->uwbd.event_list_lock, flags); - if (!list_empty(&rc->uwbd.event_list)) { - evt = list_first_entry(&rc->uwbd.event_list, struct uwb_event, list_node); - list_del(&evt->list_node); - } else - evt = NULL; - spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags); - - if (evt) { - uwbd_event_handle(evt); - kfree(evt); - } - - uwb_beca_purge(rc); /* Purge devices that left */ - } - return 0; -} - - -/** Start the UWB daemon */ -void uwbd_start(struct uwb_rc *rc) -{ - struct task_struct *task = kthread_run(uwbd, rc, "uwbd"); - if (IS_ERR(task)) { - rc->uwbd.task = NULL; - printk(KERN_ERR "UWB: Cannot start management daemon; " - "UWB won't work\n"); - } else { - rc->uwbd.task = task; - rc->uwbd.pid = rc->uwbd.task->pid; - } -} - -/* Stop the UWB daemon and free any unprocessed events */ -void uwbd_stop(struct uwb_rc *rc) -{ - if (rc->uwbd.task) - kthread_stop(rc->uwbd.task); - uwbd_flush(rc); -} - -/* - * Queue an event for the management daemon - * - * When some lower layer receives an event, it uses this function to - * push it forward to the UWB daemon. - * - * Once you pass the event, you don't own it any more, but the daemon - * does. It will uwb_event_free() it when done, so make sure you - * uwb_event_alloc()ed it or bad things will happen. - * - * If the daemon is not running, we just free the event. - */ -void uwbd_event_queue(struct uwb_event *evt) -{ - struct uwb_rc *rc = evt->rc; - unsigned long flags; - - spin_lock_irqsave(&rc->uwbd.event_list_lock, flags); - if (rc->uwbd.pid != 0) { - list_add(&evt->list_node, &rc->uwbd.event_list); - wake_up_all(&rc->uwbd.wq); - } else { - __uwb_rc_put(evt->rc); - if (evt->type == UWB_EVT_TYPE_NOTIF) - kfree(evt->notif.rceb); - kfree(evt); - } - spin_unlock_irqrestore(&rc->uwbd.event_list_lock, flags); - return; -} - -void uwbd_flush(struct uwb_rc *rc) -{ - struct uwb_event *evt, *nxt; - - spin_lock_irq(&rc->uwbd.event_list_lock); - list_for_each_entry_safe(evt, nxt, &rc->uwbd.event_list, list_node) { - if (evt->rc == rc) { - __uwb_rc_put(rc); - list_del(&evt->list_node); - if (evt->type == UWB_EVT_TYPE_NOTIF) - kfree(evt->notif.rceb); - kfree(evt); - } - } - spin_unlock_irq(&rc->uwbd.event_list_lock); -} diff --git a/drivers/uwb/whc-rc.c b/drivers/uwb/whc-rc.c deleted file mode 100644 index 22397f70dee2..000000000000 --- a/drivers/uwb/whc-rc.c +++ /dev/null @@ -1,467 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Wireless Host Controller: Radio Control Interface (WHCI v0.95[2.3]) - * Radio Control command/event transport to the UWB stack - * - * Copyright (C) 2005-2006 Intel Corporation - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - * Initialize and hook up the Radio Control interface. - * - * For each device probed, creates an 'struct whcrc' which contains - * just the representation of the UWB Radio Controller, and the logic - * for reading notifications and passing them to the UWB Core. - * - * So we initialize all of those, register the UWB Radio Controller - * and setup the notification/event handle to pipe the notifications - * to the UWB management Daemon. - * - * Once uwb_rc_add() is called, the UWB stack takes control, resets - * the radio and readies the device to take commands the UWB - * API/user-space. - * - * Note this driver is just a transport driver; the commands are - * formed at the UWB stack and given to this driver who will deliver - * them to the hw and transfer the replies/notifications back to the - * UWB stack through the UWB daemon (UWBD). - */ -#include <linux/init.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/sched.h> -#include <linux/dma-mapping.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/workqueue.h> -#include <linux/uwb.h> -#include <linux/uwb/whci.h> -#include <linux/uwb/umc.h> - -#include "uwb-internal.h" - -/** - * Descriptor for an instance of the UWB Radio Control Driver that - * attaches to the URC interface of the WHCI PCI card. - * - * Unless there is a lock specific to the 'data members', all access - * is protected by uwb_rc->mutex. - */ -struct whcrc { - struct umc_dev *umc_dev; - struct uwb_rc *uwb_rc; /* UWB host controller */ - - unsigned long area; - void __iomem *rc_base; - size_t rc_len; - spinlock_t irq_lock; - - void *evt_buf, *cmd_buf; - dma_addr_t evt_dma_buf, cmd_dma_buf; - wait_queue_head_t cmd_wq; - struct work_struct event_work; -}; - -/** - * Execute an UWB RC command on WHCI/RC - * - * @rc: Instance of a Radio Controller that is a whcrc - * @cmd: Buffer containing the RCCB and payload to execute - * @cmd_size: Size of the command buffer. - * - * We copy the command into whcrc->cmd_buf (as it is pretty and - * aligned`and physically contiguous) and then press the right keys in - * the controller's URCCMD register to get it to read it. We might - * have to wait for the cmd_sem to be open to us. - * - * NOTE: rc's mutex has to be locked - */ -static int whcrc_cmd(struct uwb_rc *uwb_rc, - const struct uwb_rccb *cmd, size_t cmd_size) -{ - int result = 0; - struct whcrc *whcrc = uwb_rc->priv; - struct device *dev = &whcrc->umc_dev->dev; - u32 urccmd; - - if (cmd_size >= 4096) - return -EINVAL; - - /* - * If the URC is halted, then the hardware has reset itself. - * Attempt to recover by restarting the device and then return - * an error as it's likely that the current command isn't - * valid for a newly started RC. - */ - if (le_readl(whcrc->rc_base + URCSTS) & URCSTS_HALTED) { - dev_err(dev, "requesting reset of halted radio controller\n"); - uwb_rc_reset_all(uwb_rc); - return -EIO; - } - - result = wait_event_timeout(whcrc->cmd_wq, - !(le_readl(whcrc->rc_base + URCCMD) & URCCMD_ACTIVE), HZ/2); - if (result == 0) { - dev_err(dev, "device is not ready to execute commands\n"); - return -ETIMEDOUT; - } - - memmove(whcrc->cmd_buf, cmd, cmd_size); - le_writeq(whcrc->cmd_dma_buf, whcrc->rc_base + URCCMDADDR); - - spin_lock(&whcrc->irq_lock); - urccmd = le_readl(whcrc->rc_base + URCCMD); - urccmd &= ~(URCCMD_EARV | URCCMD_SIZE_MASK); - le_writel(urccmd | URCCMD_ACTIVE | URCCMD_IWR | cmd_size, - whcrc->rc_base + URCCMD); - spin_unlock(&whcrc->irq_lock); - - return 0; -} - -static int whcrc_reset(struct uwb_rc *rc) -{ - struct whcrc *whcrc = rc->priv; - - return umc_controller_reset(whcrc->umc_dev); -} - -/** - * Reset event reception mechanism and tell hw we are ready to get more - * - * We have read all the events in the event buffer, so we are ready to - * reset it to the beginning. - * - * This is only called during initialization or after an event buffer - * has been retired. This means we can be sure that event processing - * is disabled and it's safe to update the URCEVTADDR register. - * - * There's no need to wait for the event processing to start as the - * URC will not clear URCCMD_ACTIVE until (internal) event buffer - * space is available. - */ -static -void whcrc_enable_events(struct whcrc *whcrc) -{ - u32 urccmd; - - le_writeq(whcrc->evt_dma_buf, whcrc->rc_base + URCEVTADDR); - - spin_lock(&whcrc->irq_lock); - urccmd = le_readl(whcrc->rc_base + URCCMD) & ~URCCMD_ACTIVE; - le_writel(urccmd | URCCMD_EARV, whcrc->rc_base + URCCMD); - spin_unlock(&whcrc->irq_lock); -} - -static void whcrc_event_work(struct work_struct *work) -{ - struct whcrc *whcrc = container_of(work, struct whcrc, event_work); - size_t size; - u64 urcevtaddr; - - urcevtaddr = le_readq(whcrc->rc_base + URCEVTADDR); - size = urcevtaddr & URCEVTADDR_OFFSET_MASK; - - uwb_rc_neh_grok(whcrc->uwb_rc, whcrc->evt_buf, size); - whcrc_enable_events(whcrc); -} - -/** - * Catch interrupts? - * - * We ack inmediately (and expect the hw to do the right thing and - * raise another IRQ if things have changed :) - */ -static -irqreturn_t whcrc_irq_cb(int irq, void *_whcrc) -{ - struct whcrc *whcrc = _whcrc; - struct device *dev = &whcrc->umc_dev->dev; - u32 urcsts; - - urcsts = le_readl(whcrc->rc_base + URCSTS); - if (!(urcsts & URCSTS_INT_MASK)) - return IRQ_NONE; - le_writel(urcsts & URCSTS_INT_MASK, whcrc->rc_base + URCSTS); - - if (urcsts & URCSTS_HSE) { - dev_err(dev, "host system error -- hardware halted\n"); - /* FIXME: do something sensible here */ - goto out; - } - if (urcsts & URCSTS_ER) - schedule_work(&whcrc->event_work); - if (urcsts & URCSTS_RCI) - wake_up_all(&whcrc->cmd_wq); -out: - return IRQ_HANDLED; -} - - -/** - * Initialize a UMC RC interface: map regions, get (shared) IRQ - */ -static -int whcrc_setup_rc_umc(struct whcrc *whcrc) -{ - int result = 0; - struct device *dev = &whcrc->umc_dev->dev; - struct umc_dev *umc_dev = whcrc->umc_dev; - - whcrc->area = umc_dev->resource.start; - whcrc->rc_len = resource_size(&umc_dev->resource); - result = -EBUSY; - if (request_mem_region(whcrc->area, whcrc->rc_len, KBUILD_MODNAME) == NULL) { - dev_err(dev, "can't request URC region (%zu bytes @ 0x%lx): %d\n", - whcrc->rc_len, whcrc->area, result); - goto error_request_region; - } - - whcrc->rc_base = ioremap_nocache(whcrc->area, whcrc->rc_len); - if (whcrc->rc_base == NULL) { - dev_err(dev, "can't ioremap registers (%zu bytes @ 0x%lx): %d\n", - whcrc->rc_len, whcrc->area, result); - goto error_ioremap_nocache; - } - - result = request_irq(umc_dev->irq, whcrc_irq_cb, IRQF_SHARED, - KBUILD_MODNAME, whcrc); - if (result < 0) { - dev_err(dev, "can't allocate IRQ %d: %d\n", - umc_dev->irq, result); - goto error_request_irq; - } - - result = -ENOMEM; - whcrc->cmd_buf = dma_alloc_coherent(&umc_dev->dev, PAGE_SIZE, - &whcrc->cmd_dma_buf, GFP_KERNEL); - if (whcrc->cmd_buf == NULL) { - dev_err(dev, "Can't allocate cmd transfer buffer\n"); - goto error_cmd_buffer; - } - - whcrc->evt_buf = dma_alloc_coherent(&umc_dev->dev, PAGE_SIZE, - &whcrc->evt_dma_buf, GFP_KERNEL); - if (whcrc->evt_buf == NULL) { - dev_err(dev, "Can't allocate evt transfer buffer\n"); - goto error_evt_buffer; - } - return 0; - -error_evt_buffer: - dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->cmd_buf, - whcrc->cmd_dma_buf); -error_cmd_buffer: - free_irq(umc_dev->irq, whcrc); -error_request_irq: - iounmap(whcrc->rc_base); -error_ioremap_nocache: - release_mem_region(whcrc->area, whcrc->rc_len); -error_request_region: - return result; -} - - -/** - * Release RC's UMC resources - */ -static -void whcrc_release_rc_umc(struct whcrc *whcrc) -{ - struct umc_dev *umc_dev = whcrc->umc_dev; - - dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->evt_buf, - whcrc->evt_dma_buf); - dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->cmd_buf, - whcrc->cmd_dma_buf); - free_irq(umc_dev->irq, whcrc); - iounmap(whcrc->rc_base); - release_mem_region(whcrc->area, whcrc->rc_len); -} - - -/** - * whcrc_start_rc - start a WHCI radio controller - * @whcrc: the radio controller to start - * - * Reset the UMC device, start the radio controller, enable events and - * finally enable interrupts. - */ -static int whcrc_start_rc(struct uwb_rc *rc) -{ - struct whcrc *whcrc = rc->priv; - struct device *dev = &whcrc->umc_dev->dev; - - /* Reset the thing */ - le_writel(URCCMD_RESET, whcrc->rc_base + URCCMD); - if (whci_wait_for(dev, whcrc->rc_base + URCCMD, URCCMD_RESET, 0, - 5000, "hardware reset") < 0) - return -EBUSY; - - /* Set the event buffer, start the controller (enable IRQs later) */ - le_writel(0, whcrc->rc_base + URCINTR); - le_writel(URCCMD_RS, whcrc->rc_base + URCCMD); - if (whci_wait_for(dev, whcrc->rc_base + URCSTS, URCSTS_HALTED, 0, - 5000, "radio controller start") < 0) - return -ETIMEDOUT; - whcrc_enable_events(whcrc); - le_writel(URCINTR_EN_ALL, whcrc->rc_base + URCINTR); - return 0; -} - - -/** - * whcrc_stop_rc - stop a WHCI radio controller - * @whcrc: the radio controller to stop - * - * Disable interrupts and cancel any pending event processing work - * before clearing the Run/Stop bit. - */ -static -void whcrc_stop_rc(struct uwb_rc *rc) -{ - struct whcrc *whcrc = rc->priv; - struct umc_dev *umc_dev = whcrc->umc_dev; - - le_writel(0, whcrc->rc_base + URCINTR); - cancel_work_sync(&whcrc->event_work); - - le_writel(0, whcrc->rc_base + URCCMD); - whci_wait_for(&umc_dev->dev, whcrc->rc_base + URCSTS, - URCSTS_HALTED, URCSTS_HALTED, 100, "radio controller stop"); -} - -static void whcrc_init(struct whcrc *whcrc) -{ - spin_lock_init(&whcrc->irq_lock); - init_waitqueue_head(&whcrc->cmd_wq); - INIT_WORK(&whcrc->event_work, whcrc_event_work); -} - -/** - * Initialize the radio controller. - * - * NOTE: we setup whcrc->uwb_rc before calling uwb_rc_add(); in the - * IRQ handler we use that to determine if the hw is ready to - * handle events. Looks like a race condition, but it really is - * not. - */ -static -int whcrc_probe(struct umc_dev *umc_dev) -{ - int result; - struct uwb_rc *uwb_rc; - struct whcrc *whcrc; - struct device *dev = &umc_dev->dev; - - result = -ENOMEM; - uwb_rc = uwb_rc_alloc(); - if (uwb_rc == NULL) { - dev_err(dev, "unable to allocate RC instance\n"); - goto error_rc_alloc; - } - whcrc = kzalloc(sizeof(*whcrc), GFP_KERNEL); - if (whcrc == NULL) { - dev_err(dev, "unable to allocate WHC-RC instance\n"); - goto error_alloc; - } - whcrc_init(whcrc); - whcrc->umc_dev = umc_dev; - - result = whcrc_setup_rc_umc(whcrc); - if (result < 0) { - dev_err(dev, "Can't setup RC UMC interface: %d\n", result); - goto error_setup_rc_umc; - } - whcrc->uwb_rc = uwb_rc; - - uwb_rc->owner = THIS_MODULE; - uwb_rc->cmd = whcrc_cmd; - uwb_rc->reset = whcrc_reset; - uwb_rc->start = whcrc_start_rc; - uwb_rc->stop = whcrc_stop_rc; - - result = uwb_rc_add(uwb_rc, dev, whcrc); - if (result < 0) - goto error_rc_add; - umc_set_drvdata(umc_dev, whcrc); - return 0; - -error_rc_add: - whcrc_release_rc_umc(whcrc); -error_setup_rc_umc: - kfree(whcrc); -error_alloc: - uwb_rc_put(uwb_rc); -error_rc_alloc: - return result; -} - -/** - * Clean up the radio control resources - * - * When we up the command semaphore, everybody possibly held trying to - * execute a command should be granted entry and then they'll see the - * host is quiescing and up it (so it will chain to the next waiter). - * This should not happen (in any case), as we can only remove when - * there are no handles open... - */ -static void whcrc_remove(struct umc_dev *umc_dev) -{ - struct whcrc *whcrc = umc_get_drvdata(umc_dev); - struct uwb_rc *uwb_rc = whcrc->uwb_rc; - - umc_set_drvdata(umc_dev, NULL); - uwb_rc_rm(uwb_rc); - whcrc_release_rc_umc(whcrc); - kfree(whcrc); - uwb_rc_put(uwb_rc); -} - -static int whcrc_pre_reset(struct umc_dev *umc) -{ - struct whcrc *whcrc = umc_get_drvdata(umc); - struct uwb_rc *uwb_rc = whcrc->uwb_rc; - - uwb_rc_pre_reset(uwb_rc); - return 0; -} - -static int whcrc_post_reset(struct umc_dev *umc) -{ - struct whcrc *whcrc = umc_get_drvdata(umc); - struct uwb_rc *uwb_rc = whcrc->uwb_rc; - - return uwb_rc_post_reset(uwb_rc); -} - -/* PCI device ID's that we handle [so it gets loaded] */ -static struct pci_device_id __used whcrc_id_table[] = { - { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) }, - { /* empty last entry */ } -}; -MODULE_DEVICE_TABLE(pci, whcrc_id_table); - -static struct umc_driver whcrc_driver = { - .name = "whc-rc", - .cap_id = UMC_CAP_ID_WHCI_RC, - .probe = whcrc_probe, - .remove = whcrc_remove, - .pre_reset = whcrc_pre_reset, - .post_reset = whcrc_post_reset, -}; - -static int __init whcrc_driver_init(void) -{ - return umc_driver_register(&whcrc_driver); -} -module_init(whcrc_driver_init); - -static void __exit whcrc_driver_exit(void) -{ - umc_driver_unregister(&whcrc_driver); -} -module_exit(whcrc_driver_exit); - -MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>"); -MODULE_DESCRIPTION("Wireless Host Controller Radio Control Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/uwb/whci.c b/drivers/uwb/whci.c deleted file mode 100644 index be8a8b8e857b..000000000000 --- a/drivers/uwb/whci.c +++ /dev/null @@ -1,257 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * WHCI UWB Multi-interface Controller enumerator. - * - * Copyright (C) 2007 Cambridge Silicon Radio Ltd. - */ -#include <linux/delay.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/dma-mapping.h> -#include <linux/slab.h> -#include <linux/uwb/whci.h> -#include <linux/uwb/umc.h> - -struct whci_card { - struct pci_dev *pci; - void __iomem *uwbbase; - u8 n_caps; - struct umc_dev *devs[0]; -}; - - -/* Fix faulty HW :( */ -static -u64 whci_capdata_quirks(struct whci_card *card, u64 capdata) -{ - u64 capdata_orig = capdata; - struct pci_dev *pci_dev = card->pci; - if (pci_dev->vendor == PCI_VENDOR_ID_INTEL - && (pci_dev->device == 0x0c3b || pci_dev->device == 0004) - && pci_dev->class == 0x0d1010) { - switch (UWBCAPDATA_TO_CAP_ID(capdata)) { - /* WLP capability has 0x100 bytes of aperture */ - case 0x80: - capdata |= 0x40 << 8; break; - /* WUSB capability has 0x80 bytes of aperture - * and ID is 1 */ - case 0x02: - capdata &= ~0xffff; - capdata |= 0x2001; - break; - } - } - if (capdata_orig != capdata) - dev_warn(&pci_dev->dev, - "PCI v%04x d%04x c%06x#%02x: " - "corrected capdata from %016Lx to %016Lx\n", - pci_dev->vendor, pci_dev->device, pci_dev->class, - (unsigned)UWBCAPDATA_TO_CAP_ID(capdata), - (unsigned long long)capdata_orig, - (unsigned long long)capdata); - return capdata; -} - - -/** - * whci_wait_for - wait for a WHCI register to be set - * - * Polls (for at most @max_ms ms) until '*@reg & @mask == @result'. - */ -int whci_wait_for(struct device *dev, u32 __iomem *reg, u32 mask, u32 result, - unsigned long max_ms, const char *tag) -{ - unsigned t = 0; - u32 val; - for (;;) { - val = le_readl(reg); - if ((val & mask) == result) - break; - if (t >= max_ms) { - dev_err(dev, "%s timed out\n", tag); - return -ETIMEDOUT; - } - msleep(10); - t += 10; - } - return 0; -} -EXPORT_SYMBOL_GPL(whci_wait_for); - - -/* - * NOTE: the capinfo and capdata registers are slightly different - * (size and cap-id fields). So for cap #0, we need to fill - * in. Size comes from the size of the register block - * (statically calculated); cap_id comes from nowhere, we use - * zero, that is reserved, for the radio controller, because - * none was defined at the spec level. - */ -static int whci_add_cap(struct whci_card *card, int n) -{ - struct umc_dev *umc; - u64 capdata; - int bar, err; - - umc = umc_device_create(&card->pci->dev, n); - if (umc == NULL) - return -ENOMEM; - - capdata = le_readq(card->uwbbase + UWBCAPDATA(n)); - - bar = UWBCAPDATA_TO_BAR(capdata) << 1; - - capdata = whci_capdata_quirks(card, capdata); - /* Capability 0 is the radio controller. It's size is 32 - * bytes (WHCI0.95[2.3, T2-9]). */ - umc->version = UWBCAPDATA_TO_VERSION(capdata); - umc->cap_id = n == 0 ? 0 : UWBCAPDATA_TO_CAP_ID(capdata); - umc->bar = bar; - umc->resource.start = pci_resource_start(card->pci, bar) - + UWBCAPDATA_TO_OFFSET(capdata); - umc->resource.end = umc->resource.start - + (n == 0 ? 0x20 : UWBCAPDATA_TO_SIZE(capdata)) - 1; - umc->resource.name = dev_name(&umc->dev); - umc->resource.flags = card->pci->resource[bar].flags; - umc->resource.parent = &card->pci->resource[bar]; - umc->irq = card->pci->irq; - - err = umc_device_register(umc); - if (err < 0) - goto error; - card->devs[n] = umc; - return 0; - -error: - kfree(umc); - return err; -} - -static void whci_del_cap(struct whci_card *card, int n) -{ - struct umc_dev *umc = card->devs[n]; - - umc_device_unregister(umc); -} - -static int whci_n_caps(struct pci_dev *pci) -{ - void __iomem *uwbbase; - u64 capinfo; - - uwbbase = pci_iomap(pci, 0, 8); - if (!uwbbase) - return -ENOMEM; - capinfo = le_readq(uwbbase + UWBCAPINFO); - pci_iounmap(pci, uwbbase); - - return UWBCAPINFO_TO_N_CAPS(capinfo); -} - -static int whci_probe(struct pci_dev *pci, const struct pci_device_id *id) -{ - struct whci_card *card; - int err, n_caps, n; - - err = pci_enable_device(pci); - if (err < 0) - goto error; - pci_enable_msi(pci); - pci_set_master(pci); - err = -ENXIO; - if (!pci_set_dma_mask(pci, DMA_BIT_MASK(64))) - pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64)); - else if (!pci_set_dma_mask(pci, DMA_BIT_MASK(32))) - pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)); - else - goto error_dma; - - err = n_caps = whci_n_caps(pci); - if (n_caps < 0) - goto error_ncaps; - - err = -ENOMEM; - card = kzalloc(sizeof(struct whci_card) - + sizeof(struct umc_dev *) * (n_caps + 1), - GFP_KERNEL); - if (card == NULL) - goto error_kzalloc; - card->pci = pci; - card->n_caps = n_caps; - - err = -EBUSY; - if (!request_mem_region(pci_resource_start(pci, 0), - UWBCAPDATA_SIZE(card->n_caps), - "whci (capability data)")) - goto error_request_memregion; - err = -ENOMEM; - card->uwbbase = pci_iomap(pci, 0, UWBCAPDATA_SIZE(card->n_caps)); - if (!card->uwbbase) - goto error_iomap; - - /* Add each capability. */ - for (n = 0; n <= card->n_caps; n++) { - err = whci_add_cap(card, n); - if (err < 0 && n == 0) { - dev_err(&pci->dev, "cannot bind UWB radio controller:" - " %d\n", err); - goto error_bind; - } - if (err < 0) - dev_warn(&pci->dev, "warning: cannot bind capability " - "#%u: %d\n", n, err); - } - pci_set_drvdata(pci, card); - return 0; - -error_bind: - pci_iounmap(pci, card->uwbbase); -error_iomap: - release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps)); -error_request_memregion: - kfree(card); -error_kzalloc: -error_ncaps: -error_dma: - pci_disable_msi(pci); - pci_disable_device(pci); -error: - return err; -} - -static void whci_remove(struct pci_dev *pci) -{ - struct whci_card *card = pci_get_drvdata(pci); - int n; - - pci_set_drvdata(pci, NULL); - /* Unregister each capability in reverse (so the master device - * is unregistered last). */ - for (n = card->n_caps; n >= 0 ; n--) - whci_del_cap(card, n); - pci_iounmap(pci, card->uwbbase); - release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps)); - kfree(card); - pci_disable_msi(pci); - pci_disable_device(pci); -} - -static struct pci_device_id whci_id_table[] = { - { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) }, - { 0 }, -}; -MODULE_DEVICE_TABLE(pci, whci_id_table); - - -static struct pci_driver whci_driver = { - .name = "whci", - .id_table = whci_id_table, - .probe = whci_probe, - .remove = whci_remove, -}; - -module_pci_driver(whci_driver); -MODULE_DESCRIPTION("WHCI UWB Multi-interface Controller enumerator"); -MODULE_AUTHOR("Cambridge Silicon Radio Ltd."); -MODULE_LICENSE("GPL"); |