linux/drivers/uwb/whc-rc.c
<<
>>
Prefs
   1/*
   2 * Wireless Host Controller: Radio Control Interface (WHCI v0.95[2.3])
   3 * Radio Control command/event transport to the UWB stack
   4 *
   5 * Copyright (C) 2005-2006 Intel Corporation
   6 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License version
  10 * 2 as published by the Free Software Foundation.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  20 * 02110-1301, USA.
  21 *
  22 *
  23 * Initialize and hook up the Radio Control interface.
  24 *
  25 * For each device probed, creates an 'struct whcrc' which contains
  26 * just the representation of the UWB Radio Controller, and the logic
  27 * for reading notifications and passing them to the UWB Core.
  28 *
  29 * So we initialize all of those, register the UWB Radio Controller
  30 * and setup the notification/event handle to pipe the notifications
  31 * to the UWB management Daemon.
  32 *
  33 * Once uwb_rc_add() is called, the UWB stack takes control, resets
  34 * the radio and readies the device to take commands the UWB
  35 * API/user-space.
  36 *
  37 * Note this driver is just a transport driver; the commands are
  38 * formed at the UWB stack and given to this driver who will deliver
  39 * them to the hw and transfer the replies/notifications back to the
  40 * UWB stack through the UWB daemon (UWBD).
  41 */
  42#include <linux/init.h>
  43#include <linux/module.h>
  44#include <linux/pci.h>
  45#include <linux/sched.h>
  46#include <linux/dma-mapping.h>
  47#include <linux/interrupt.h>
  48#include <linux/slab.h>
  49#include <linux/workqueue.h>
  50#include <linux/uwb.h>
  51#include <linux/uwb/whci.h>
  52#include <linux/uwb/umc.h>
  53
  54#include "uwb-internal.h"
  55
  56/**
  57 * Descriptor for an instance of the UWB Radio Control Driver that
  58 * attaches to the URC interface of the WHCI PCI card.
  59 *
  60 * Unless there is a lock specific to the 'data members', all access
  61 * is protected by uwb_rc->mutex.
  62 */
  63struct whcrc {
  64        struct umc_dev *umc_dev;
  65        struct uwb_rc *uwb_rc;          /* UWB host controller */
  66
  67        unsigned long area;
  68        void __iomem *rc_base;
  69        size_t rc_len;
  70        spinlock_t irq_lock;
  71
  72        void *evt_buf, *cmd_buf;
  73        dma_addr_t evt_dma_buf, cmd_dma_buf;
  74        wait_queue_head_t cmd_wq;
  75        struct work_struct event_work;
  76};
  77
  78/**
  79 * Execute an UWB RC command on WHCI/RC
  80 *
  81 * @rc:       Instance of a Radio Controller that is a whcrc
  82 * @cmd:      Buffer containing the RCCB and payload to execute
  83 * @cmd_size: Size of the command buffer.
  84 *
  85 * We copy the command into whcrc->cmd_buf (as it is pretty and
  86 * aligned`and physically contiguous) and then press the right keys in
  87 * the controller's URCCMD register to get it to read it. We might
  88 * have to wait for the cmd_sem to be open to us.
  89 *
  90 * NOTE: rc's mutex has to be locked
  91 */
  92static int whcrc_cmd(struct uwb_rc *uwb_rc,
  93              const struct uwb_rccb *cmd, size_t cmd_size)
  94{
  95        int result = 0;
  96        struct whcrc *whcrc = uwb_rc->priv;
  97        struct device *dev = &whcrc->umc_dev->dev;
  98        u32 urccmd;
  99
 100        if (cmd_size >= 4096)
 101                return -EINVAL;
 102
 103        /*
 104         * If the URC is halted, then the hardware has reset itself.
 105         * Attempt to recover by restarting the device and then return
 106         * an error as it's likely that the current command isn't
 107         * valid for a newly started RC.
 108         */
 109        if (le_readl(whcrc->rc_base + URCSTS) & URCSTS_HALTED) {
 110                dev_err(dev, "requesting reset of halted radio controller\n");
 111                uwb_rc_reset_all(uwb_rc);
 112                return -EIO;
 113        }
 114
 115        result = wait_event_timeout(whcrc->cmd_wq,
 116                !(le_readl(whcrc->rc_base + URCCMD) & URCCMD_ACTIVE), HZ/2);
 117        if (result == 0) {
 118                dev_err(dev, "device is not ready to execute commands\n");
 119                return -ETIMEDOUT;
 120        }
 121
 122        memmove(whcrc->cmd_buf, cmd, cmd_size);
 123        le_writeq(whcrc->cmd_dma_buf, whcrc->rc_base + URCCMDADDR);
 124
 125        spin_lock(&whcrc->irq_lock);
 126        urccmd = le_readl(whcrc->rc_base + URCCMD);
 127        urccmd &= ~(URCCMD_EARV | URCCMD_SIZE_MASK);
 128        le_writel(urccmd | URCCMD_ACTIVE | URCCMD_IWR | cmd_size,
 129                  whcrc->rc_base + URCCMD);
 130        spin_unlock(&whcrc->irq_lock);
 131
 132        return 0;
 133}
 134
 135static int whcrc_reset(struct uwb_rc *rc)
 136{
 137        struct whcrc *whcrc = rc->priv;
 138
 139        return umc_controller_reset(whcrc->umc_dev);
 140}
 141
 142/**
 143 * Reset event reception mechanism and tell hw we are ready to get more
 144 *
 145 * We have read all the events in the event buffer, so we are ready to
 146 * reset it to the beginning.
 147 *
 148 * This is only called during initialization or after an event buffer
 149 * has been retired.  This means we can be sure that event processing
 150 * is disabled and it's safe to update the URCEVTADDR register.
 151 *
 152 * There's no need to wait for the event processing to start as the
 153 * URC will not clear URCCMD_ACTIVE until (internal) event buffer
 154 * space is available.
 155 */
 156static
 157void whcrc_enable_events(struct whcrc *whcrc)
 158{
 159        u32 urccmd;
 160
 161        le_writeq(whcrc->evt_dma_buf, whcrc->rc_base + URCEVTADDR);
 162
 163        spin_lock(&whcrc->irq_lock);
 164        urccmd = le_readl(whcrc->rc_base + URCCMD) & ~URCCMD_ACTIVE;
 165        le_writel(urccmd | URCCMD_EARV, whcrc->rc_base + URCCMD);
 166        spin_unlock(&whcrc->irq_lock);
 167}
 168
 169static void whcrc_event_work(struct work_struct *work)
 170{
 171        struct whcrc *whcrc = container_of(work, struct whcrc, event_work);
 172        size_t size;
 173        u64 urcevtaddr;
 174
 175        urcevtaddr = le_readq(whcrc->rc_base + URCEVTADDR);
 176        size = urcevtaddr & URCEVTADDR_OFFSET_MASK;
 177
 178        uwb_rc_neh_grok(whcrc->uwb_rc, whcrc->evt_buf, size);
 179        whcrc_enable_events(whcrc);
 180}
 181
 182/**
 183 * Catch interrupts?
 184 *
 185 * We ack inmediately (and expect the hw to do the right thing and
 186 * raise another IRQ if things have changed :)
 187 */
 188static
 189irqreturn_t whcrc_irq_cb(int irq, void *_whcrc)
 190{
 191        struct whcrc *whcrc = _whcrc;
 192        struct device *dev = &whcrc->umc_dev->dev;
 193        u32 urcsts;
 194
 195        urcsts = le_readl(whcrc->rc_base + URCSTS);
 196        if (!(urcsts & URCSTS_INT_MASK))
 197                return IRQ_NONE;
 198        le_writel(urcsts & URCSTS_INT_MASK, whcrc->rc_base + URCSTS);
 199
 200        if (urcsts & URCSTS_HSE) {
 201                dev_err(dev, "host system error -- hardware halted\n");
 202                /* FIXME: do something sensible here */
 203                goto out;
 204        }
 205        if (urcsts & URCSTS_ER)
 206                schedule_work(&whcrc->event_work);
 207        if (urcsts & URCSTS_RCI)
 208                wake_up_all(&whcrc->cmd_wq);
 209out:
 210        return IRQ_HANDLED;
 211}
 212
 213
 214/**
 215 * Initialize a UMC RC interface: map regions, get (shared) IRQ
 216 */
 217static
 218int whcrc_setup_rc_umc(struct whcrc *whcrc)
 219{
 220        int result = 0;
 221        struct device *dev = &whcrc->umc_dev->dev;
 222        struct umc_dev *umc_dev = whcrc->umc_dev;
 223
 224        whcrc->area = umc_dev->resource.start;
 225        whcrc->rc_len = resource_size(&umc_dev->resource);
 226        result = -EBUSY;
 227        if (request_mem_region(whcrc->area, whcrc->rc_len, KBUILD_MODNAME) == NULL) {
 228                dev_err(dev, "can't request URC region (%zu bytes @ 0x%lx): %d\n",
 229                        whcrc->rc_len, whcrc->area, result);
 230                goto error_request_region;
 231        }
 232
 233        whcrc->rc_base = ioremap_nocache(whcrc->area, whcrc->rc_len);
 234        if (whcrc->rc_base == NULL) {
 235                dev_err(dev, "can't ioremap registers (%zu bytes @ 0x%lx): %d\n",
 236                        whcrc->rc_len, whcrc->area, result);
 237                goto error_ioremap_nocache;
 238        }
 239
 240        result = request_irq(umc_dev->irq, whcrc_irq_cb, IRQF_SHARED,
 241                             KBUILD_MODNAME, whcrc);
 242        if (result < 0) {
 243                dev_err(dev, "can't allocate IRQ %d: %d\n",
 244                        umc_dev->irq, result);
 245                goto error_request_irq;
 246        }
 247
 248        result = -ENOMEM;
 249        whcrc->cmd_buf = dma_alloc_coherent(&umc_dev->dev, PAGE_SIZE,
 250                                            &whcrc->cmd_dma_buf, GFP_KERNEL);
 251        if (whcrc->cmd_buf == NULL) {
 252                dev_err(dev, "Can't allocate cmd transfer buffer\n");
 253                goto error_cmd_buffer;
 254        }
 255
 256        whcrc->evt_buf = dma_alloc_coherent(&umc_dev->dev, PAGE_SIZE,
 257                                            &whcrc->evt_dma_buf, GFP_KERNEL);
 258        if (whcrc->evt_buf == NULL) {
 259                dev_err(dev, "Can't allocate evt transfer buffer\n");
 260                goto error_evt_buffer;
 261        }
 262        return 0;
 263
 264error_evt_buffer:
 265        dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->cmd_buf,
 266                          whcrc->cmd_dma_buf);
 267error_cmd_buffer:
 268        free_irq(umc_dev->irq, whcrc);
 269error_request_irq:
 270        iounmap(whcrc->rc_base);
 271error_ioremap_nocache:
 272        release_mem_region(whcrc->area, whcrc->rc_len);
 273error_request_region:
 274        return result;
 275}
 276
 277
 278/**
 279 * Release RC's UMC resources
 280 */
 281static
 282void whcrc_release_rc_umc(struct whcrc *whcrc)
 283{
 284        struct umc_dev *umc_dev = whcrc->umc_dev;
 285
 286        dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->evt_buf,
 287                          whcrc->evt_dma_buf);
 288        dma_free_coherent(&umc_dev->dev, PAGE_SIZE, whcrc->cmd_buf,
 289                          whcrc->cmd_dma_buf);
 290        free_irq(umc_dev->irq, whcrc);
 291        iounmap(whcrc->rc_base);
 292        release_mem_region(whcrc->area, whcrc->rc_len);
 293}
 294
 295
 296/**
 297 * whcrc_start_rc - start a WHCI radio controller
 298 * @whcrc: the radio controller to start
 299 *
 300 * Reset the UMC device, start the radio controller, enable events and
 301 * finally enable interrupts.
 302 */
 303static int whcrc_start_rc(struct uwb_rc *rc)
 304{
 305        struct whcrc *whcrc = rc->priv;
 306        struct device *dev = &whcrc->umc_dev->dev;
 307
 308        /* Reset the thing */
 309        le_writel(URCCMD_RESET, whcrc->rc_base + URCCMD);
 310        if (whci_wait_for(dev, whcrc->rc_base + URCCMD, URCCMD_RESET, 0,
 311                          5000, "hardware reset") < 0)
 312                return -EBUSY;
 313
 314        /* Set the event buffer, start the controller (enable IRQs later) */
 315        le_writel(0, whcrc->rc_base + URCINTR);
 316        le_writel(URCCMD_RS, whcrc->rc_base + URCCMD);
 317        if (whci_wait_for(dev, whcrc->rc_base + URCSTS, URCSTS_HALTED, 0,
 318                          5000, "radio controller start") < 0)
 319                return -ETIMEDOUT;
 320        whcrc_enable_events(whcrc);
 321        le_writel(URCINTR_EN_ALL, whcrc->rc_base + URCINTR);
 322        return 0;
 323}
 324
 325
 326/**
 327 * whcrc_stop_rc - stop a WHCI radio controller
 328 * @whcrc: the radio controller to stop
 329 *
 330 * Disable interrupts and cancel any pending event processing work
 331 * before clearing the Run/Stop bit.
 332 */
 333static
 334void whcrc_stop_rc(struct uwb_rc *rc)
 335{
 336        struct whcrc *whcrc = rc->priv;
 337        struct umc_dev *umc_dev = whcrc->umc_dev;
 338
 339        le_writel(0, whcrc->rc_base + URCINTR);
 340        cancel_work_sync(&whcrc->event_work);
 341
 342        le_writel(0, whcrc->rc_base + URCCMD);
 343        whci_wait_for(&umc_dev->dev, whcrc->rc_base + URCSTS,
 344                      URCSTS_HALTED, URCSTS_HALTED, 100, "radio controller stop");
 345}
 346
 347static void whcrc_init(struct whcrc *whcrc)
 348{
 349        spin_lock_init(&whcrc->irq_lock);
 350        init_waitqueue_head(&whcrc->cmd_wq);
 351        INIT_WORK(&whcrc->event_work, whcrc_event_work);
 352}
 353
 354/**
 355 * Initialize the radio controller.
 356 *
 357 * NOTE: we setup whcrc->uwb_rc before calling uwb_rc_add(); in the
 358 *       IRQ handler we use that to determine if the hw is ready to
 359 *       handle events. Looks like a race condition, but it really is
 360 *       not.
 361 */
 362static
 363int whcrc_probe(struct umc_dev *umc_dev)
 364{
 365        int result;
 366        struct uwb_rc *uwb_rc;
 367        struct whcrc *whcrc;
 368        struct device *dev = &umc_dev->dev;
 369
 370        result = -ENOMEM;
 371        uwb_rc = uwb_rc_alloc();
 372        if (uwb_rc == NULL) {
 373                dev_err(dev, "unable to allocate RC instance\n");
 374                goto error_rc_alloc;
 375        }
 376        whcrc = kzalloc(sizeof(*whcrc), GFP_KERNEL);
 377        if (whcrc == NULL) {
 378                dev_err(dev, "unable to allocate WHC-RC instance\n");
 379                goto error_alloc;
 380        }
 381        whcrc_init(whcrc);
 382        whcrc->umc_dev = umc_dev;
 383
 384        result = whcrc_setup_rc_umc(whcrc);
 385        if (result < 0) {
 386                dev_err(dev, "Can't setup RC UMC interface: %d\n", result);
 387                goto error_setup_rc_umc;
 388        }
 389        whcrc->uwb_rc = uwb_rc;
 390
 391        uwb_rc->owner = THIS_MODULE;
 392        uwb_rc->cmd   = whcrc_cmd;
 393        uwb_rc->reset = whcrc_reset;
 394        uwb_rc->start = whcrc_start_rc;
 395        uwb_rc->stop  = whcrc_stop_rc;
 396
 397        result = uwb_rc_add(uwb_rc, dev, whcrc);
 398        if (result < 0)
 399                goto error_rc_add;
 400        umc_set_drvdata(umc_dev, whcrc);
 401        return 0;
 402
 403error_rc_add:
 404        whcrc_release_rc_umc(whcrc);
 405error_setup_rc_umc:
 406        kfree(whcrc);
 407error_alloc:
 408        uwb_rc_put(uwb_rc);
 409error_rc_alloc:
 410        return result;
 411}
 412
 413/**
 414 * Clean up the radio control resources
 415 *
 416 * When we up the command semaphore, everybody possibly held trying to
 417 * execute a command should be granted entry and then they'll see the
 418 * host is quiescing and up it (so it will chain to the next waiter).
 419 * This should not happen (in any case), as we can only remove when
 420 * there are no handles open...
 421 */
 422static void whcrc_remove(struct umc_dev *umc_dev)
 423{
 424        struct whcrc *whcrc = umc_get_drvdata(umc_dev);
 425        struct uwb_rc *uwb_rc = whcrc->uwb_rc;
 426
 427        umc_set_drvdata(umc_dev, NULL);
 428        uwb_rc_rm(uwb_rc);
 429        whcrc_release_rc_umc(whcrc);
 430        kfree(whcrc);
 431        uwb_rc_put(uwb_rc);
 432}
 433
 434static int whcrc_pre_reset(struct umc_dev *umc)
 435{
 436        struct whcrc *whcrc = umc_get_drvdata(umc);
 437        struct uwb_rc *uwb_rc = whcrc->uwb_rc;
 438
 439        uwb_rc_pre_reset(uwb_rc);
 440        return 0;
 441}
 442
 443static int whcrc_post_reset(struct umc_dev *umc)
 444{
 445        struct whcrc *whcrc = umc_get_drvdata(umc);
 446        struct uwb_rc *uwb_rc = whcrc->uwb_rc;
 447
 448        return uwb_rc_post_reset(uwb_rc);
 449}
 450
 451/* PCI device ID's that we handle [so it gets loaded] */
 452static struct pci_device_id __used whcrc_id_table[] = {
 453        { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
 454        { /* empty last entry */ }
 455};
 456MODULE_DEVICE_TABLE(pci, whcrc_id_table);
 457
 458static struct umc_driver whcrc_driver = {
 459        .name       = "whc-rc",
 460        .cap_id     = UMC_CAP_ID_WHCI_RC,
 461        .probe      = whcrc_probe,
 462        .remove     = whcrc_remove,
 463        .pre_reset  = whcrc_pre_reset,
 464        .post_reset = whcrc_post_reset,
 465};
 466
 467static int __init whcrc_driver_init(void)
 468{
 469        return umc_driver_register(&whcrc_driver);
 470}
 471module_init(whcrc_driver_init);
 472
 473static void __exit whcrc_driver_exit(void)
 474{
 475        umc_driver_unregister(&whcrc_driver);
 476}
 477module_exit(whcrc_driver_exit);
 478
 479MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
 480MODULE_DESCRIPTION("Wireless Host Controller Radio Control Driver");
 481MODULE_LICENSE("GPL");
 482
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.