2012-05-09 17:27:20 +04:00
/**
* tpci200 . c
*
* driver for the TEWS TPCI - 200 device
2012-11-16 19:19:58 +04:00
*
* Copyright ( C ) 2009 - 2012 CERN ( www . cern . ch )
* Author : Nicolas Serafini , EIC2 SA
* Author : Samuel Iglesias Gonsalvez < siglesias @ igalia . com >
2012-05-09 17:27:20 +04:00
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the Free
2012-05-11 12:17:14 +04:00
* Software Foundation ; version 2 of the License .
2012-05-09 17:27:20 +04:00
*/
# include <linux/module.h>
2012-10-22 11:36:48 +04:00
# include <linux/slab.h>
2012-05-09 17:27:20 +04:00
# include "tpci200.h"
2012-09-27 14:37:30 +04:00
static const u16 tpci200_status_timeout [ ] = {
2012-09-11 15:34:56 +04:00
TPCI200_A_TIMEOUT ,
TPCI200_B_TIMEOUT ,
TPCI200_C_TIMEOUT ,
TPCI200_D_TIMEOUT ,
} ;
2012-09-27 14:37:30 +04:00
static const u16 tpci200_status_error [ ] = {
2012-09-11 15:34:56 +04:00
TPCI200_A_ERROR ,
TPCI200_B_ERROR ,
TPCI200_C_ERROR ,
TPCI200_D_ERROR ,
} ;
2012-09-27 14:37:31 +04:00
static const size_t tpci200_space_size [ IPACK_SPACE_COUNT ] = {
2012-09-27 14:37:36 +04:00
[ IPACK_IO_SPACE ] = TPCI200_IO_SPACE_SIZE ,
[ IPACK_ID_SPACE ] = TPCI200_ID_SPACE_SIZE ,
[ IPACK_INT_SPACE ] = TPCI200_INT_SPACE_SIZE ,
[ IPACK_MEM8_SPACE ] = TPCI200_MEM8_SPACE_SIZE ,
2012-09-27 14:37:37 +04:00
[ IPACK_MEM16_SPACE ] = TPCI200_MEM16_SPACE_SIZE ,
2012-09-27 14:37:31 +04:00
} ;
static const size_t tpci200_space_interval [ IPACK_SPACE_COUNT ] = {
2012-09-27 14:37:36 +04:00
[ IPACK_IO_SPACE ] = TPCI200_IO_SPACE_INTERVAL ,
[ IPACK_ID_SPACE ] = TPCI200_ID_SPACE_INTERVAL ,
[ IPACK_INT_SPACE ] = TPCI200_INT_SPACE_INTERVAL ,
[ IPACK_MEM8_SPACE ] = TPCI200_MEM8_SPACE_INTERVAL ,
2012-09-27 14:37:37 +04:00
[ IPACK_MEM16_SPACE ] = TPCI200_MEM16_SPACE_INTERVAL ,
2012-09-27 14:37:31 +04:00
} ;
2012-05-09 17:27:20 +04:00
static struct tpci200_board * check_slot ( struct ipack_device * dev )
{
struct tpci200_board * tpci200 ;
2012-05-25 15:08:12 +04:00
if ( dev = = NULL )
2012-05-09 17:27:20 +04:00
return NULL ;
2012-07-20 11:39:04 +04:00
tpci200 = dev_get_drvdata ( dev - > bus - > parent ) ;
if ( tpci200 = = NULL ) {
dev_info ( & dev - > dev , " carrier board not found \n " ) ;
2012-05-09 17:27:20 +04:00
return NULL ;
}
if ( dev - > slot > = TPCI200_NB_SLOT ) {
2012-05-25 15:08:12 +04:00
dev_info ( & dev - > dev ,
" Slot [%d:%d] doesn't exist! Last tpci200 slot is %d. \n " ,
2012-09-27 14:37:25 +04:00
dev - > bus - > bus_nr , dev - > slot , TPCI200_NB_SLOT - 1 ) ;
2012-05-09 17:27:20 +04:00
return NULL ;
}
return tpci200 ;
}
2012-09-12 16:55:23 +04:00
static void tpci200_clear_mask ( struct tpci200_board * tpci200 ,
__le16 __iomem * addr , u16 mask )
{
2012-09-12 16:55:33 +04:00
unsigned long flags ;
spin_lock_irqsave ( & tpci200 - > regs_lock , flags ) ;
iowrite16 ( ioread16 ( addr ) & ( ~ mask ) , addr ) ;
spin_unlock_irqrestore ( & tpci200 - > regs_lock , flags ) ;
2012-09-12 16:55:23 +04:00
}
static void tpci200_set_mask ( struct tpci200_board * tpci200 ,
__le16 __iomem * addr , u16 mask )
{
2012-09-12 16:55:33 +04:00
unsigned long flags ;
spin_lock_irqsave ( & tpci200 - > regs_lock , flags ) ;
iowrite16 ( ioread16 ( addr ) | mask , addr ) ;
spin_unlock_irqrestore ( & tpci200 - > regs_lock , flags ) ;
2012-09-12 16:55:23 +04:00
}
2012-05-09 17:27:20 +04:00
static void tpci200_unregister ( struct tpci200_board * tpci200 )
{
free_irq ( tpci200 - > info - > pdev - > irq , ( void * ) tpci200 ) ;
pci_iounmap ( tpci200 - > info - > pdev , tpci200 - > info - > interface_regs ) ;
2012-09-11 15:35:04 +04:00
pci_iounmap ( tpci200 - > info - > pdev , tpci200 - > info - > cfg_regs ) ;
2012-05-09 17:27:20 +04:00
pci_release_region ( tpci200 - > info - > pdev , TPCI200_IP_INTERFACE_BAR ) ;
pci_release_region ( tpci200 - > info - > pdev , TPCI200_IO_ID_INT_SPACES_BAR ) ;
2012-09-27 14:37:37 +04:00
pci_release_region ( tpci200 - > info - > pdev , TPCI200_MEM16_SPACE_BAR ) ;
2012-05-09 17:27:20 +04:00
pci_release_region ( tpci200 - > info - > pdev , TPCI200_MEM8_SPACE_BAR ) ;
2012-09-11 15:35:04 +04:00
pci_release_region ( tpci200 - > info - > pdev , TPCI200_CFG_MEM_BAR ) ;
2012-05-09 17:27:20 +04:00
pci_disable_device ( tpci200 - > info - > pdev ) ;
pci_dev_put ( tpci200 - > info - > pdev ) ;
}
2012-09-12 16:55:36 +04:00
static void tpci200_enable_irq ( struct tpci200_board * tpci200 ,
int islot )
{
tpci200_set_mask ( tpci200 ,
& tpci200 - > info - > interface_regs - > control [ islot ] ,
TPCI200_INT0_EN | TPCI200_INT1_EN ) ;
}
static void tpci200_disable_irq ( struct tpci200_board * tpci200 ,
int islot )
{
tpci200_clear_mask ( tpci200 ,
& tpci200 - > info - > interface_regs - > control [ islot ] ,
TPCI200_INT0_EN | TPCI200_INT1_EN ) ;
}
2012-09-12 16:55:25 +04:00
static irqreturn_t tpci200_slot_irq ( struct slot_irq * slot_irq )
{
2012-09-12 16:55:35 +04:00
irqreturn_t ret ;
2012-09-12 16:55:25 +04:00
2012-09-12 16:55:35 +04:00
if ( ! slot_irq )
return - ENODEV ;
ret = slot_irq - > handler ( slot_irq - > arg ) ;
2012-09-12 16:55:25 +04:00
return ret ;
}
2012-05-09 17:27:20 +04:00
static irqreturn_t tpci200_interrupt ( int irq , void * dev_id )
{
struct tpci200_board * tpci200 = ( struct tpci200_board * ) dev_id ;
2012-09-11 15:35:13 +04:00
struct slot_irq * slot_irq ;
2012-09-12 16:55:35 +04:00
irqreturn_t ret ;
u16 status_reg ;
int i ;
2012-05-09 17:27:20 +04:00
/* Read status register */
2012-09-12 16:55:35 +04:00
status_reg = ioread16 ( & tpci200 - > info - > interface_regs - > status ) ;
2012-05-09 17:27:20 +04:00
2012-09-12 16:55:35 +04:00
/* Did we cause the interrupt? */
if ( ! ( status_reg & TPCI200_SLOT_INT_MASK ) )
2012-09-12 16:55:34 +04:00
return IRQ_NONE ;
2012-09-12 16:55:35 +04:00
/* callback to the IRQ handler for the corresponding slot */
rcu_read_lock ( ) ;
for ( i = 0 ; i < TPCI200_NB_SLOT ; i + + ) {
if ( ! ( status_reg & ( ( TPCI200_A_INT0 | TPCI200_A_INT1 ) < < ( 2 * i ) ) ) )
continue ;
slot_irq = rcu_dereference ( tpci200 - > slots [ i ] . irq ) ;
ret = tpci200_slot_irq ( slot_irq ) ;
if ( ret = = - ENODEV ) {
dev_info ( & tpci200 - > info - > pdev - > dev ,
" No registered ISR for slot [%d:%d]!. IRQ will be disabled. \n " ,
tpci200 - > number , i ) ;
2012-09-12 16:55:36 +04:00
tpci200_disable_irq ( tpci200 , i ) ;
2012-09-12 16:55:35 +04:00
}
2012-09-12 16:55:34 +04:00
}
2012-09-12 16:55:35 +04:00
rcu_read_unlock ( ) ;
return IRQ_HANDLED ;
2012-05-09 17:27:20 +04:00
}
2012-09-12 16:55:37 +04:00
static int tpci200_free_irq ( struct ipack_device * dev )
{
struct slot_irq * slot_irq ;
struct tpci200_board * tpci200 ;
tpci200 = check_slot ( dev ) ;
if ( tpci200 = = NULL )
return - EINVAL ;
if ( mutex_lock_interruptible ( & tpci200 - > mutex ) )
return - ERESTARTSYS ;
if ( tpci200 - > slots [ dev - > slot ] . irq = = NULL ) {
mutex_unlock ( & tpci200 - > mutex ) ;
return - EINVAL ;
}
tpci200_disable_irq ( tpci200 , dev - > slot ) ;
slot_irq = tpci200 - > slots [ dev - > slot ] . irq ;
/* uninstall handler */
RCU_INIT_POINTER ( tpci200 - > slots [ dev - > slot ] . irq , NULL ) ;
synchronize_rcu ( ) ;
kfree ( slot_irq ) ;
mutex_unlock ( & tpci200 - > mutex ) ;
return 0 ;
}
2012-09-13 14:32:21 +04:00
static int tpci200_request_irq ( struct ipack_device * dev ,
2012-09-12 16:55:38 +04:00
irqreturn_t ( * handler ) ( void * ) , void * arg )
2012-09-12 16:55:37 +04:00
{
int res = 0 ;
struct slot_irq * slot_irq ;
struct tpci200_board * tpci200 ;
tpci200 = check_slot ( dev ) ;
if ( tpci200 = = NULL )
return - EINVAL ;
if ( mutex_lock_interruptible ( & tpci200 - > mutex ) )
return - ERESTARTSYS ;
if ( tpci200 - > slots [ dev - > slot ] . irq ! = NULL ) {
dev_err ( & dev - > dev ,
2012-11-12 00:41:13 +04:00
" Slot [%d:%d] IRQ already registered ! \n " ,
dev - > bus - > bus_nr ,
2012-09-12 16:55:37 +04:00
dev - > slot ) ;
res = - EINVAL ;
goto out_unlock ;
}
slot_irq = kzalloc ( sizeof ( struct slot_irq ) , GFP_KERNEL ) ;
if ( slot_irq = = NULL ) {
dev_err ( & dev - > dev ,
" Slot [%d:%d] unable to allocate memory for IRQ ! \n " ,
2012-09-27 14:37:25 +04:00
dev - > bus - > bus_nr , dev - > slot ) ;
2012-09-12 16:55:37 +04:00
res = - ENOMEM ;
goto out_unlock ;
}
/*
* WARNING : Setup Interrupt Vector in the IndustryPack device
* before an IRQ request .
* Read the User Manual of your IndustryPack device to know
* where to write the vector in memory .
*/
slot_irq - > handler = handler ;
slot_irq - > arg = arg ;
slot_irq - > holder = dev ;
rcu_assign_pointer ( tpci200 - > slots [ dev - > slot ] . irq , slot_irq ) ;
tpci200_enable_irq ( tpci200 , dev - > slot ) ;
out_unlock :
mutex_unlock ( & tpci200 - > mutex ) ;
return res ;
}
2012-05-09 17:27:20 +04:00
static int tpci200_register ( struct tpci200_board * tpci200 )
{
2012-05-23 17:54:40 +04:00
int i ;
2012-05-09 17:27:20 +04:00
int res ;
2012-09-27 14:37:28 +04:00
phys_addr_t ioidint_base ;
2012-05-09 17:27:20 +04:00
unsigned short slot_ctrl ;
if ( pci_enable_device ( tpci200 - > info - > pdev ) < 0 )
return - ENODEV ;
/* Request IP interface register (Bar 2) */
res = pci_request_region ( tpci200 - > info - > pdev , TPCI200_IP_INTERFACE_BAR ,
" Carrier IP interface registers " ) ;
if ( res ) {
2012-05-25 15:08:12 +04:00
dev_err ( & tpci200 - > info - > pdev - > dev ,
" (bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 2 ! " ,
tpci200 - > info - > pdev - > bus - > number ,
tpci200 - > info - > pdev - > devfn ) ;
2012-05-23 17:54:40 +04:00
goto out_disable_pci ;
2012-05-09 17:27:20 +04:00
}
/* Request IO ID INT space (Bar 3) */
res = pci_request_region ( tpci200 - > info - > pdev ,
TPCI200_IO_ID_INT_SPACES_BAR ,
" Carrier IO ID INT space " ) ;
if ( res ) {
2012-05-25 15:08:12 +04:00
dev_err ( & tpci200 - > info - > pdev - > dev ,
" (bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 3 ! " ,
tpci200 - > info - > pdev - > bus - > number ,
tpci200 - > info - > pdev - > devfn ) ;
2012-05-09 17:27:20 +04:00
goto out_release_ip_space ;
}
2012-09-27 14:37:36 +04:00
/* Request MEM8 space (Bar 5) */
2012-05-09 17:27:20 +04:00
res = pci_request_region ( tpci200 - > info - > pdev , TPCI200_MEM8_SPACE_BAR ,
2012-09-27 14:37:36 +04:00
" Carrier MEM8 space " ) ;
2012-05-09 17:27:20 +04:00
if ( res ) {
2012-05-25 15:08:12 +04:00
dev_err ( & tpci200 - > info - > pdev - > dev ,
2012-09-27 14:37:36 +04:00
" (bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 5! " ,
2012-05-25 15:08:12 +04:00
tpci200 - > info - > pdev - > bus - > number ,
tpci200 - > info - > pdev - > devfn ) ;
2012-05-09 17:27:20 +04:00
goto out_release_ioid_int_space ;
}
2012-09-27 14:37:37 +04:00
/* Request MEM16 space (Bar 4) */
res = pci_request_region ( tpci200 - > info - > pdev , TPCI200_MEM16_SPACE_BAR ,
" Carrier MEM16 space " ) ;
if ( res ) {
dev_err ( & tpci200 - > info - > pdev - > dev ,
" (bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 4! " ,
tpci200 - > info - > pdev - > bus - > number ,
tpci200 - > info - > pdev - > devfn ) ;
goto out_release_mem8_space ;
}
2012-05-09 17:27:20 +04:00
/* Map internal tpci200 driver user space */
tpci200 - > info - > interface_regs =
2012-07-20 11:39:05 +04:00
ioremap_nocache ( pci_resource_start ( tpci200 - > info - > pdev ,
2012-05-09 17:27:20 +04:00
TPCI200_IP_INTERFACE_BAR ) ,
TPCI200_IFACE_SIZE ) ;
2012-09-12 16:55:33 +04:00
/* Initialize lock that protects interface_regs */
spin_lock_init ( & tpci200 - > regs_lock ) ;
2012-05-09 17:27:20 +04:00
ioidint_base = pci_resource_start ( tpci200 - > info - > pdev ,
TPCI200_IO_ID_INT_SPACES_BAR ) ;
2012-09-27 14:37:29 +04:00
tpci200 - > mod_mem [ IPACK_IO_SPACE ] = ioidint_base + TPCI200_IO_SPACE_OFF ;
tpci200 - > mod_mem [ IPACK_ID_SPACE ] = ioidint_base + TPCI200_ID_SPACE_OFF ;
tpci200 - > mod_mem [ IPACK_INT_SPACE ] =
ioidint_base + TPCI200_INT_SPACE_OFF ;
2012-09-27 14:37:36 +04:00
tpci200 - > mod_mem [ IPACK_MEM8_SPACE ] =
2012-09-27 14:37:29 +04:00
pci_resource_start ( tpci200 - > info - > pdev ,
2012-09-27 14:37:30 +04:00
TPCI200_MEM8_SPACE_BAR ) ;
2012-09-27 14:37:37 +04:00
tpci200 - > mod_mem [ IPACK_MEM16_SPACE ] =
pci_resource_start ( tpci200 - > info - > pdev ,
TPCI200_MEM16_SPACE_BAR ) ;
2012-05-09 17:27:20 +04:00
/* Set the default parameters of the slot
* INT0 disabled , level sensitive
* INT1 disabled , level sensitive
* error interrupt disabled
* timeout interrupt disabled
* recover time disabled
* clock rate 8 MHz
*/
slot_ctrl = 0 ;
2012-09-27 14:37:35 +04:00
for ( i = 0 ; i < TPCI200_NB_SLOT ; i + + )
2012-09-11 15:34:54 +04:00
writew ( slot_ctrl , & tpci200 - > info - > interface_regs - > control [ i ] ) ;
2012-05-09 17:27:20 +04:00
res = request_irq ( tpci200 - > info - > pdev - > irq ,
tpci200_interrupt , IRQF_SHARED ,
2012-05-18 13:10:07 +04:00
KBUILD_MODNAME , ( void * ) tpci200 ) ;
2012-05-09 17:27:20 +04:00
if ( res ) {
2012-05-25 15:08:12 +04:00
dev_err ( & tpci200 - > info - > pdev - > dev ,
" (bn 0x%X, sn 0x%X) unable to register IRQ ! " ,
tpci200 - > info - > pdev - > bus - > number ,
tpci200 - > info - > pdev - > devfn ) ;
2012-05-23 17:54:40 +04:00
goto out_release_ioid_int_space ;
2012-05-09 17:27:20 +04:00
}
return 0 ;
2012-09-27 14:37:37 +04:00
out_release_mem8_space :
pci_release_region ( tpci200 - > info - > pdev , TPCI200_MEM8_SPACE_BAR ) ;
2012-05-09 17:27:20 +04:00
out_release_ioid_int_space :
pci_release_region ( tpci200 - > info - > pdev , TPCI200_IO_ID_INT_SPACES_BAR ) ;
out_release_ip_space :
pci_release_region ( tpci200 - > info - > pdev , TPCI200_IP_INTERFACE_BAR ) ;
out_disable_pci :
pci_disable_device ( tpci200 - > info - > pdev ) ;
return res ;
}
2012-09-11 15:34:56 +04:00
static int tpci200_get_clockrate ( struct ipack_device * dev )
{
struct tpci200_board * tpci200 = check_slot ( dev ) ;
2012-09-12 16:55:46 +04:00
__le16 __iomem * addr ;
2012-09-11 15:34:56 +04:00
if ( ! tpci200 )
return - ENODEV ;
addr = & tpci200 - > info - > interface_regs - > control [ dev - > slot ] ;
return ( ioread16 ( addr ) & TPCI200_CLK32 ) ? 32 : 8 ;
}
static int tpci200_set_clockrate ( struct ipack_device * dev , int mherz )
{
struct tpci200_board * tpci200 = check_slot ( dev ) ;
2012-09-12 16:55:46 +04:00
__le16 __iomem * addr ;
2012-09-11 15:34:56 +04:00
if ( ! tpci200 )
return - ENODEV ;
addr = & tpci200 - > info - > interface_regs - > control [ dev - > slot ] ;
switch ( mherz ) {
case 8 :
2012-09-12 16:55:23 +04:00
tpci200_clear_mask ( tpci200 , addr , TPCI200_CLK32 ) ;
2012-09-11 15:34:56 +04:00
break ;
case 32 :
2012-09-12 16:55:23 +04:00
tpci200_set_mask ( tpci200 , addr , TPCI200_CLK32 ) ;
2012-09-11 15:34:56 +04:00
break ;
default :
return - EINVAL ;
}
return 0 ;
}
static int tpci200_get_error ( struct ipack_device * dev )
{
struct tpci200_board * tpci200 = check_slot ( dev ) ;
2012-09-12 16:55:46 +04:00
__le16 __iomem * addr ;
2012-09-11 15:34:56 +04:00
u16 mask ;
if ( ! tpci200 )
return - ENODEV ;
addr = & tpci200 - > info - > interface_regs - > status ;
mask = tpci200_status_error [ dev - > slot ] ;
return ( ioread16 ( addr ) & mask ) ? 1 : 0 ;
}
static int tpci200_get_timeout ( struct ipack_device * dev )
{
struct tpci200_board * tpci200 = check_slot ( dev ) ;
2012-09-12 16:55:46 +04:00
__le16 __iomem * addr ;
2012-09-11 15:34:56 +04:00
u16 mask ;
if ( ! tpci200 )
return - ENODEV ;
addr = & tpci200 - > info - > interface_regs - > status ;
mask = tpci200_status_timeout [ dev - > slot ] ;
return ( ioread16 ( addr ) & mask ) ? 1 : 0 ;
}
static int tpci200_reset_timeout ( struct ipack_device * dev )
{
struct tpci200_board * tpci200 = check_slot ( dev ) ;
2012-09-12 16:55:46 +04:00
__le16 __iomem * addr ;
2012-09-11 15:34:56 +04:00
u16 mask ;
if ( ! tpci200 )
return - ENODEV ;
addr = & tpci200 - > info - > interface_regs - > status ;
mask = tpci200_status_timeout [ dev - > slot ] ;
iowrite16 ( mask , addr ) ;
return 0 ;
}
2012-05-09 17:27:20 +04:00
static void tpci200_uninstall ( struct tpci200_board * tpci200 )
{
tpci200_unregister ( tpci200 ) ;
kfree ( tpci200 - > slots ) ;
}
2012-09-10 22:14:01 +04:00
static const struct ipack_bus_ops tpci200_bus_ops = {
2012-05-09 17:27:20 +04:00
. request_irq = tpci200_request_irq ,
. free_irq = tpci200_free_irq ,
2012-09-11 15:34:56 +04:00
. get_clockrate = tpci200_get_clockrate ,
. set_clockrate = tpci200_set_clockrate ,
. get_error = tpci200_get_error ,
. get_timeout = tpci200_get_timeout ,
. reset_timeout = tpci200_reset_timeout ,
2012-05-09 17:27:20 +04:00
} ;
static int tpci200_install ( struct tpci200_board * tpci200 )
{
int res ;
tpci200 - > slots = kzalloc (
TPCI200_NB_SLOT * sizeof ( struct tpci200_slot ) , GFP_KERNEL ) ;
2012-06-07 12:24:54 +04:00
if ( tpci200 - > slots = = NULL )
return - ENOMEM ;
2012-05-09 17:27:20 +04:00
res = tpci200_register ( tpci200 ) ;
2012-06-07 12:24:54 +04:00
if ( res ) {
kfree ( tpci200 - > slots ) ;
tpci200 - > slots = NULL ;
return res ;
}
2012-05-09 17:27:20 +04:00
mutex_init ( & tpci200 - > mutex ) ;
return 0 ;
}
2012-09-27 14:37:26 +04:00
static void tpci200_release_device ( struct ipack_device * dev )
{
kfree ( dev ) ;
}
static int tpci200_create_device ( struct tpci200_board * tpci200 , int i )
{
2013-03-08 12:21:47 +04:00
int ret ;
2012-09-27 14:37:31 +04:00
enum ipack_space space ;
2012-09-27 14:37:26 +04:00
struct ipack_device * dev =
kzalloc ( sizeof ( struct ipack_device ) , GFP_KERNEL ) ;
if ( ! dev )
return - ENOMEM ;
dev - > slot = i ;
dev - > bus = tpci200 - > info - > ipack_bus ;
dev - > release = tpci200_release_device ;
2012-09-27 14:37:31 +04:00
for ( space = 0 ; space < IPACK_SPACE_COUNT ; space + + ) {
dev - > region [ space ] . start =
tpci200 - > mod_mem [ space ]
+ tpci200_space_interval [ space ] * i ;
dev - > region [ space ] . size = tpci200_space_size [ space ] ;
}
2013-03-08 12:21:47 +04:00
ret = ipack_device_init ( dev ) ;
if ( ret < 0 ) {
ipack_put_device ( dev ) ;
return ret ;
}
ret = ipack_device_add ( dev ) ;
if ( ret < 0 )
ipack_put_device ( dev ) ;
return ret ;
2012-09-27 14:37:26 +04:00
}
2012-09-07 19:50:54 +04:00
static int tpci200_pci_probe ( struct pci_dev * pdev ,
const struct pci_device_id * id )
2012-05-09 17:27:20 +04:00
{
2012-05-23 17:54:40 +04:00
int ret , i ;
2012-05-09 17:27:20 +04:00
struct tpci200_board * tpci200 ;
2012-09-11 15:34:56 +04:00
u32 reg32 ;
2012-05-09 17:27:20 +04:00
tpci200 = kzalloc ( sizeof ( struct tpci200_board ) , GFP_KERNEL ) ;
if ( ! tpci200 )
return - ENOMEM ;
tpci200 - > info = kzalloc ( sizeof ( struct tpci200_infos ) , GFP_KERNEL ) ;
if ( ! tpci200 - > info ) {
2012-09-04 19:01:06 +04:00
ret = - ENOMEM ;
goto out_err_info ;
2012-05-09 17:27:20 +04:00
}
2012-09-11 15:35:05 +04:00
pci_dev_get ( pdev ) ;
2012-09-04 19:01:07 +04:00
/* Obtain a mapping of the carrier's PCI configuration registers */
ret = pci_request_region ( pdev , TPCI200_CFG_MEM_BAR ,
KBUILD_MODNAME " Configuration Memory " ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " Failed to allocate PCI Configuration Memory " ) ;
ret = - EBUSY ;
goto out_err_pci_request ;
}
tpci200 - > info - > cfg_regs = ioremap_nocache (
pci_resource_start ( pdev , TPCI200_CFG_MEM_BAR ) ,
pci_resource_len ( pdev , TPCI200_CFG_MEM_BAR ) ) ;
if ( ! tpci200 - > info - > cfg_regs ) {
dev_err ( & pdev - > dev , " Failed to map PCI Configuration Memory " ) ;
ret = - EFAULT ;
goto out_err_ioremap ;
}
/* Disable byte swapping for 16 bit IP module access. This will ensure
* that the Industrypack big endian byte order is preserved by the
* carrier . */
reg32 = ioread32 ( tpci200 - > info - > cfg_regs + LAS1_DESC ) ;
reg32 | = 1 < < LAS_BIT_BIGENDIAN ;
iowrite32 ( reg32 , tpci200 - > info - > cfg_regs + LAS1_DESC ) ;
reg32 = ioread32 ( tpci200 - > info - > cfg_regs + LAS2_DESC ) ;
reg32 | = 1 < < LAS_BIT_BIGENDIAN ;
iowrite32 ( reg32 , tpci200 - > info - > cfg_regs + LAS2_DESC ) ;
2012-05-09 17:27:20 +04:00
/* Save struct pci_dev pointer */
tpci200 - > info - > pdev = pdev ;
tpci200 - > info - > id_table = ( struct pci_device_id * ) id ;
/* register the device and initialize it */
ret = tpci200_install ( tpci200 ) ;
if ( ret ) {
2012-09-04 19:01:06 +04:00
dev_err ( & pdev - > dev , " error during tpci200 install \n " ) ;
ret = - ENODEV ;
goto out_err_install ;
2012-05-09 17:27:20 +04:00
}
2012-05-18 13:10:05 +04:00
/* Register the carrier in the industry pack bus driver */
tpci200 - > info - > ipack_bus = ipack_bus_register ( & pdev - > dev ,
TPCI200_NB_SLOT ,
2014-09-02 19:31:40 +04:00
& tpci200_bus_ops ,
THIS_MODULE ) ;
2012-05-18 13:10:05 +04:00
if ( ! tpci200 - > info - > ipack_bus ) {
2012-05-25 15:08:12 +04:00
dev_err ( & pdev - > dev ,
" error registering the carrier on ipack driver \n " ) ;
2012-09-04 19:01:06 +04:00
ret = - EFAULT ;
goto out_err_bus_register ;
2012-05-09 17:27:20 +04:00
}
2012-05-18 13:10:05 +04:00
2012-05-09 17:27:20 +04:00
/* save the bus number given by ipack to logging purpose */
2012-05-18 13:10:05 +04:00
tpci200 - > number = tpci200 - > info - > ipack_bus - > bus_nr ;
2012-05-09 17:27:20 +04:00
dev_set_drvdata ( & pdev - > dev , tpci200 ) ;
2012-05-23 17:54:40 +04:00
for ( i = 0 ; i < TPCI200_NB_SLOT ; i + + )
2012-09-27 14:37:26 +04:00
tpci200_create_device ( tpci200 , i ) ;
2012-09-04 19:01:06 +04:00
return 0 ;
out_err_bus_register :
tpci200_uninstall ( tpci200 ) ;
out_err_install :
2012-09-04 19:01:07 +04:00
iounmap ( tpci200 - > info - > cfg_regs ) ;
out_err_ioremap :
pci_release_region ( pdev , TPCI200_CFG_MEM_BAR ) ;
out_err_pci_request :
2012-09-11 15:35:05 +04:00
pci_dev_put ( pdev ) ;
2012-09-04 19:01:06 +04:00
kfree ( tpci200 - > info ) ;
out_err_info :
kfree ( tpci200 ) ;
2012-05-09 17:27:20 +04:00
return ret ;
}
static void __tpci200_pci_remove ( struct tpci200_board * tpci200 )
{
2012-05-18 13:10:05 +04:00
ipack_bus_unregister ( tpci200 - > info - > ipack_bus ) ;
2012-09-11 15:35:10 +04:00
tpci200_uninstall ( tpci200 ) ;
2012-09-04 19:01:07 +04:00
2012-05-18 13:10:05 +04:00
kfree ( tpci200 - > info ) ;
2012-05-09 17:27:20 +04:00
kfree ( tpci200 ) ;
}
2012-11-19 22:26:39 +04:00
static void tpci200_pci_remove ( struct pci_dev * dev )
2012-05-09 17:27:20 +04:00
{
2012-07-20 11:39:04 +04:00
struct tpci200_board * tpci200 = pci_get_drvdata ( dev ) ;
2012-05-09 17:27:20 +04:00
2012-07-20 11:39:04 +04:00
__tpci200_pci_remove ( tpci200 ) ;
2012-05-09 17:27:20 +04:00
}
2014-07-18 19:27:12 +04:00
static const struct pci_device_id tpci200_idtable [ ] = {
2012-05-09 17:27:20 +04:00
{ TPCI200_VENDOR_ID , TPCI200_DEVICE_ID , TPCI200_SUBVENDOR_ID ,
TPCI200_SUBDEVICE_ID } ,
{ 0 , } ,
} ;
2012-06-07 12:24:58 +04:00
MODULE_DEVICE_TABLE ( pci , tpci200_idtable ) ;
2012-05-09 17:27:20 +04:00
static struct pci_driver tpci200_pci_drv = {
. name = " tpci200 " ,
. id_table = tpci200_idtable ,
2012-09-07 19:50:54 +04:00
. probe = tpci200_pci_probe ,
2012-11-19 22:21:31 +04:00
. remove = tpci200_pci_remove ,
2012-05-09 17:27:20 +04:00
} ;
2012-10-18 19:18:46 +04:00
module_pci_driver ( tpci200_pci_drv ) ;
2012-05-09 17:27:20 +04:00
MODULE_DESCRIPTION ( " TEWS TPCI-200 device driver " ) ;
MODULE_LICENSE ( " GPL " ) ;