2013-09-05 16:42:06 -07:00
/*
* Intel MIC Platform Software Stack ( MPSS )
*
* Copyright ( c ) 2013 Intel Corporation .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms 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 .
*
* The full GNU General Public License is included in this distribution in
* the file called " COPYING " .
*
* Disclaimer : The codes contained in these modules may be specific to
* the Intel Software Development Platform codenamed : Knights Ferry , and
* the Intel product codenamed : Knights Corner , and are not backward
* compatible with other Intel products . Additionally , Intel will NOT
* support the codes or instruction set in future products .
*
* Intel MIC Card driver .
*
*/
# include <linux/module.h>
# include <linux/pci.h>
# include <linux/platform_device.h>
2013-09-27 09:49:42 -07:00
# include "../common/mic_dev.h"
2013-09-05 16:42:06 -07:00
# include "mic_device.h"
# include "mic_x100.h"
static const char mic_driver_name [ ] = " mic " ;
static struct mic_driver g_drv ;
/**
* mic_read_spad - read from the scratchpad register
* @ mdev : pointer to mic_device instance
* @ idx : index to scratchpad register , 0 based
*
* This function allows reading of the 32 bit scratchpad register .
*
* RETURNS : An appropriate - ERRNO error value on error , or zero for success .
*/
u32 mic_read_spad ( struct mic_device * mdev , unsigned int idx )
{
return mic_mmio_read ( & mdev - > mmio ,
MIC_X100_SBOX_BASE_ADDRESS +
MIC_X100_SBOX_SPAD0 + idx * 4 ) ;
}
/**
* __mic_send_intr - Send interrupt to Host .
* @ mdev : pointer to mic_device instance
* @ doorbell : Doorbell number .
*/
void mic_send_intr ( struct mic_device * mdev , int doorbell )
{
struct mic_mw * mw = & mdev - > mmio ;
if ( doorbell > MIC_X100_MAX_DOORBELL_IDX )
return ;
/* Ensure that the interrupt is ordered w.r.t previous stores. */
wmb ( ) ;
mic_mmio_write ( mw , MIC_X100_SBOX_SDBIC0_DBREQ_BIT ,
MIC_X100_SBOX_BASE_ADDRESS +
( MIC_X100_SBOX_SDBIC0 + ( 4 * doorbell ) ) ) ;
}
/**
* mic_ack_interrupt - Device specific interrupt handling .
* @ mdev : pointer to mic_device instance
*
* Returns : bitmask of doorbell events triggered .
*/
u32 mic_ack_interrupt ( struct mic_device * mdev )
{
return 0 ;
}
static inline int mic_get_sbox_irq ( int db )
{
return MIC_X100_IRQ_BASE + db ;
}
static inline int mic_get_rdmasr_irq ( int index )
{
return MIC_X100_RDMASR_IRQ_BASE + index ;
}
/**
* mic_hw_intr_init - Initialize h / w specific interrupt
* information .
* @ mdrv : pointer to mic_driver
*/
void mic_hw_intr_init ( struct mic_driver * mdrv )
{
mdrv - > intr_info . num_intr = MIC_X100_NUM_SBOX_IRQ +
MIC_X100_NUM_RDMASR_IRQ ;
}
/**
* mic_db_to_irq - Retrieve irq number corresponding to a doorbell .
* @ mdrv : pointer to mic_driver
* @ db : The doorbell obtained for which the irq is needed . Doorbell
* may correspond to an sbox doorbell or an rdmasr index .
*
* Returns the irq corresponding to the doorbell .
*/
int mic_db_to_irq ( struct mic_driver * mdrv , int db )
{
int rdmasr_index ;
if ( db < MIC_X100_NUM_SBOX_IRQ ) {
return mic_get_sbox_irq ( db ) ;
} else {
rdmasr_index = db - MIC_X100_NUM_SBOX_IRQ +
MIC_X100_RDMASR_IRQ_BASE ;
return mic_get_rdmasr_irq ( rdmasr_index ) ;
}
}
/*
* mic_card_map - Allocate virtual address for a remote memory region .
* @ mdev : pointer to mic_device instance .
* @ addr : Remote DMA address .
* @ size : Size of the region .
*
* Returns : Virtual address backing the remote memory region .
*/
void __iomem *
mic_card_map ( struct mic_device * mdev , dma_addr_t addr , size_t size )
{
return ioremap ( addr , size ) ;
}
/*
* mic_card_unmap - Unmap the virtual address for a remote memory region .
* @ mdev : pointer to mic_device instance .
* @ addr : Virtual address for remote memory region .
*
* Returns : None .
*/
void mic_card_unmap ( struct mic_device * mdev , void __iomem * addr )
{
iounmap ( addr ) ;
}
static int __init mic_probe ( struct platform_device * pdev )
{
struct mic_driver * mdrv = & g_drv ;
struct mic_device * mdev = & mdrv - > mdev ;
int rc = 0 ;
mdrv - > dev = & pdev - > dev ;
snprintf ( mdrv - > name , sizeof ( mic_driver_name ) , mic_driver_name ) ;
mdev - > mmio . pa = MIC_X100_MMIO_BASE ;
mdev - > mmio . len = MIC_X100_MMIO_LEN ;
mdev - > mmio . va = ioremap ( MIC_X100_MMIO_BASE , MIC_X100_MMIO_LEN ) ;
if ( ! mdev - > mmio . va ) {
dev_err ( & pdev - > dev , " Cannot remap MMIO BAR \n " ) ;
rc = - EIO ;
goto done ;
}
mic_hw_intr_init ( mdrv ) ;
rc = mic_driver_init ( mdrv ) ;
if ( rc ) {
dev_err ( & pdev - > dev , " mic_driver_init failed rc %d \n " , rc ) ;
goto iounmap ;
}
done :
return rc ;
iounmap :
iounmap ( mdev - > mmio . va ) ;
return rc ;
}
static int mic_remove ( struct platform_device * pdev )
{
struct mic_driver * mdrv = & g_drv ;
struct mic_device * mdev = & mdrv - > mdev ;
mic_driver_uninit ( mdrv ) ;
iounmap ( mdev - > mmio . va ) ;
return 0 ;
}
static void mic_platform_shutdown ( struct platform_device * pdev )
{
mic_remove ( pdev ) ;
}
static struct platform_device mic_platform_dev = {
. name = mic_driver_name ,
. id = 0 ,
. num_resources = 0 ,
} ;
static struct platform_driver __refdata mic_platform_driver = {
. probe = mic_probe ,
. remove = mic_remove ,
. shutdown = mic_platform_shutdown ,
. driver = {
. name = mic_driver_name ,
. owner = THIS_MODULE ,
} ,
} ;
static int __init mic_init ( void )
{
int ret ;
struct cpuinfo_x86 * c = & cpu_data ( 0 ) ;
if ( ! ( c - > x86 = = 11 & & c - > x86_model = = 1 ) ) {
ret = - ENODEV ;
pr_err ( " %s not running on X100 ret %d \n " , __func__ , ret ) ;
goto done ;
}
mic_init_card_debugfs ( ) ;
ret = platform_device_register ( & mic_platform_dev ) ;
if ( ret ) {
pr_err ( " platform_device_register ret %d \n " , ret ) ;
goto cleanup_debugfs ;
}
ret = platform_driver_register ( & mic_platform_driver ) ;
if ( ret ) {
pr_err ( " platform_driver_register ret %d \n " , ret ) ;
goto device_unregister ;
}
return ret ;
device_unregister :
platform_device_unregister ( & mic_platform_dev ) ;
cleanup_debugfs :
mic_exit_card_debugfs ( ) ;
done :
return ret ;
}
static void __exit mic_exit ( void )
{
platform_driver_unregister ( & mic_platform_driver ) ;
platform_device_unregister ( & mic_platform_dev ) ;
mic_exit_card_debugfs ( ) ;
}
module_init ( mic_init ) ;
module_exit ( mic_exit ) ;
MODULE_AUTHOR ( " Intel Corporation " ) ;
MODULE_DESCRIPTION ( " Intel(R) MIC X100 Card driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;