Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

uwb: add the driver to enumerate WHCI capabilities

This enumerates the capabilties of a WHCI device, adding a umc device for
each one.

Signed-off-by: David Vrabel <david.vrabel@csr.com>

authored by

David Vrabel and committed by
David Vrabel
8f1b678a da389eac

+387 -1
+1 -1
drivers/uwb/Makefile
··· 1 1 obj-$(CONFIG_UWB) += uwb.o 2 - obj-$(CONFIG_UWB_WHCI) += umc.o 2 + obj-$(CONFIG_UWB_WHCI) += umc.o whci.o 3 3 4 4 uwb-objs := \ 5 5 address.o \
+269
drivers/uwb/whci.c
··· 1 + /* 2 + * WHCI UWB Multi-interface Controller enumerator. 3 + * 4 + * Copyright (C) 2007 Cambridge Silicon Radio Ltd. 5 + * 6 + * This file is released under the GNU GPL v2. 7 + */ 8 + #include <linux/delay.h> 9 + #include <linux/kernel.h> 10 + #include <linux/pci.h> 11 + #include <linux/dma-mapping.h> 12 + #include <linux/uwb/whci.h> 13 + #include <linux/uwb/umc.h> 14 + 15 + struct whci_card { 16 + struct pci_dev *pci; 17 + void __iomem *uwbbase; 18 + u8 n_caps; 19 + struct umc_dev *devs[0]; 20 + }; 21 + 22 + 23 + /* Fix faulty HW :( */ 24 + static 25 + u64 whci_capdata_quirks(struct whci_card *card, u64 capdata) 26 + { 27 + u64 capdata_orig = capdata; 28 + struct pci_dev *pci_dev = card->pci; 29 + if (pci_dev->vendor == PCI_VENDOR_ID_INTEL 30 + && (pci_dev->device == 0x0c3b || pci_dev->device == 0004) 31 + && pci_dev->class == 0x0d1010) { 32 + switch (UWBCAPDATA_TO_CAP_ID(capdata)) { 33 + /* WLP capability has 0x100 bytes of aperture */ 34 + case 0x80: 35 + capdata |= 0x40 << 8; break; 36 + /* WUSB capability has 0x80 bytes of aperture 37 + * and ID is 1 */ 38 + case 0x02: 39 + capdata &= ~0xffff; 40 + capdata |= 0x2001; 41 + break; 42 + } 43 + } 44 + if (capdata_orig != capdata) 45 + dev_warn(&pci_dev->dev, 46 + "PCI v%04x d%04x c%06x#%02x: " 47 + "corrected capdata from %016Lx to %016Lx\n", 48 + pci_dev->vendor, pci_dev->device, pci_dev->class, 49 + (unsigned)UWBCAPDATA_TO_CAP_ID(capdata), 50 + (unsigned long long)capdata_orig, 51 + (unsigned long long)capdata); 52 + return capdata; 53 + } 54 + 55 + 56 + /** 57 + * whci_wait_for - wait for a WHCI register to be set 58 + * 59 + * Polls (for at most @max_ms ms) until '*@reg & @mask == @result'. 60 + */ 61 + int whci_wait_for(struct device *dev, u32 __iomem *reg, u32 mask, u32 result, 62 + unsigned long max_ms, const char *tag) 63 + { 64 + unsigned t = 0; 65 + u32 val; 66 + for (;;) { 67 + val = le_readl(reg); 68 + if ((val & mask) == result) 69 + break; 70 + msleep(10); 71 + if (t >= max_ms) { 72 + dev_err(dev, "timed out waiting for %s ", tag); 73 + return -ETIMEDOUT; 74 + } 75 + t += 10; 76 + } 77 + return 0; 78 + } 79 + EXPORT_SYMBOL_GPL(whci_wait_for); 80 + 81 + 82 + /* 83 + * NOTE: the capinfo and capdata registers are slightly different 84 + * (size and cap-id fields). So for cap #0, we need to fill 85 + * in. Size comes from the size of the register block 86 + * (statically calculated); cap_id comes from nowhere, we use 87 + * zero, that is reserved, for the radio controller, because 88 + * none was defined at the spec level. 89 + */ 90 + static int whci_add_cap(struct whci_card *card, int n) 91 + { 92 + struct umc_dev *umc; 93 + u64 capdata; 94 + int bar, err; 95 + 96 + umc = umc_device_create(&card->pci->dev, n); 97 + if (umc == NULL) 98 + return -ENOMEM; 99 + 100 + capdata = le_readq(card->uwbbase + UWBCAPDATA(n)); 101 + 102 + bar = UWBCAPDATA_TO_BAR(capdata) << 1; 103 + 104 + capdata = whci_capdata_quirks(card, capdata); 105 + /* Capability 0 is the radio controller. It's size is 32 106 + * bytes (WHCI0.95[2.3, T2-9]). */ 107 + umc->version = UWBCAPDATA_TO_VERSION(capdata); 108 + umc->cap_id = n == 0 ? 0 : UWBCAPDATA_TO_CAP_ID(capdata); 109 + umc->bar = bar; 110 + umc->resource.start = pci_resource_start(card->pci, bar) 111 + + UWBCAPDATA_TO_OFFSET(capdata); 112 + umc->resource.end = umc->resource.start 113 + + (n == 0 ? 0x20 : UWBCAPDATA_TO_SIZE(capdata)) - 1; 114 + umc->resource.name = umc->dev.bus_id; 115 + umc->resource.flags = card->pci->resource[bar].flags; 116 + umc->resource.parent = &card->pci->resource[bar]; 117 + umc->irq = card->pci->irq; 118 + 119 + err = umc_device_register(umc); 120 + if (err < 0) 121 + goto error; 122 + card->devs[n] = umc; 123 + return 0; 124 + 125 + error: 126 + kfree(umc); 127 + return err; 128 + } 129 + 130 + static void whci_del_cap(struct whci_card *card, int n) 131 + { 132 + struct umc_dev *umc = card->devs[n]; 133 + 134 + if (umc != NULL) 135 + umc_device_unregister(umc); 136 + } 137 + 138 + static int whci_n_caps(struct pci_dev *pci) 139 + { 140 + void __iomem *uwbbase; 141 + u64 capinfo; 142 + 143 + uwbbase = pci_iomap(pci, 0, 8); 144 + if (!uwbbase) 145 + return -ENOMEM; 146 + capinfo = le_readq(uwbbase + UWBCAPINFO); 147 + pci_iounmap(pci, uwbbase); 148 + 149 + return UWBCAPINFO_TO_N_CAPS(capinfo); 150 + } 151 + 152 + static int whci_probe(struct pci_dev *pci, const struct pci_device_id *id) 153 + { 154 + struct whci_card *card; 155 + int err, n_caps, n; 156 + 157 + err = pci_enable_device(pci); 158 + if (err < 0) 159 + goto error; 160 + pci_enable_msi(pci); 161 + pci_set_master(pci); 162 + err = -ENXIO; 163 + if (!pci_set_dma_mask(pci, DMA_64BIT_MASK)) 164 + pci_set_consistent_dma_mask(pci, DMA_64BIT_MASK); 165 + else if (!pci_set_dma_mask(pci, DMA_32BIT_MASK)) 166 + pci_set_consistent_dma_mask(pci, DMA_32BIT_MASK); 167 + else 168 + goto error_dma; 169 + 170 + err = n_caps = whci_n_caps(pci); 171 + if (n_caps < 0) 172 + goto error_ncaps; 173 + 174 + err = -ENOMEM; 175 + card = kzalloc(sizeof(struct whci_card) 176 + + sizeof(struct whci_dev *) * (n_caps + 1), 177 + GFP_KERNEL); 178 + if (card == NULL) 179 + goto error_kzalloc; 180 + card->pci = pci; 181 + card->n_caps = n_caps; 182 + 183 + err = -EBUSY; 184 + if (!request_mem_region(pci_resource_start(pci, 0), 185 + UWBCAPDATA_SIZE(card->n_caps), 186 + "whci (capability data)")) 187 + goto error_request_memregion; 188 + err = -ENOMEM; 189 + card->uwbbase = pci_iomap(pci, 0, UWBCAPDATA_SIZE(card->n_caps)); 190 + if (!card->uwbbase) 191 + goto error_iomap; 192 + 193 + /* Add each capability. */ 194 + for (n = 0; n <= card->n_caps; n++) { 195 + err = whci_add_cap(card, n); 196 + if (err < 0 && n == 0) { 197 + dev_err(&pci->dev, "cannot bind UWB radio controller:" 198 + " %d\n", err); 199 + goto error_bind; 200 + } 201 + if (err < 0) 202 + dev_warn(&pci->dev, "warning: cannot bind capability " 203 + "#%u: %d\n", n, err); 204 + } 205 + pci_set_drvdata(pci, card); 206 + return 0; 207 + 208 + error_bind: 209 + pci_iounmap(pci, card->uwbbase); 210 + error_iomap: 211 + release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps)); 212 + error_request_memregion: 213 + kfree(card); 214 + error_kzalloc: 215 + error_ncaps: 216 + error_dma: 217 + pci_disable_msi(pci); 218 + pci_disable_device(pci); 219 + error: 220 + return err; 221 + } 222 + 223 + static void whci_remove(struct pci_dev *pci) 224 + { 225 + struct whci_card *card = pci_get_drvdata(pci); 226 + int n; 227 + 228 + pci_set_drvdata(pci, NULL); 229 + /* Unregister each capability in reverse (so the master device 230 + * is unregistered last). */ 231 + for (n = card->n_caps; n >= 0 ; n--) 232 + whci_del_cap(card, n); 233 + pci_iounmap(pci, card->uwbbase); 234 + release_mem_region(pci_resource_start(pci, 0), UWBCAPDATA_SIZE(card->n_caps)); 235 + kfree(card); 236 + pci_disable_msi(pci); 237 + pci_disable_device(pci); 238 + } 239 + 240 + static struct pci_device_id whci_id_table[] = { 241 + { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) }, 242 + { 0 }, 243 + }; 244 + MODULE_DEVICE_TABLE(pci, whci_id_table); 245 + 246 + 247 + static struct pci_driver whci_driver = { 248 + .name = "whci", 249 + .id_table = whci_id_table, 250 + .probe = whci_probe, 251 + .remove = whci_remove, 252 + }; 253 + 254 + static int __init whci_init(void) 255 + { 256 + return pci_register_driver(&whci_driver); 257 + } 258 + 259 + static void __exit whci_exit(void) 260 + { 261 + pci_unregister_driver(&whci_driver); 262 + } 263 + 264 + module_init(whci_init); 265 + module_exit(whci_exit); 266 + 267 + MODULE_DESCRIPTION("WHCI UWB Multi-interface Controller enumerator"); 268 + MODULE_AUTHOR("Cambridge Silicon Radio Ltd."); 269 + MODULE_LICENSE("GPL");
+117
include/linux/uwb/whci.h
··· 1 + /* 2 + * Wireless Host Controller Interface for Ultra-Wide-Band and Wireless USB 3 + * 4 + * Copyright (C) 2005-2006 Intel Corporation 5 + * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> 6 + * 7 + * This program is free software; you can redistribute it and/or 8 + * modify it under the terms of the GNU General Public License version 9 + * 2 as published by the Free Software Foundation. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 + * 02110-1301, USA. 20 + * 21 + * 22 + * 23 + * References: 24 + * [WHCI] Wireless Host Controller Interface Specification for 25 + * Certified Wireless Universal Serial Bus, revision 0.95. 26 + */ 27 + #ifndef _LINUX_UWB_WHCI_H_ 28 + #define _LINUX_UWB_WHCI_H_ 29 + 30 + #include <linux/pci.h> 31 + 32 + /* 33 + * UWB interface capability registers (offsets from UWBBASE) 34 + * 35 + * [WHCI] section 2.2 36 + */ 37 + #define UWBCAPINFO 0x00 /* == UWBCAPDATA(0) */ 38 + # define UWBCAPINFO_TO_N_CAPS(c) (((c) >> 0) & 0xFull) 39 + #define UWBCAPDATA(n) (8*(n)) 40 + # define UWBCAPDATA_TO_VERSION(c) (((c) >> 32) & 0xFFFFull) 41 + # define UWBCAPDATA_TO_OFFSET(c) (((c) >> 18) & 0x3FFFull) 42 + # define UWBCAPDATA_TO_BAR(c) (((c) >> 16) & 0x3ull) 43 + # define UWBCAPDATA_TO_SIZE(c) ((((c) >> 8) & 0xFFull) * sizeof(u32)) 44 + # define UWBCAPDATA_TO_CAP_ID(c) (((c) >> 0) & 0xFFull) 45 + 46 + /* Size of the WHCI capability data (including the RC capability) for 47 + a device with n capabilities. */ 48 + #define UWBCAPDATA_SIZE(n) (8 + 8*(n)) 49 + 50 + 51 + /* 52 + * URC registers (offsets from URCBASE) 53 + * 54 + * [WHCI] section 2.3 55 + */ 56 + #define URCCMD 0x00 57 + # define URCCMD_RESET (1 << 31) /* UMC Hardware reset */ 58 + # define URCCMD_RS (1 << 30) /* Run/Stop */ 59 + # define URCCMD_EARV (1 << 29) /* Event Address Register Valid */ 60 + # define URCCMD_ACTIVE (1 << 15) /* Command is active */ 61 + # define URCCMD_IWR (1 << 14) /* Interrupt When Ready */ 62 + # define URCCMD_SIZE_MASK 0x00000fff /* Command size mask */ 63 + #define URCSTS 0x04 64 + # define URCSTS_EPS (1 << 17) /* Event Processing Status */ 65 + # define URCSTS_HALTED (1 << 16) /* RC halted */ 66 + # define URCSTS_HSE (1 << 10) /* Host System Error...fried */ 67 + # define URCSTS_ER (1 << 9) /* Event Ready */ 68 + # define URCSTS_RCI (1 << 8) /* Ready for Command Interrupt */ 69 + # define URCSTS_INT_MASK 0x00000700 /* URC interrupt sources */ 70 + # define URCSTS_ISI 0x000000ff /* Interrupt Source Identification */ 71 + #define URCINTR 0x08 72 + # define URCINTR_EN_ALL 0x000007ff /* Enable all interrupt sources */ 73 + #define URCCMDADDR 0x10 74 + #define URCEVTADDR 0x18 75 + # define URCEVTADDR_OFFSET_MASK 0xfff /* Event pointer offset mask */ 76 + 77 + 78 + /** Write 32 bit @value to little endian register at @addr */ 79 + static inline 80 + void le_writel(u32 value, void __iomem *addr) 81 + { 82 + iowrite32(value, addr); 83 + } 84 + 85 + 86 + /** Read from 32 bit little endian register at @addr */ 87 + static inline 88 + u32 le_readl(void __iomem *addr) 89 + { 90 + return ioread32(addr); 91 + } 92 + 93 + 94 + /** Write 64 bit @value to little endian register at @addr */ 95 + static inline 96 + void le_writeq(u64 value, void __iomem *addr) 97 + { 98 + iowrite32(value, addr); 99 + iowrite32(value >> 32, addr + 4); 100 + } 101 + 102 + 103 + /** Read from 64 bit little endian register at @addr */ 104 + static inline 105 + u64 le_readq(void __iomem *addr) 106 + { 107 + u64 value; 108 + value = ioread32(addr); 109 + value |= (u64)ioread32(addr + 4) << 32; 110 + return value; 111 + } 112 + 113 + extern int whci_wait_for(struct device *dev, u32 __iomem *reg, 114 + u32 mask, u32 result, 115 + unsigned long max_ms, const char *tag); 116 + 117 + #endif /* #ifndef _LINUX_UWB_WHCI_H_ */