linux/drivers/misc/mic/card/mic_x100.c
<<
>>
Prefs
   1/*
   2 * Intel MIC Platform Software Stack (MPSS)
   3 *
   4 * Copyright(c) 2013 Intel Corporation.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License, version 2, as
   8 * published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful, but
  11 * WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13 * General Public License for more details.
  14 *
  15 * The full GNU General Public License is included in this distribution in
  16 * the file called "COPYING".
  17 *
  18 * Disclaimer: The codes contained in these modules may be specific to
  19 * the Intel Software Development Platform codenamed: Knights Ferry, and
  20 * the Intel product codenamed: Knights Corner, and are not backward
  21 * compatible with other Intel products. Additionally, Intel will NOT
  22 * support the codes or instruction set in future products.
  23 *
  24 * Intel MIC Card driver.
  25 *
  26 */
  27#include <linux/module.h>
  28#include <linux/pci.h>
  29#include <linux/platform_device.h>
  30
  31#include "../common/mic_dev.h"
  32#include "mic_device.h"
  33#include "mic_x100.h"
  34
  35static const char mic_driver_name[] = "mic";
  36
  37static struct mic_driver g_drv;
  38
  39/**
  40 * mic_read_spad - read from the scratchpad register
  41 * @mdev: pointer to mic_device instance
  42 * @idx: index to scratchpad register, 0 based
  43 *
  44 * This function allows reading of the 32bit scratchpad register.
  45 *
  46 * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
  47 */
  48u32 mic_read_spad(struct mic_device *mdev, unsigned int idx)
  49{
  50        return mic_mmio_read(&mdev->mmio,
  51                MIC_X100_SBOX_BASE_ADDRESS +
  52                MIC_X100_SBOX_SPAD0 + idx * 4);
  53}
  54
  55/**
  56 * __mic_send_intr - Send interrupt to Host.
  57 * @mdev: pointer to mic_device instance
  58 * @doorbell: Doorbell number.
  59 */
  60void mic_send_intr(struct mic_device *mdev, int doorbell)
  61{
  62        struct mic_mw *mw = &mdev->mmio;
  63
  64        if (doorbell > MIC_X100_MAX_DOORBELL_IDX)
  65                return;
  66        /* Ensure that the interrupt is ordered w.r.t previous stores. */
  67        wmb();
  68        mic_mmio_write(mw, MIC_X100_SBOX_SDBIC0_DBREQ_BIT,
  69                       MIC_X100_SBOX_BASE_ADDRESS +
  70                       (MIC_X100_SBOX_SDBIC0 + (4 * doorbell)));
  71}
  72
  73/*
  74 * mic_x100_send_sbox_intr - Send an MIC_X100_SBOX interrupt to MIC.
  75 */
  76static void mic_x100_send_sbox_intr(struct mic_mw *mw, int doorbell)
  77{
  78        u64 apic_icr_offset = MIC_X100_SBOX_APICICR0 + doorbell * 8;
  79        u32 apicicr_low = mic_mmio_read(mw, MIC_X100_SBOX_BASE_ADDRESS +
  80                                        apic_icr_offset);
  81
  82        /* for MIC we need to make sure we "hit" the send_icr bit (13) */
  83        apicicr_low = (apicicr_low | (1 << 13));
  84        /*
  85         * Ensure that the interrupt is ordered w.r.t. previous stores
  86         * to main memory. Fence instructions are not implemented in X100
  87         * since execution is in order but a compiler barrier is still
  88         * required.
  89         */
  90        wmb();
  91        mic_mmio_write(mw, apicicr_low,
  92                       MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset);
  93}
  94
  95static void mic_x100_send_rdmasr_intr(struct mic_mw *mw, int doorbell)
  96{
  97        int rdmasr_offset = MIC_X100_SBOX_RDMASR0 + (doorbell << 2);
  98        /*
  99         * Ensure that the interrupt is ordered w.r.t. previous stores
 100         * to main memory. Fence instructions are not implemented in X100
 101         * since execution is in order but a compiler barrier is still
 102         * required.
 103         */
 104        wmb();
 105        mic_mmio_write(mw, 0, MIC_X100_SBOX_BASE_ADDRESS + rdmasr_offset);
 106}
 107
 108/**
 109 * mic_ack_interrupt - Device specific interrupt handling.
 110 * @mdev: pointer to mic_device instance
 111 *
 112 * Returns: bitmask of doorbell events triggered.
 113 */
 114u32 mic_ack_interrupt(struct mic_device *mdev)
 115{
 116        return 0;
 117}
 118
 119static inline int mic_get_sbox_irq(int db)
 120{
 121        return MIC_X100_IRQ_BASE + db;
 122}
 123
 124static inline int mic_get_rdmasr_irq(int index)
 125{
 126        return  MIC_X100_RDMASR_IRQ_BASE + index;
 127}
 128
 129void mic_send_p2p_intr(int db, struct mic_mw *mw)
 130{
 131        int rdmasr_index;
 132
 133        if (db < MIC_X100_NUM_SBOX_IRQ) {
 134                mic_x100_send_sbox_intr(mw, db);
 135        } else {
 136                rdmasr_index = db - MIC_X100_NUM_SBOX_IRQ;
 137                mic_x100_send_rdmasr_intr(mw, rdmasr_index);
 138        }
 139}
 140
 141/**
 142 * mic_hw_intr_init - Initialize h/w specific interrupt
 143 * information.
 144 * @mdrv: pointer to mic_driver
 145 */
 146void mic_hw_intr_init(struct mic_driver *mdrv)
 147{
 148        mdrv->intr_info.num_intr = MIC_X100_NUM_SBOX_IRQ +
 149                                MIC_X100_NUM_RDMASR_IRQ;
 150}
 151
 152/**
 153 * mic_db_to_irq - Retrieve irq number corresponding to a doorbell.
 154 * @mdrv: pointer to mic_driver
 155 * @db: The doorbell obtained for which the irq is needed. Doorbell
 156 * may correspond to an sbox doorbell or an rdmasr index.
 157 *
 158 * Returns the irq corresponding to the doorbell.
 159 */
 160int mic_db_to_irq(struct mic_driver *mdrv, int db)
 161{
 162        int rdmasr_index;
 163
 164        /*
 165         * The total number of doorbell interrupts on the card are 16. Indices
 166         * 0-8 falls in the SBOX category and 8-15 fall in the RDMASR category.
 167         */
 168        if (db < MIC_X100_NUM_SBOX_IRQ) {
 169                return mic_get_sbox_irq(db);
 170        } else {
 171                rdmasr_index = db - MIC_X100_NUM_SBOX_IRQ;
 172                return mic_get_rdmasr_irq(rdmasr_index);
 173        }
 174}
 175
 176/*
 177 * mic_card_map - Allocate virtual address for a remote memory region.
 178 * @mdev: pointer to mic_device instance.
 179 * @addr: Remote DMA address.
 180 * @size: Size of the region.
 181 *
 182 * Returns: Virtual address backing the remote memory region.
 183 */
 184void __iomem *
 185mic_card_map(struct mic_device *mdev, dma_addr_t addr, size_t size)
 186{
 187        return ioremap(addr, size);
 188}
 189
 190/*
 191 * mic_card_unmap - Unmap the virtual address for a remote memory region.
 192 * @mdev: pointer to mic_device instance.
 193 * @addr: Virtual address for remote memory region.
 194 *
 195 * Returns: None.
 196 */
 197void mic_card_unmap(struct mic_device *mdev, void __iomem *addr)
 198{
 199        iounmap(addr);
 200}
 201
 202static inline struct mic_driver *mbdev_to_mdrv(struct mbus_device *mbdev)
 203{
 204        return dev_get_drvdata(mbdev->dev.parent);
 205}
 206
 207static struct mic_irq *
 208_mic_request_threaded_irq(struct mbus_device *mbdev,
 209                          irq_handler_t handler, irq_handler_t thread_fn,
 210                          const char *name, void *data, int intr_src)
 211{
 212        int rc = 0;
 213        unsigned int irq = intr_src;
 214        unsigned long cookie = irq;
 215
 216        rc  = request_threaded_irq(irq, handler, thread_fn, 0, name, data);
 217        if (rc) {
 218                dev_err(mbdev_to_mdrv(mbdev)->dev,
 219                        "request_threaded_irq failed rc = %d\n", rc);
 220                return ERR_PTR(rc);
 221        }
 222        return (struct mic_irq *)cookie;
 223}
 224
 225static void _mic_free_irq(struct mbus_device *mbdev,
 226                          struct mic_irq *cookie, void *data)
 227{
 228        unsigned long irq = (unsigned long)cookie;
 229        free_irq(irq, data);
 230}
 231
 232static void _mic_ack_interrupt(struct mbus_device *mbdev, int num)
 233{
 234        mic_ack_interrupt(&mbdev_to_mdrv(mbdev)->mdev);
 235}
 236
 237static struct mbus_hw_ops mbus_hw_ops = {
 238        .request_threaded_irq = _mic_request_threaded_irq,
 239        .free_irq = _mic_free_irq,
 240        .ack_interrupt = _mic_ack_interrupt,
 241};
 242
 243static int __init mic_probe(struct platform_device *pdev)
 244{
 245        struct mic_driver *mdrv = &g_drv;
 246        struct mic_device *mdev = &mdrv->mdev;
 247        int rc = 0;
 248
 249        mdrv->dev = &pdev->dev;
 250        snprintf(mdrv->name, sizeof(mic_driver_name), mic_driver_name);
 251
 252        mdev->mmio.pa = MIC_X100_MMIO_BASE;
 253        mdev->mmio.len = MIC_X100_MMIO_LEN;
 254        mdev->mmio.va = devm_ioremap(&pdev->dev, MIC_X100_MMIO_BASE,
 255                                     MIC_X100_MMIO_LEN);
 256        if (!mdev->mmio.va) {
 257                dev_err(&pdev->dev, "Cannot remap MMIO BAR\n");
 258                rc = -EIO;
 259                goto done;
 260        }
 261        mic_hw_intr_init(mdrv);
 262        platform_set_drvdata(pdev, mdrv);
 263        mdrv->dma_mbdev = mbus_register_device(mdrv->dev, MBUS_DEV_DMA_MIC,
 264                                               NULL, &mbus_hw_ops, 0,
 265                                               mdrv->mdev.mmio.va);
 266        if (IS_ERR(mdrv->dma_mbdev)) {
 267                rc = PTR_ERR(mdrv->dma_mbdev);
 268                dev_err(&pdev->dev, "mbus_add_device failed rc %d\n", rc);
 269                goto done;
 270        }
 271        rc = mic_driver_init(mdrv);
 272        if (rc) {
 273                dev_err(&pdev->dev, "mic_driver_init failed rc %d\n", rc);
 274                goto remove_dma;
 275        }
 276done:
 277        return rc;
 278remove_dma:
 279        mbus_unregister_device(mdrv->dma_mbdev);
 280        return rc;
 281}
 282
 283static int mic_remove(struct platform_device *pdev)
 284{
 285        struct mic_driver *mdrv = &g_drv;
 286
 287        mic_driver_uninit(mdrv);
 288        mbus_unregister_device(mdrv->dma_mbdev);
 289        return 0;
 290}
 291
 292static void mic_platform_shutdown(struct platform_device *pdev)
 293{
 294        mic_remove(pdev);
 295}
 296
 297static u64 mic_dma_mask = DMA_BIT_MASK(64);
 298
 299static struct platform_device mic_platform_dev = {
 300        .name = mic_driver_name,
 301        .id   = 0,
 302        .num_resources = 0,
 303        .dev = {
 304                .dma_mask = &mic_dma_mask,
 305                .coherent_dma_mask = DMA_BIT_MASK(64),
 306        },
 307};
 308
 309static struct platform_driver __refdata mic_platform_driver = {
 310        .probe = mic_probe,
 311        .remove = mic_remove,
 312        .shutdown = mic_platform_shutdown,
 313        .driver         = {
 314                .name   = mic_driver_name,
 315        },
 316};
 317
 318static int __init mic_init(void)
 319{
 320        int ret;
 321        struct cpuinfo_x86 *c = &cpu_data(0);
 322
 323        if (!(c->x86 == 11 && c->x86_model == 1)) {
 324                ret = -ENODEV;
 325                pr_err("%s not running on X100 ret %d\n", __func__, ret);
 326                goto done;
 327        }
 328
 329        request_module("mic_x100_dma");
 330        mic_init_card_debugfs();
 331        ret = platform_device_register(&mic_platform_dev);
 332        if (ret) {
 333                pr_err("platform_device_register ret %d\n", ret);
 334                goto cleanup_debugfs;
 335        }
 336        ret = platform_driver_register(&mic_platform_driver);
 337        if (ret) {
 338                pr_err("platform_driver_register ret %d\n", ret);
 339                goto device_unregister;
 340        }
 341        return ret;
 342
 343device_unregister:
 344        platform_device_unregister(&mic_platform_dev);
 345cleanup_debugfs:
 346        mic_exit_card_debugfs();
 347done:
 348        return ret;
 349}
 350
 351static void __exit mic_exit(void)
 352{
 353        platform_driver_unregister(&mic_platform_driver);
 354        platform_device_unregister(&mic_platform_dev);
 355        mic_exit_card_debugfs();
 356}
 357
 358module_init(mic_init);
 359module_exit(mic_exit);
 360
 361MODULE_AUTHOR("Intel Corporation");
 362MODULE_DESCRIPTION("Intel(R) MIC X100 Card driver");
 363MODULE_LICENSE("GPL v2");
 364