2005-04-17 02:20:36 +04:00
/*
* IEEE 1394 for Linux
*
* Low level ( host adapter ) management .
*
* Copyright ( C ) 1999 Andreas E . Bombe
* Copyright ( C ) 1999 Emanuel Pirker
*
* This code is licensed under the GPL . See the file COPYING in the root
* directory of the kernel sources for details .
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/list.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/timer.h>
2005-09-30 22:59:10 +04:00
# include <linux/jiffies.h>
2006-06-13 02:11:07 +04:00
# include <linux/mutex.h>
2005-04-17 02:20:36 +04:00
# include "csr1212.h"
# include "ieee1394.h"
# include "ieee1394_types.h"
# include "hosts.h"
# include "ieee1394_core.h"
# include "highlevel.h"
# include "nodemgr.h"
# include "csr.h"
# include "config_roms.h"
2006-11-22 17:57:56 +03:00
static void delayed_reset_bus ( struct work_struct * work )
2005-04-17 02:20:36 +04:00
{
2006-11-22 17:57:56 +03:00
struct hpsb_host * host =
container_of ( work , struct hpsb_host , delayed_reset . work ) ;
2008-12-14 02:02:21 +03:00
u8 generation = host - > csr . generation + 1 ;
2005-04-17 02:20:36 +04:00
/* The generation field rolls over to 2 rather than 0 per IEEE
* 1394 a - 2000. */
if ( generation > 0xf | | generation < 2 )
generation = 2 ;
2008-12-14 02:02:21 +03:00
csr_set_bus_info_generation ( host - > csr . rom , generation ) ;
2005-04-17 02:20:36 +04:00
if ( csr1212_generate_csr_image ( host - > csr . rom ) ! = CSR1212_SUCCESS ) {
2006-10-10 23:12:39 +04:00
/* CSR image creation failed.
* Reset generation field and do not issue a bus reset . */
2008-12-14 02:02:21 +03:00
csr_set_bus_info_generation ( host - > csr . rom ,
2006-10-10 23:12:39 +04:00
host - > csr . generation ) ;
2005-04-17 02:20:36 +04:00
return ;
}
host - > csr . generation = generation ;
host - > update_config_rom = 0 ;
if ( host - > driver - > set_hw_config_rom )
2006-10-10 23:12:39 +04:00
host - > driver - > set_hw_config_rom ( host ,
host - > csr . rom - > bus_info_data ) ;
2005-04-17 02:20:36 +04:00
host - > csr . gen_timestamp [ host - > csr . generation ] = jiffies ;
hpsb_reset_bus ( host , SHORT_RESET ) ;
}
static int dummy_transmit_packet ( struct hpsb_host * h , struct hpsb_packet * p )
{
2005-12-02 02:52:03 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int dummy_devctl ( struct hpsb_host * h , enum devctl_cmd c , int arg )
{
2005-12-02 02:52:03 +03:00
return - 1 ;
2005-04-17 02:20:36 +04:00
}
2006-10-10 23:12:39 +04:00
static int dummy_isoctl ( struct hpsb_iso * iso , enum isoctl_cmd command ,
unsigned long arg )
2005-04-17 02:20:36 +04:00
{
return - 1 ;
}
static struct hpsb_host_driver dummy_driver = {
2005-12-02 02:52:03 +03:00
. transmit_packet = dummy_transmit_packet ,
. devctl = dummy_devctl ,
. isoctl = dummy_isoctl
2005-04-17 02:20:36 +04:00
} ;
static int alloc_hostnum_cb ( struct hpsb_host * host , void * __data )
{
int * hostnum = __data ;
if ( host - > id = = * hostnum )
return 1 ;
return 0 ;
}
2006-07-03 20:02:37 +04:00
static DEFINE_MUTEX ( host_num_alloc ) ;
2005-04-17 02:20:36 +04:00
/**
* hpsb_alloc_host - allocate a new host controller .
* @ drv : the driver that will manage the host controller
* @ extra : number of extra bytes to allocate for the driver
*
* Allocate a & hpsb_host and initialize the general subsystem specific
* fields . If the driver needs to store per host data , as drivers
* usually do , the amount of memory required can be specified by the
* @ extra parameter . Once allocated , the driver should initialize the
* driver specific parts , enable the controller and make it available
* to the general subsystem using hpsb_add_host ( ) .
*
2006-06-26 20:35:02 +04:00
* Return Value : a pointer to the & hpsb_host if successful , % NULL if
2005-04-17 02:20:36 +04:00
* no memory was available .
*/
struct hpsb_host * hpsb_alloc_host ( struct hpsb_host_driver * drv , size_t extra ,
struct device * dev )
{
2005-12-02 02:52:03 +03:00
struct hpsb_host * h ;
2005-04-17 02:20:36 +04:00
int i ;
int hostnum = 0 ;
2006-12-07 07:33:17 +03:00
h = kzalloc ( sizeof ( * h ) + extra , GFP_KERNEL ) ;
2005-12-02 02:52:03 +03:00
if ( ! h )
2005-11-07 14:31:45 +03:00
return NULL ;
2005-04-17 02:20:36 +04:00
h - > csr . rom = csr1212_create_csr ( & csr_bus_ops , CSR_BUS_INFO_SIZE , h ) ;
2006-10-10 23:19:21 +04:00
if ( ! h - > csr . rom )
goto fail ;
2005-04-17 02:20:36 +04:00
h - > hostdata = h + 1 ;
2005-12-02 02:52:03 +03:00
h - > driver = drv ;
2005-04-17 02:20:36 +04:00
2007-03-26 00:22:40 +04:00
INIT_LIST_HEAD ( & h - > pending_packets ) ;
2005-04-17 02:20:36 +04:00
INIT_LIST_HEAD ( & h - > addr_space ) ;
for ( i = 2 ; i < 16 ; i + + )
h - > csr . gen_timestamp [ i ] = jiffies - 60 * HZ ;
atomic_set ( & h - > generation , 0 ) ;
2006-11-22 17:57:56 +03:00
INIT_DELAYED_WORK ( & h - > delayed_reset , delayed_reset_bus ) ;
2005-04-17 02:20:36 +04:00
init_timer ( & h - > timeout ) ;
h - > timeout . data = ( unsigned long ) h ;
h - > timeout . function = abort_timedouts ;
2006-10-10 23:12:39 +04:00
h - > timeout_interval = HZ / 20 ; /* 50ms, half of minimum SPLIT_TIMEOUT */
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
h - > topology_map = h - > csr . topology_map + 3 ;
h - > speed_map = ( u8 * ) ( h - > csr . speed_map + 2 ) ;
2005-04-17 02:20:36 +04:00
2006-06-13 02:11:07 +04:00
mutex_lock ( & host_num_alloc ) ;
2005-04-17 02:20:36 +04:00
while ( nodemgr_for_each_host ( & hostnum , alloc_hostnum_cb ) )
hostnum + + ;
2006-10-10 23:11:43 +04:00
mutex_unlock ( & host_num_alloc ) ;
2005-04-17 02:20:36 +04:00
h - > id = hostnum ;
memcpy ( & h - > device , & nodemgr_dev_template_host , sizeof ( h - > device ) ) ;
h - > device . parent = dev ;
2007-07-08 15:34:21 +04:00
set_dev_node ( & h - > device , dev_to_node ( dev ) ) ;
2008-10-30 03:49:20 +03:00
dev_set_name ( & h - > device , " fw-host%d " , h - > id ) ;
2005-04-17 02:20:36 +04:00
2007-05-25 13:50:53 +04:00
h - > host_dev . parent = & h - > device ;
h - > host_dev . class = & hpsb_host_class ;
2008-10-30 03:49:20 +03:00
dev_set_name ( & h - > host_dev , " fw-host%d " , h - > id ) ;
2005-04-17 02:20:36 +04:00
2006-10-10 23:19:21 +04:00
if ( device_register ( & h - > device ) )
goto fail ;
2007-05-25 13:50:53 +04:00
if ( device_register ( & h - > host_dev ) ) {
2006-10-10 23:19:21 +04:00
device_unregister ( & h - > device ) ;
goto fail ;
}
2005-04-17 02:20:36 +04:00
get_device ( & h - > device ) ;
return h ;
2006-10-10 23:19:21 +04:00
fail :
kfree ( h ) ;
return NULL ;
2005-04-17 02:20:36 +04:00
}
int hpsb_add_host ( struct hpsb_host * host )
{
if ( hpsb_default_host_entry ( host ) )
return - ENOMEM ;
2007-03-27 03:36:50 +04:00
2005-04-17 02:20:36 +04:00
highlevel_add_host ( host ) ;
return 0 ;
}
2007-01-07 23:49:27 +03:00
void hpsb_resume_host ( struct hpsb_host * host )
{
if ( host - > driver - > set_hw_config_rom )
host - > driver - > set_hw_config_rom ( host ,
host - > csr . rom - > bus_info_data ) ;
host - > driver - > devctl ( host , RESET_BUS , SHORT_RESET ) ;
}
2005-04-17 02:20:36 +04:00
void hpsb_remove_host ( struct hpsb_host * host )
{
2005-12-02 02:52:03 +03:00
host - > is_shutdown = 1 ;
2005-04-17 02:20:36 +04:00
cancel_delayed_work ( & host - > delayed_reset ) ;
flush_scheduled_work ( ) ;
2005-12-02 02:52:03 +03:00
host - > driver = & dummy_driver ;
highlevel_remove_host ( host ) ;
2005-04-17 02:20:36 +04:00
2007-05-25 13:50:53 +04:00
device_unregister ( & host - > host_dev ) ;
2005-04-17 02:20:36 +04:00
device_unregister ( & host - > device ) ;
}
2007-03-05 05:06:23 +03:00
/**
* hpsb_update_config_rom_image - updates configuration ROM image of a host
*
* Updates the configuration ROM image of a host . rom_version must be the
* current version , otherwise it will fail with return value - 1. If this
* host does not support config - rom - update , it will return - % EINVAL .
* Return value 0 indicates success .
*/
2005-04-17 02:20:36 +04:00
int hpsb_update_config_rom_image ( struct hpsb_host * host )
{
unsigned long reset_delay ;
int next_gen = host - > csr . generation + 1 ;
if ( ! host - > update_config_rom )
return - EINVAL ;
if ( next_gen > 0xf )
next_gen = 2 ;
/* Stop the delayed interrupt, we're about to change the config rom and
* it would be a waste to do a bus reset twice . */
cancel_delayed_work ( & host - > delayed_reset ) ;
/* IEEE 1394a-2000 prohibits using the same generation number
* twice in a 60 second period . */
2005-09-30 22:59:10 +04:00
if ( time_before ( jiffies , host - > csr . gen_timestamp [ next_gen ] + 60 * HZ ) )
2005-04-17 02:20:36 +04:00
/* Wait 60 seconds from the last time this generation number was
* used . */
2006-10-10 23:12:39 +04:00
reset_delay =
( 60 * HZ ) + host - > csr . gen_timestamp [ next_gen ] - jiffies ;
2005-04-17 02:20:36 +04:00
else
/* Wait 1 second in case some other code wants to change the
* Config ROM in the near future . */
reset_delay = HZ ;
2006-11-22 17:57:56 +03:00
PREPARE_DELAYED_WORK ( & host - > delayed_reset , delayed_reset_bus ) ;
2005-04-17 02:20:36 +04:00
schedule_delayed_work ( & host - > delayed_reset , reset_delay ) ;
return 0 ;
}