linux/drivers/dma/ioat.c
<<
>>
Prefs
   1/*
   2 * Intel I/OAT DMA Linux driver
   3 * Copyright(c) 2007 Intel Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 *
  14 * You should have received a copy of the GNU General Public License along with
  15 * this program; if not, write to the Free Software Foundation, Inc.,
  16 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  17 *
  18 * The full GNU General Public License is included in this distribution in
  19 * the file called "COPYING".
  20 *
  21 */
  22
  23/*
  24 * This driver supports an Intel I/OAT DMA engine, which does asynchronous
  25 * copy operations.
  26 */
  27
  28#include <linux/init.h>
  29#include <linux/module.h>
  30#include <linux/pci.h>
  31#include <linux/interrupt.h>
  32#include <linux/dca.h>
  33#include "ioatdma.h"
  34#include "ioatdma_registers.h"
  35#include "ioatdma_hw.h"
  36
  37MODULE_VERSION(IOAT_DMA_VERSION);
  38MODULE_LICENSE("GPL");
  39MODULE_AUTHOR("Intel Corporation");
  40
  41static struct pci_device_id ioat_pci_tbl[] = {
  42        /* I/OAT v1 platforms */
  43        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT) },
  44        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_CNB)  },
  45        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SCNB) },
  46        { PCI_DEVICE(PCI_VENDOR_ID_UNISYS, PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR) },
  47
  48        /* I/OAT v2 platforms */
  49        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_SNB) },
  50
  51        /* I/OAT v3 platforms */
  52        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG0) },
  53        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG1) },
  54        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG2) },
  55        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG3) },
  56        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG4) },
  57        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG5) },
  58        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG6) },
  59        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IOAT_TBG7) },
  60        { 0, }
  61};
  62
  63struct ioat_device {
  64        struct pci_dev          *pdev;
  65        void __iomem            *iobase;
  66        struct ioatdma_device   *dma;
  67        struct dca_provider     *dca;
  68};
  69
  70static int __devinit ioat_probe(struct pci_dev *pdev,
  71                                const struct pci_device_id *id);
  72static void __devexit ioat_remove(struct pci_dev *pdev);
  73
  74static int ioat_dca_enabled = 1;
  75module_param(ioat_dca_enabled, int, 0644);
  76MODULE_PARM_DESC(ioat_dca_enabled, "control support of dca service (default: 1)");
  77
  78static int ioat_setup_functionality(struct pci_dev *pdev, void __iomem *iobase)
  79{
  80        struct ioat_device *device = pci_get_drvdata(pdev);
  81        u8 version;
  82        int err = 0;
  83
  84        version = readb(iobase + IOAT_VER_OFFSET);
  85        switch (version) {
  86        case IOAT_VER_1_2:
  87                device->dma = ioat_dma_probe(pdev, iobase);
  88                if (device->dma && ioat_dca_enabled)
  89                        device->dca = ioat_dca_init(pdev, iobase);
  90                break;
  91        case IOAT_VER_2_0:
  92                device->dma = ioat_dma_probe(pdev, iobase);
  93                if (device->dma && ioat_dca_enabled)
  94                        device->dca = ioat2_dca_init(pdev, iobase);
  95                break;
  96        case IOAT_VER_3_0:
  97                device->dma = ioat_dma_probe(pdev, iobase);
  98                if (device->dma && ioat_dca_enabled)
  99                        device->dca = ioat3_dca_init(pdev, iobase);
 100                break;
 101        default:
 102                err = -ENODEV;
 103                break;
 104        }
 105        if (!device->dma)
 106                err = -ENODEV;
 107        return err;
 108}
 109
 110static void ioat_shutdown_functionality(struct pci_dev *pdev)
 111{
 112        struct ioat_device *device = pci_get_drvdata(pdev);
 113
 114        dev_err(&pdev->dev, "Removing dma and dca services\n");
 115        if (device->dca) {
 116                unregister_dca_provider(device->dca);
 117                free_dca_provider(device->dca);
 118                device->dca = NULL;
 119        }
 120
 121        if (device->dma) {
 122                ioat_dma_remove(device->dma);
 123                device->dma = NULL;
 124        }
 125}
 126
 127static struct pci_driver ioat_pci_driver = {
 128        .name           = "ioatdma",
 129        .id_table       = ioat_pci_tbl,
 130        .probe          = ioat_probe,
 131        .shutdown       = ioat_shutdown_functionality,
 132        .remove         = __devexit_p(ioat_remove),
 133};
 134
 135static int __devinit ioat_probe(struct pci_dev *pdev,
 136                                const struct pci_device_id *id)
 137{
 138        void __iomem *iobase;
 139        struct ioat_device *device;
 140        unsigned long mmio_start, mmio_len;
 141        int err;
 142
 143        err = pci_enable_device(pdev);
 144        if (err)
 145                goto err_enable_device;
 146
 147        err = pci_request_regions(pdev, ioat_pci_driver.name);
 148        if (err)
 149                goto err_request_regions;
 150
 151        err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
 152        if (err)
 153                err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 154        if (err)
 155                goto err_set_dma_mask;
 156
 157        err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
 158        if (err)
 159                err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
 160        if (err)
 161                goto err_set_dma_mask;
 162
 163        mmio_start = pci_resource_start(pdev, 0);
 164        mmio_len = pci_resource_len(pdev, 0);
 165        iobase = ioremap(mmio_start, mmio_len);
 166        if (!iobase) {
 167                err = -ENOMEM;
 168                goto err_ioremap;
 169        }
 170
 171        device = kzalloc(sizeof(*device), GFP_KERNEL);
 172        if (!device) {
 173                err = -ENOMEM;
 174                goto err_kzalloc;
 175        }
 176        device->pdev = pdev;
 177        pci_set_drvdata(pdev, device);
 178        device->iobase = iobase;
 179
 180        pci_set_master(pdev);
 181
 182        err = ioat_setup_functionality(pdev, iobase);
 183        if (err)
 184                goto err_version;
 185
 186        return 0;
 187
 188err_version:
 189        kfree(device);
 190err_kzalloc:
 191        iounmap(iobase);
 192err_ioremap:
 193err_set_dma_mask:
 194        pci_release_regions(pdev);
 195        pci_disable_device(pdev);
 196err_request_regions:
 197err_enable_device:
 198        return err;
 199}
 200
 201/*
 202 * It is unsafe to remove this module: if removed while a requested
 203 * dma is outstanding, esp. from tcp, it is possible to hang while
 204 * waiting for something that will never finish.  However, if you're
 205 * feeling lucky, this usually works just fine.
 206 */
 207static void __devexit ioat_remove(struct pci_dev *pdev)
 208{
 209        struct ioat_device *device = pci_get_drvdata(pdev);
 210
 211        ioat_shutdown_functionality(pdev);
 212
 213        kfree(device);
 214}
 215
 216static int __init ioat_init_module(void)
 217{
 218        return pci_register_driver(&ioat_pci_driver);
 219}
 220module_init(ioat_init_module);
 221
 222static void __exit ioat_exit_module(void)
 223{
 224        pci_unregister_driver(&ioat_pci_driver);
 225}
 226module_exit(ioat_exit_module);
 227
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.