@ -21,6 +21,7 @@
# include <linux/delay.h>
# include <linux/firmware.h>
# include <linux/pci.h>
# include <linux/kmod.h>
# include <linux/mic_common.h>
# include <linux/mic_bus.h>
@ -29,6 +30,188 @@
# include "mic_smpt.h"
# include "mic_virtio.h"
static inline struct mic_device * scdev_to_mdev ( struct scif_hw_dev * scdev )
{
return dev_get_drvdata ( scdev - > dev . parent ) ;
}
static void * __mic_dma_alloc ( struct device * dev , size_t size ,
dma_addr_t * dma_handle , gfp_t gfp ,
struct dma_attrs * attrs )
{
struct scif_hw_dev * scdev = dev_get_drvdata ( dev ) ;
struct mic_device * mdev = scdev_to_mdev ( scdev ) ;
dma_addr_t tmp ;
void * va = kmalloc ( size , gfp ) ;
if ( va ) {
tmp = mic_map_single ( mdev , va , size ) ;
if ( dma_mapping_error ( dev , tmp ) ) {
kfree ( va ) ;
va = NULL ;
} else {
* dma_handle = tmp ;
}
}
return va ;
}
static void __mic_dma_free ( struct device * dev , size_t size , void * vaddr ,
dma_addr_t dma_handle , struct dma_attrs * attrs )
{
struct scif_hw_dev * scdev = dev_get_drvdata ( dev ) ;
struct mic_device * mdev = scdev_to_mdev ( scdev ) ;
mic_unmap_single ( mdev , dma_handle , size ) ;
kfree ( vaddr ) ;
}
static dma_addr_t
__mic_dma_map_page ( struct device * dev , struct page * page , unsigned long offset ,
size_t size , enum dma_data_direction dir ,
struct dma_attrs * attrs )
{
void * va = phys_to_virt ( page_to_phys ( page ) ) + offset ;
struct scif_hw_dev * scdev = dev_get_drvdata ( dev ) ;
struct mic_device * mdev = scdev_to_mdev ( scdev ) ;
return mic_map_single ( mdev , va , size ) ;
}
static void
__mic_dma_unmap_page ( struct device * dev , dma_addr_t dma_addr ,
size_t size , enum dma_data_direction dir ,
struct dma_attrs * attrs )
{
struct scif_hw_dev * scdev = dev_get_drvdata ( dev ) ;
struct mic_device * mdev = scdev_to_mdev ( scdev ) ;
mic_unmap_single ( mdev , dma_addr , size ) ;
}
static int __mic_dma_map_sg ( struct device * dev , struct scatterlist * sg ,
int nents , enum dma_data_direction dir ,
struct dma_attrs * attrs )
{
struct scif_hw_dev * scdev = dev_get_drvdata ( dev ) ;
struct mic_device * mdev = scdev_to_mdev ( scdev ) ;
struct scatterlist * s ;
int i , j , ret ;
dma_addr_t da ;
ret = dma_map_sg ( mdev - > sdev - > parent , sg , nents , dir ) ;
if ( ret < = 0 )
return 0 ;
for_each_sg ( sg , s , nents , i ) {
da = mic_map ( mdev , sg_dma_address ( s ) + s - > offset , s - > length ) ;
if ( ! da )
goto err ;
sg_dma_address ( s ) = da ;
}
return nents ;
err :
for_each_sg ( sg , s , i , j ) {
mic_unmap ( mdev , sg_dma_address ( s ) , s - > length ) ;
sg_dma_address ( s ) = mic_to_dma_addr ( mdev , sg_dma_address ( s ) ) ;
}
dma_unmap_sg ( mdev - > sdev - > parent , sg , nents , dir ) ;
return 0 ;
}
static void __mic_dma_unmap_sg ( struct device * dev ,
struct scatterlist * sg , int nents ,
enum dma_data_direction dir ,
struct dma_attrs * attrs )
{
struct scif_hw_dev * scdev = dev_get_drvdata ( dev ) ;
struct mic_device * mdev = scdev_to_mdev ( scdev ) ;
struct scatterlist * s ;
dma_addr_t da ;
int i ;
for_each_sg ( sg , s , nents , i ) {
da = mic_to_dma_addr ( mdev , sg_dma_address ( s ) ) ;
mic_unmap ( mdev , sg_dma_address ( s ) , s - > length ) ;
sg_dma_address ( s ) = da ;
}
dma_unmap_sg ( mdev - > sdev - > parent , sg , nents , dir ) ;
}
static struct dma_map_ops __mic_dma_ops = {
. alloc = __mic_dma_alloc ,
. free = __mic_dma_free ,
. map_page = __mic_dma_map_page ,
. unmap_page = __mic_dma_unmap_page ,
. map_sg = __mic_dma_map_sg ,
. unmap_sg = __mic_dma_unmap_sg ,
} ;
static struct mic_irq *
___mic_request_irq ( struct scif_hw_dev * scdev ,
irqreturn_t ( * func ) ( int irq , void * data ) ,
const char * name ,
void * data , int db )
{
struct mic_device * mdev = scdev_to_mdev ( scdev ) ;
return mic_request_threaded_irq ( mdev , func , NULL , name , data ,
db , MIC_INTR_DB ) ;
}
static void
___mic_free_irq ( struct scif_hw_dev * scdev ,
struct mic_irq * cookie , void * data )
{
struct mic_device * mdev = scdev_to_mdev ( scdev ) ;
return mic_free_irq ( mdev , cookie , data ) ;
}
static void ___mic_ack_interrupt ( struct scif_hw_dev * scdev , int num )
{
struct mic_device * mdev = scdev_to_mdev ( scdev ) ;
mdev - > ops - > intr_workarounds ( mdev ) ;
}
static int ___mic_next_db ( struct scif_hw_dev * scdev )
{
struct mic_device * mdev = scdev_to_mdev ( scdev ) ;
return mic_next_db ( mdev ) ;
}
static void ___mic_send_intr ( struct scif_hw_dev * scdev , int db )
{
struct mic_device * mdev = scdev_to_mdev ( scdev ) ;
mdev - > ops - > send_intr ( mdev , db ) ;
}
static void __iomem * ___mic_ioremap ( struct scif_hw_dev * scdev ,
phys_addr_t pa , size_t len )
{
struct mic_device * mdev = scdev_to_mdev ( scdev ) ;
return mdev - > aper . va + pa ;
}
static void ___mic_iounmap ( struct scif_hw_dev * scdev , void __iomem * va )
{
/* nothing to do */
}
static struct scif_hw_ops scif_hw_ops = {
. request_irq = ___mic_request_irq ,
. free_irq = ___mic_free_irq ,
. ack_interrupt = ___mic_ack_interrupt ,
. next_db = ___mic_next_db ,
. send_intr = ___mic_send_intr ,
. ioremap = ___mic_ioremap ,
. iounmap = ___mic_iounmap ,
} ;
static inline struct mic_device * mbdev_to_mdev ( struct mbus_device * mbdev )
{
return dev_get_drvdata ( mbdev - > dev . parent ) ;
@ -127,6 +310,58 @@ void mic_bootparam_init(struct mic_device *mdev)
bootparam - > h2c_config_db = - 1 ;
bootparam - > shutdown_status = 0 ;
bootparam - > shutdown_card = 0 ;
/* Total nodes = number of MICs + 1 for self node */
bootparam - > tot_nodes = atomic_read ( & g_num_mics ) + 1 ;
bootparam - > node_id = mdev - > id + 1 ;
bootparam - > scif_host_dma_addr = 0x0 ;
bootparam - > scif_card_dma_addr = 0x0 ;
bootparam - > c2h_scif_db = - 1 ;
bootparam - > h2c_scif_db = - 1 ;
}
/**
* mic_request_dma_chans - Request DMA channels
* @ mdev : pointer to mic_device instance
*
* returns number of DMA channels acquired
*/
static int mic_request_dma_chans ( struct mic_device * mdev )
{
dma_cap_mask_t mask ;
struct dma_chan * chan ;
request_module ( " mic_x100_dma " ) ;
dma_cap_zero ( mask ) ;
dma_cap_set ( DMA_MEMCPY , mask ) ;
do {
chan = dma_request_channel ( mask , mdev - > ops - > dma_filter ,
mdev - > sdev - > parent ) ;
if ( chan ) {
mdev - > dma_ch [ mdev - > num_dma_ch + + ] = chan ;
if ( mdev - > num_dma_ch > = MIC_MAX_DMA_CHAN )
break ;
}
} while ( chan ) ;
dev_info ( mdev - > sdev - > parent , " DMA channels # %d \n " , mdev - > num_dma_ch ) ;
return mdev - > num_dma_ch ;
}
/**
* mic_free_dma_chans - release DMA channels
* @ mdev : pointer to mic_device instance
*
* returns none
*/
static void mic_free_dma_chans ( struct mic_device * mdev )
{
int i = 0 ;
for ( i = 0 ; i < mdev - > num_dma_ch ; i + + ) {
dma_release_channel ( mdev - > dma_ch [ i ] ) ;
mdev - > dma_ch [ i ] = NULL ;
}
mdev - > num_dma_ch = 0 ;
}
/**
@ -141,6 +376,7 @@ int mic_start(struct mic_device *mdev, const char *buf)
{
int rc ;
mutex_lock ( & mdev - > mic_mutex ) ;
mic_bootparam_init ( mdev ) ;
retry :
if ( MIC_OFFLINE ! = mdev - > state ) {
rc = - EINVAL ;
@ -161,14 +397,22 @@ retry:
rc = PTR_ERR ( mdev - > dma_mbdev ) ;
goto unlock_ret ;
}
mdev - > dma_ch = mic_request_dma_chan ( mdev ) ;
if ( ! mdev - > dma_ch ) {
rc = - ENXIO ;
if ( ! mic_request_dma_chans ( mdev ) ) {
rc = - ENODEV ;
goto dma_remove ;
}
mdev - > scdev = scif_register_device ( mdev - > sdev - > parent , MIC_SCIF_DEV ,
& __mic_dma_ops , & scif_hw_ops ,
mdev - > id + 1 , 0 , & mdev - > mmio ,
& mdev - > aper , mdev - > dp , NULL ,
mdev - > dma_ch , mdev - > num_dma_ch ) ;
if ( IS_ERR ( mdev - > scdev ) ) {
rc = PTR_ERR ( mdev - > scdev ) ;
goto dma_free ;
}
rc = mdev - > ops - > load_mic_fw ( mdev , buf ) ;
if ( rc )
goto dma_release ;
goto scif_remov e;
mic_smpt_restore ( mdev ) ;
mic_intr_restore ( mdev ) ;
mdev - > intr_ops - > enable_interrupts ( mdev ) ;
@ -177,8 +421,10 @@ retry:
mdev - > ops - > send_firmware_intr ( mdev ) ;
mic_set_state ( mdev , MIC_ONLINE ) ;
goto unlock_ret ;
dma_release :
dma_release_channel ( mdev - > dma_ch ) ;
scif_remove :
scif_unregister_device ( mdev - > scdev ) ;
dma_free :
mic_free_dma_chans ( mdev ) ;
dma_remove :
mbus_unregister_device ( mdev - > dma_mbdev ) ;
unlock_ret :
@ -197,11 +443,9 @@ void mic_stop(struct mic_device *mdev, bool force)
{
mutex_lock ( & mdev - > mic_mutex ) ;
if ( MIC_OFFLINE ! = mdev - > state | | force ) {
scif_unregister_device ( mdev - > scdev ) ;
mic_virtio_reset_devices ( mdev ) ;
if ( mdev - > dma_ch ) {
dma_release_channel ( mdev - > dma_ch ) ;
mdev - > dma_ch = NULL ;
}
mic_free_dma_chans ( mdev ) ;
mbus_unregister_device ( mdev - > dma_mbdev ) ;
mic_bootparam_init ( mdev ) ;
mic_reset ( mdev ) ;