2007-10-16 01:27:39 -07:00
/*
* Intel I / OAT DMA Linux driver
2009-02-26 11:05:43 +01:00
* Copyright ( c ) 2007 - 2009 Intel Corporation .
2007-10-16 01:27:39 -07:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin St - Fifth Floor , Boston , MA 02110 - 1301 USA .
*
* The full GNU General Public License is included in this distribution in
* the file called " COPYING " .
*
*/
/*
* This driver supports an Intel I / OAT DMA engine , which does asynchronous
* copy operations .
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/pci.h>
# include <linux/interrupt.h>
2007-10-16 01:27:42 -07:00
# include <linux/dca.h>
2009-07-28 14:32:12 -07:00
# include "dma.h"
2009-08-26 13:01:44 -07:00
# include "dma_v2.h"
2009-07-28 14:32:12 -07:00
# include "registers.h"
# include "hw.h"
2007-10-16 01:27:39 -07:00
2007-10-18 03:07:13 -07:00
MODULE_VERSION ( IOAT_DMA_VERSION ) ;
2009-09-08 17:42:55 -07:00
MODULE_LICENSE ( " Dual BSD/GPL " ) ;
2007-10-16 01:27:39 -07:00
MODULE_AUTHOR ( " Intel Corporation " ) ;
static struct pci_device_id ioat_pci_tbl [ ] = {
2007-11-14 16:59:51 -08:00
/* I/OAT v1 platforms */
2007-10-16 01:27:39 -07:00
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_IOAT ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_IOAT_CNB ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_IOAT_SCNB ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_UNISYS , PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR ) } ,
2007-11-14 16:59:51 -08:00
/* I/OAT v2 platforms */
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_IOAT_SNB ) } ,
2008-07-22 17:30:57 -07:00
/* I/OAT v3 platforms */
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_IOAT_TBG0 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_IOAT_TBG1 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_IOAT_TBG2 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_IOAT_TBG3 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_IOAT_TBG4 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_IOAT_TBG5 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_IOAT_TBG6 ) } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_INTEL , PCI_DEVICE_ID_INTEL_IOAT_TBG7 ) } ,
2007-10-16 01:27:39 -07:00
{ 0 , }
} ;
2009-07-28 14:42:38 -07:00
static int __devinit ioat_pci_probe ( struct pci_dev * pdev ,
const struct pci_device_id * id ) ;
2007-10-16 01:27:39 -07:00
static void __devexit ioat_remove ( struct pci_dev * pdev ) ;
2007-10-16 01:27:42 -07:00
static int ioat_dca_enabled = 1 ;
module_param ( ioat_dca_enabled , int , 0644 ) ;
MODULE_PARM_DESC ( ioat_dca_enabled , " control support of dca service (default: 1) " ) ;
2009-09-08 17:29:44 -07:00
# define DRV_NAME "ioatdma"
2007-10-18 03:07:12 -07:00
static struct pci_driver ioat_pci_driver = {
2009-09-08 17:29:44 -07:00
. name = DRV_NAME ,
2007-10-16 01:27:39 -07:00
. id_table = ioat_pci_tbl ,
2009-07-28 14:42:38 -07:00
. probe = ioat_pci_probe ,
2007-10-16 01:27:39 -07:00
. remove = __devexit_p ( ioat_remove ) ,
} ;
2009-07-28 14:42:38 -07:00
static struct ioatdma_device *
alloc_ioatdma ( struct pci_dev * pdev , void __iomem * iobase )
{
struct device * dev = & pdev - > dev ;
struct ioatdma_device * d = devm_kzalloc ( dev , sizeof ( * d ) , GFP_KERNEL ) ;
if ( ! d )
return NULL ;
d - > pdev = pdev ;
d - > reg_base = iobase ;
return d ;
}
static int __devinit ioat_pci_probe ( struct pci_dev * pdev , const struct pci_device_id * id )
2007-10-16 01:27:39 -07:00
{
2009-09-08 17:29:44 -07:00
void __iomem * const * iomap ;
struct device * dev = & pdev - > dev ;
2009-07-28 14:42:38 -07:00
struct ioatdma_device * device ;
2007-10-16 01:27:39 -07:00
int err ;
2009-09-08 17:29:44 -07:00
err = pcim_enable_device ( pdev ) ;
2007-10-16 01:27:39 -07:00
if ( err )
2009-09-08 17:29:44 -07:00
return err ;
2007-10-16 01:27:39 -07:00
2009-09-08 17:29:44 -07:00
err = pcim_iomap_regions ( pdev , 1 < < IOAT_MMIO_BAR , DRV_NAME ) ;
2007-10-16 01:27:39 -07:00
if ( err )
2009-09-08 17:29:44 -07:00
return err ;
iomap = pcim_iomap_table ( pdev ) ;
if ( ! iomap )
return - ENOMEM ;
2007-10-16 01:27:39 -07:00
2009-04-06 19:01:13 -07:00
err = pci_set_dma_mask ( pdev , DMA_BIT_MASK ( 64 ) ) ;
2007-10-16 01:27:39 -07:00
if ( err )
2009-04-06 19:01:15 -07:00
err = pci_set_dma_mask ( pdev , DMA_BIT_MASK ( 32 ) ) ;
2007-10-16 01:27:39 -07:00
if ( err )
2009-09-08 17:29:44 -07:00
return err ;
2007-10-16 01:27:39 -07:00
2009-04-06 19:01:13 -07:00
err = pci_set_consistent_dma_mask ( pdev , DMA_BIT_MASK ( 64 ) ) ;
2007-10-16 01:27:39 -07:00
if ( err )
2009-04-06 19:01:15 -07:00
err = pci_set_consistent_dma_mask ( pdev , DMA_BIT_MASK ( 32 ) ) ;
2007-10-16 01:27:39 -07:00
if ( err )
2009-09-08 17:29:44 -07:00
return err ;
device = devm_kzalloc ( dev , sizeof ( * device ) , GFP_KERNEL ) ;
if ( ! device )
return - ENOMEM ;
2007-10-16 01:27:39 -07:00
pci_set_master ( pdev ) ;
2009-07-28 14:42:38 -07:00
device = alloc_ioatdma ( pdev , iomap [ IOAT_MMIO_BAR ] ) ;
if ( ! device )
return - ENOMEM ;
pci_set_drvdata ( pdev , device ) ;
device - > version = readb ( device - > reg_base + IOAT_VER_OFFSET ) ;
if ( device - > version = = IOAT_VER_1_2 )
err = ioat1_dma_probe ( device , ioat_dca_enabled ) ;
else if ( device - > version = = IOAT_VER_2_0 )
err = ioat2_dma_probe ( device , ioat_dca_enabled ) ;
else if ( device - > version > = IOAT_VER_3_0 )
err = ioat3_dma_probe ( device , ioat_dca_enabled ) ;
else
2009-09-08 17:29:44 -07:00
return - ENODEV ;
2009-01-06 11:38:20 -07:00
2009-07-28 14:42:38 -07:00
if ( err ) {
2009-09-08 17:29:44 -07:00
dev_err ( dev , " Intel(R) I/OAT DMA Engine init failed \n " ) ;
return - ENODEV ;
}
2007-10-16 01:27:39 -07:00
return 0 ;
}
static void __devexit ioat_remove ( struct pci_dev * pdev )
{
2009-07-28 14:42:38 -07:00
struct ioatdma_device * device = pci_get_drvdata ( pdev ) ;
if ( ! device )
return ;
2007-10-16 01:27:39 -07:00
2009-01-06 11:38:20 -07:00
dev_err ( & pdev - > dev , " Removing dma and dca services \n " ) ;
if ( device - > dca ) {
unregister_dca_provider ( device - > dca ) ;
free_dca_provider ( device - > dca ) ;
device - > dca = NULL ;
}
2009-07-28 14:42:38 -07:00
ioat_dma_remove ( device ) ;
2007-10-16 01:27:39 -07:00
}
static int __init ioat_init_module ( void )
{
2007-10-18 03:07:12 -07:00
return pci_register_driver ( & ioat_pci_driver ) ;
2007-10-16 01:27:39 -07:00
}
module_init ( ioat_init_module ) ;
static void __exit ioat_exit_module ( void )
{
2007-10-18 03:07:12 -07:00
pci_unregister_driver ( & ioat_pci_driver ) ;
2007-10-16 01:27:39 -07:00
}
module_exit ( ioat_exit_module ) ;