2005-04-17 02:20:36 +04:00
/*
* IEEE 1394 for Linux
*
* Core support : hpsb_packet management , packet handling and forwarding to
* highlevel or lowlevel code
*
* Copyright ( C ) 1999 , 2000 Andreas E . Bombe
* 2002 Manfred Weihs < weihs @ ict . tuwien . ac . at >
*
* This code is licensed under the GPL . See the file COPYING in the root
* directory of the kernel sources for details .
*
*
* Contributions :
*
* Manfred Weihs < weihs @ ict . tuwien . ac . at >
* loopback functionality in hpsb_send_packet
* allow highlevel drivers to disable automatic response generation
* and to generate responses themselves ( deferred )
*
*/
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/string.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/interrupt.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/bitops.h>
# include <linux/kdev_t.h>
2007-07-17 15:03:35 +04:00
# include <linux/freezer.h>
2005-04-17 02:20:36 +04:00
# include <linux/suspend.h>
2006-06-13 02:15:50 +04:00
# include <linux/kthread.h>
2007-02-03 19:44:39 +03:00
# include <linux/preempt.h>
# include <linux/time.h>
2005-04-17 02:20:36 +04:00
2007-02-03 19:44:39 +03:00
# include <asm/system.h>
2005-04-17 02:20:36 +04:00
# include <asm/byteorder.h>
# include "ieee1394_types.h"
# include "ieee1394.h"
# include "hosts.h"
# include "ieee1394_core.h"
# include "highlevel.h"
# include "ieee1394_transactions.h"
# include "csr.h"
# include "nodemgr.h"
# include "dma.h"
# include "iso.h"
# include "config_roms.h"
/*
* Disable the nodemgr detection and config rom reading functionality .
*/
2005-07-10 04:01:23 +04:00
static int disable_nodemgr ;
2005-04-17 02:20:36 +04:00
module_param ( disable_nodemgr , int , 0444 ) ;
MODULE_PARM_DESC ( disable_nodemgr , " Disable nodemgr functionality. " ) ;
/* Disable Isochronous Resource Manager functionality */
int hpsb_disable_irm = 0 ;
2006-03-29 05:03:34 +04:00
module_param_named ( disable_irm , hpsb_disable_irm , bool , 0444 ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( disable_irm ,
" Disable Isochronous Resource Manager functionality. " ) ;
/* We are GPL, so treat us special */
MODULE_LICENSE ( " GPL " ) ;
/* Some globals used */
const char * hpsb_speedto_str [ ] = { " S100 " , " S200 " , " S400 " , " S800 " , " S1600 " , " S3200 " } ;
2005-03-23 20:53:36 +03:00
struct class * hpsb_protocol_class ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_IEEE1394_VERBOSEDEBUG
2005-09-30 22:59:09 +04:00
static void dump_packet ( const char * text , quadlet_t * data , int size , int speed )
2005-04-17 02:20:36 +04:00
{
int i ;
size / = 4 ;
size = ( size > 4 ? 4 : size ) ;
printk ( KERN_DEBUG " ieee1394: %s " , text ) ;
2005-09-30 22:59:09 +04:00
if ( speed > - 1 & & speed < 6 )
printk ( " at %s " , hpsb_speedto_str [ speed ] ) ;
printk ( " : " ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < size ; i + + )
printk ( " %08x " , data [ i ] ) ;
printk ( " \n " ) ;
}
# else
2006-08-02 20:44:00 +04:00
# define dump_packet(a,b,c,d) do {} while (0)
2005-04-17 02:20:36 +04:00
# endif
static void abort_requests ( struct hpsb_host * host ) ;
static void queue_packet_complete ( struct hpsb_packet * packet ) ;
/**
2007-03-05 05:06:23 +03:00
* hpsb_set_packet_complete_task - set task that runs when a packet completes
2005-04-17 02:20:36 +04:00
* @ packet : the packet whose completion we want the task added to
* @ routine : function to call
* @ data : data ( if any ) to pass to the above function
2007-03-05 05:06:23 +03:00
*
* Set the task that runs when a packet completes . You cannot call this more
* than once on a single packet before it is sent .
2007-03-26 00:22:40 +04:00
*
* Typically , the complete @ routine is responsible to call hpsb_free_packet ( ) .
2005-04-17 02:20:36 +04:00
*/
void hpsb_set_packet_complete_task ( struct hpsb_packet * packet ,
void ( * routine ) ( void * ) , void * data )
{
WARN_ON ( packet - > complete_routine ! = NULL ) ;
packet - > complete_routine = routine ;
packet - > complete_data = data ;
return ;
}
/**
* hpsb_alloc_packet - allocate new packet structure
2007-03-26 00:22:40 +04:00
* @ data_size : size of the data block to be allocated , in bytes
2005-04-17 02:20:36 +04:00
*
* This function allocates , initializes and returns a new & struct hpsb_packet .
2007-03-26 00:22:40 +04:00
* It can be used in interrupt context . A header block is always included and
* initialized with zeros . Its size is big enough to contain all possible 1394
* headers . The data block is only allocated if @ data_size is not zero .
2005-04-17 02:20:36 +04:00
*
* For packets for which responses will be received the @ data_size has to be big
* enough to contain the response ' s data block since no further allocation
* occurs at response matching time .
*
* The packet ' s generation value will be set to the current generation number
* for ease of use . Remember to overwrite it with your own recorded generation
* number if you can not be sure that your code will not race with a bus reset .
*
* Return value : A pointer to a & struct hpsb_packet or NULL on allocation
* failure .
*/
struct hpsb_packet * hpsb_alloc_packet ( size_t data_size )
{
2007-03-26 00:22:40 +04:00
struct hpsb_packet * packet ;
2005-04-17 02:20:36 +04:00
data_size = ( ( data_size + 3 ) & ~ 3 ) ;
2007-03-26 00:22:40 +04:00
packet = kzalloc ( sizeof ( * packet ) + data_size , GFP_ATOMIC ) ;
if ( ! packet )
2005-04-17 02:20:36 +04:00
return NULL ;
packet - > state = hpsb_unused ;
packet - > generation = - 1 ;
INIT_LIST_HEAD ( & packet - > driver_list ) ;
2007-03-26 00:22:40 +04:00
INIT_LIST_HEAD ( & packet - > queue ) ;
2005-04-17 02:20:36 +04:00
atomic_set ( & packet - > refcnt , 1 ) ;
if ( data_size ) {
2007-03-26 00:22:40 +04:00
packet - > data = packet - > embedded_data ;
packet - > allocated_data_size = data_size ;
2005-04-17 02:20:36 +04:00
}
return packet ;
}
/**
* hpsb_free_packet - free packet and data associated with it
* @ packet : packet to free ( is NULL safe )
*
2007-03-26 00:22:40 +04:00
* Frees @ packet - > data only if it was allocated through hpsb_alloc_packet ( ) .
2005-04-17 02:20:36 +04:00
*/
void hpsb_free_packet ( struct hpsb_packet * packet )
{
if ( packet & & atomic_dec_and_test ( & packet - > refcnt ) ) {
2007-03-26 00:22:40 +04:00
BUG_ON ( ! list_empty ( & packet - > driver_list ) | |
! list_empty ( & packet - > queue ) ) ;
kfree ( packet ) ;
2005-04-17 02:20:36 +04:00
}
}
2007-03-05 05:06:23 +03:00
/**
* hpsb_reset_bus - initiate bus reset on the given host
* @ host : host controller whose bus to reset
* @ type : one of enum reset_types
*
* Returns 1 if bus reset already in progress , 0 otherwise .
*/
2005-04-17 02:20:36 +04:00
int hpsb_reset_bus ( struct hpsb_host * host , int type )
{
2005-12-02 02:52:03 +03:00
if ( ! host - > in_bus_reset ) {
host - > driver - > devctl ( host , RESET_BUS , type ) ;
return 0 ;
} else {
return 1 ;
}
2005-04-17 02:20:36 +04:00
}
2007-02-03 19:44:39 +03:00
/**
* hpsb_read_cycle_timer - read cycle timer register and system time
* @ host : host whose isochronous cycle timer register is read
* @ cycle_timer : address of bitfield to return the register contents
* @ local_time : address to return the system time
*
* The format of * @ cycle_timer , is described in OHCI 1.1 clause 5.13 . This
* format is also read from non - OHCI controllers . * @ local_time contains the
* system time in microseconds since the Epoch , read at the moment when the
* cycle timer was read .
*
* Return value : 0 for success or error number otherwise .
*/
int hpsb_read_cycle_timer ( struct hpsb_host * host , u32 * cycle_timer ,
u64 * local_time )
{
int ctr ;
struct timeval tv ;
unsigned long flags ;
if ( ! host | | ! cycle_timer | | ! local_time )
return - EINVAL ;
preempt_disable ( ) ;
local_irq_save ( flags ) ;
ctr = host - > driver - > devctl ( host , GET_CYCLE_COUNTER , 0 ) ;
if ( ctr )
do_gettimeofday ( & tv ) ;
local_irq_restore ( flags ) ;
preempt_enable ( ) ;
if ( ! ctr )
return - EIO ;
* cycle_timer = ctr ;
* local_time = tv . tv_sec * 1000000ULL + tv . tv_usec ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
2007-03-05 05:06:23 +03:00
/**
* hpsb_bus_reset - notify a bus reset to the core
*
* For host driver module usage . Safe to use in interrupt context , although
* quite complex ; so you may want to run it in the bottom rather than top half .
*
* Returns 1 if bus reset already in progress , 0 otherwise .
*/
2005-04-17 02:20:36 +04:00
int hpsb_bus_reset ( struct hpsb_host * host )
{
2005-12-02 02:52:03 +03:00
if ( host - > in_bus_reset ) {
HPSB_NOTICE ( " %s called while bus reset already in progress " ,
2005-04-17 02:20:36 +04:00
__FUNCTION__ ) ;
2005-12-02 02:52:03 +03:00
return 1 ;
}
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
abort_requests ( host ) ;
host - > in_bus_reset = 1 ;
host - > irm_id = - 1 ;
2005-04-17 02:20:36 +04:00
host - > is_irm = 0 ;
2005-12-02 02:52:03 +03:00
host - > busmgr_id = - 1 ;
2005-04-17 02:20:36 +04:00
host - > is_busmgr = 0 ;
host - > is_cycmst = 0 ;
2005-12-02 02:52:03 +03:00
host - > node_count = 0 ;
host - > selfid_count = 0 ;
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/*
* Verify num_of_selfids SelfIDs and return number of nodes . Return zero in
* case verification failed .
*/
static int check_selfids ( struct hpsb_host * host )
{
2005-12-02 02:52:03 +03:00
int nodeid = - 1 ;
int rest_of_selfids = host - > selfid_count ;
struct selfid * sid = ( struct selfid * ) host - > topology_map ;
struct ext_selfid * esid ;
int esid_seq = 23 ;
2005-04-17 02:20:36 +04:00
host - > nodes_active = 0 ;
2005-12-02 02:52:03 +03:00
while ( rest_of_selfids - - ) {
if ( ! sid - > extended ) {
nodeid + + ;
esid_seq = 0 ;
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
if ( sid - > phy_id ! = nodeid ) {
HPSB_INFO ( " SelfIDs failed monotony check with "
" %d " , sid - > phy_id ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
if ( sid - > link_active ) {
host - > nodes_active + + ;
if ( sid - > contender )
host - > irm_id = LOCAL_BUS | sid - > phy_id ;
}
2005-12-02 02:52:03 +03:00
} else {
esid = ( struct ext_selfid * ) sid ;
if ( ( esid - > phy_id ! = nodeid )
| | ( esid - > seq_nr ! = esid_seq ) ) {
HPSB_INFO ( " SelfIDs failed monotony check with "
" %d/%d " , esid - > phy_id , esid - > seq_nr ) ;
return 0 ;
}
esid_seq + + ;
}
sid + + ;
}
esid = ( struct ext_selfid * ) ( sid - 1 ) ;
while ( esid - > extended ) {
if ( ( esid - > porta = = SELFID_PORT_PARENT ) | |
2005-12-02 02:51:56 +03:00
( esid - > portb = = SELFID_PORT_PARENT ) | |
( esid - > portc = = SELFID_PORT_PARENT ) | |
( esid - > portd = = SELFID_PORT_PARENT ) | |
( esid - > porte = = SELFID_PORT_PARENT ) | |
( esid - > portf = = SELFID_PORT_PARENT ) | |
( esid - > portg = = SELFID_PORT_PARENT ) | |
( esid - > porth = = SELFID_PORT_PARENT ) ) {
2005-04-17 02:20:36 +04:00
HPSB_INFO ( " SelfIDs failed root check on "
" extended SelfID " ) ;
return 0 ;
2005-12-02 02:52:03 +03:00
}
esid - - ;
}
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
sid = ( struct selfid * ) esid ;
2005-12-02 02:51:56 +03:00
if ( ( sid - > port0 = = SELFID_PORT_PARENT ) | |
( sid - > port1 = = SELFID_PORT_PARENT ) | |
( sid - > port2 = = SELFID_PORT_PARENT ) ) {
2005-04-17 02:20:36 +04:00
HPSB_INFO ( " SelfIDs failed root check " ) ;
return 0 ;
2005-12-02 02:52:03 +03:00
}
2005-04-17 02:20:36 +04:00
host - > node_count = nodeid + 1 ;
2005-12-02 02:52:03 +03:00
return 1 ;
2005-04-17 02:20:36 +04:00
}
static void build_speed_map ( struct hpsb_host * host , int nodecount )
{
u8 cldcnt [ nodecount ] ;
2005-12-02 02:52:03 +03:00
u8 * map = host - > speed_map ;
2006-06-13 02:12:37 +04:00
u8 * speedcap = host - > speed ;
2005-12-02 02:52:03 +03:00
struct selfid * sid ;
struct ext_selfid * esid ;
int i , j , n ;
for ( i = 0 ; i < ( nodecount * 64 ) ; i + = 64 ) {
for ( j = 0 ; j < nodecount ; j + + ) {
map [ i + j ] = IEEE1394_SPEED_MAX ;
}
}
for ( i = 0 ; i < nodecount ; i + + ) {
cldcnt [ i ] = 0 ;
}
/* find direct children count and speed */
for ( sid = ( struct selfid * ) & host - > topology_map [ host - > selfid_count - 1 ] ,
n = nodecount - 1 ;
( void * ) sid > = ( void * ) host - > topology_map ; sid - - ) {
if ( sid - > extended ) {
esid = ( struct ext_selfid * ) sid ;
2005-04-17 02:20:36 +04:00
2005-12-02 02:51:56 +03:00
if ( esid - > porta = = SELFID_PORT_CHILD ) cldcnt [ n ] + + ;
if ( esid - > portb = = SELFID_PORT_CHILD ) cldcnt [ n ] + + ;
if ( esid - > portc = = SELFID_PORT_CHILD ) cldcnt [ n ] + + ;
if ( esid - > portd = = SELFID_PORT_CHILD ) cldcnt [ n ] + + ;
if ( esid - > porte = = SELFID_PORT_CHILD ) cldcnt [ n ] + + ;
if ( esid - > portf = = SELFID_PORT_CHILD ) cldcnt [ n ] + + ;
if ( esid - > portg = = SELFID_PORT_CHILD ) cldcnt [ n ] + + ;
if ( esid - > porth = = SELFID_PORT_CHILD ) cldcnt [ n ] + + ;
2005-04-17 02:20:36 +04:00
} else {
2005-12-02 02:51:56 +03:00
if ( sid - > port0 = = SELFID_PORT_CHILD ) cldcnt [ n ] + + ;
if ( sid - > port1 = = SELFID_PORT_CHILD ) cldcnt [ n ] + + ;
if ( sid - > port2 = = SELFID_PORT_CHILD ) cldcnt [ n ] + + ;
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
speedcap [ n ] = sid - > speed ;
n - - ;
}
}
/* set self mapping */
for ( i = 0 ; i < nodecount ; i + + ) {
map [ 64 * i + i ] = speedcap [ i ] ;
}
/* fix up direct children count to total children count;
* also fix up speedcaps for sibling and parent communication */
for ( i = 1 ; i < nodecount ; i + + ) {
for ( j = cldcnt [ i ] , n = i - 1 ; j > 0 ; j - - ) {
cldcnt [ i ] + = cldcnt [ n ] ;
speedcap [ n ] = min ( speedcap [ n ] , speedcap [ i ] ) ;
n - = cldcnt [ n ] + 1 ;
}
}
for ( n = 0 ; n < nodecount ; n + + ) {
for ( i = n - cldcnt [ n ] ; i < = n ; i + + ) {
for ( j = 0 ; j < ( n - cldcnt [ n ] ) ; j + + ) {
map [ j * 64 + i ] = map [ i * 64 + j ] =
min ( map [ i * 64 + j ] , speedcap [ n ] ) ;
}
for ( j = n + 1 ; j < nodecount ; j + + ) {
map [ j * 64 + i ] = map [ i * 64 + j ] =
min ( map [ i * 64 + j ] , speedcap [ n ] ) ;
}
}
}
2006-06-13 02:12:37 +04:00
2006-07-03 20:02:27 +04:00
# if SELFID_SPEED_UNKNOWN != IEEE1394_SPEED_MAX
2006-06-13 02:12:37 +04:00
/* assume maximum speed for 1394b PHYs, nodemgr will correct it */
for ( n = 0 ; n < nodecount ; n + + )
2006-07-03 20:02:27 +04:00
if ( speedcap [ n ] = = SELFID_SPEED_UNKNOWN )
2006-06-13 02:12:37 +04:00
speedcap [ n ] = IEEE1394_SPEED_MAX ;
2006-07-03 20:02:27 +04:00
# endif
2005-04-17 02:20:36 +04:00
}
2007-03-05 05:06:23 +03:00
/**
* hpsb_selfid_received - hand over received selfid packet to the core
*
* For host driver module usage . Safe to use in interrupt context .
*
* The host driver should have done a successful complement check ( second
* quadlet is complement of first ) beforehand .
*/
2005-04-17 02:20:36 +04:00
void hpsb_selfid_received ( struct hpsb_host * host , quadlet_t sid )
{
2005-12-02 02:52:03 +03:00
if ( host - > in_bus_reset ) {
HPSB_VERBOSE ( " Including SelfID 0x%x " , sid ) ;
host - > topology_map [ host - > selfid_count + + ] = sid ;
} else {
HPSB_NOTICE ( " Spurious SelfID packet (0x%08x) received from bus %d " ,
2005-04-17 02:20:36 +04:00
sid , NODEID_TO_BUS ( host - > node_id ) ) ;
2005-12-02 02:52:03 +03:00
}
2005-04-17 02:20:36 +04:00
}
2007-03-05 05:06:23 +03:00
/**
* hpsb_selfid_complete - notify completion of SelfID stage to the core
*
* For host driver module usage . Safe to use in interrupt context , although
* quite complex ; so you may want to run it in the bottom rather than top half .
*
* Notify completion of SelfID stage to the core and report new physical ID
* and whether host is root now .
*/
2005-04-17 02:20:36 +04:00
void hpsb_selfid_complete ( struct hpsb_host * host , int phyid , int isroot )
{
if ( ! host - > in_bus_reset )
HPSB_NOTICE ( " SelfID completion called outside of bus reset! " ) ;
2005-12-02 02:52:03 +03:00
host - > node_id = LOCAL_BUS | phyid ;
host - > is_root = isroot ;
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
if ( ! check_selfids ( host ) ) {
if ( host - > reset_retries + + < 20 ) {
/* selfid stage did not complete without error */
HPSB_NOTICE ( " Error in SelfID stage, resetting " ) ;
2005-04-17 02:20:36 +04:00
host - > in_bus_reset = 0 ;
/* this should work from ohci1394 now... */
2005-12-02 02:52:03 +03:00
hpsb_reset_bus ( host , LONG_RESET ) ;
return ;
} else {
HPSB_NOTICE ( " Stopping out-of-control reset loop " ) ;
HPSB_NOTICE ( " Warning - topology map and speed map will not be valid " ) ;
2005-04-17 02:20:36 +04:00
host - > reset_retries = 0 ;
2005-12-02 02:52:03 +03:00
}
} else {
2005-04-17 02:20:36 +04:00
host - > reset_retries = 0 ;
2005-12-02 02:52:03 +03:00
build_speed_map ( host , host - > node_count ) ;
}
2005-04-17 02:20:36 +04:00
HPSB_VERBOSE ( " selfid_complete called with successful SelfID stage "
" ... irm_id: 0x%X node_id: 0x%X " , host - > irm_id , host - > node_id ) ;
2005-12-02 02:52:03 +03:00
/* irm_id is kept up to date by check_selfids() */
if ( host - > irm_id = = host - > node_id ) {
host - > is_irm = 1 ;
} else {
host - > is_busmgr = 0 ;
host - > is_irm = 0 ;
}
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
if ( isroot ) {
2005-04-17 02:20:36 +04:00
host - > driver - > devctl ( host , ACT_CYCLE_MASTER , 1 ) ;
host - > is_cycmst = 1 ;
}
atomic_inc ( & host - > generation ) ;
host - > in_bus_reset = 0 ;
2005-12-02 02:52:03 +03:00
highlevel_host_reset ( host ) ;
2005-04-17 02:20:36 +04:00
}
2007-03-26 00:22:40 +04:00
static spinlock_t pending_packets_lock = SPIN_LOCK_UNLOCKED ;
2007-03-05 05:06:23 +03:00
/**
* hpsb_packet_sent - notify core of sending a packet
*
* For host driver module usage . Safe to call from within a transmit packet
* routine .
*
* Notify core of sending a packet . Ackcode is the ack code returned for async
* transmits or ACKX_SEND_ERROR if the transmission failed completely ; ACKX_NONE
* for other cases ( internal errors that don ' t justify a panic ) .
*/
2005-04-17 02:20:36 +04:00
void hpsb_packet_sent ( struct hpsb_host * host , struct hpsb_packet * packet ,
2005-12-02 02:52:03 +03:00
int ackcode )
2005-04-17 02:20:36 +04:00
{
unsigned long flags ;
2007-03-26 00:22:40 +04:00
spin_lock_irqsave ( & pending_packets_lock , flags ) ;
2005-04-17 02:20:36 +04:00
packet - > ack_code = ackcode ;
if ( packet - > no_waiter | | packet - > state = = hpsb_complete ) {
/* if packet->no_waiter, must not have a tlabel allocated */
2007-03-26 00:22:40 +04:00
spin_unlock_irqrestore ( & pending_packets_lock , flags ) ;
2005-04-17 02:20:36 +04:00
hpsb_free_packet ( packet ) ;
return ;
}
atomic_dec ( & packet - > refcnt ) ; /* drop HC's reference */
2007-03-26 00:22:40 +04:00
/* here the packet must be on the host->pending_packets queue */
2005-04-17 02:20:36 +04:00
if ( ackcode ! = ACK_PENDING | | ! packet - > expect_response ) {
packet - > state = hpsb_complete ;
2007-03-26 00:22:40 +04:00
list_del_init ( & packet - > queue ) ;
spin_unlock_irqrestore ( & pending_packets_lock , flags ) ;
2005-04-17 02:20:36 +04:00
queue_packet_complete ( packet ) ;
return ;
}
packet - > state = hpsb_pending ;
packet - > sendtime = jiffies ;
2007-03-26 00:22:40 +04:00
spin_unlock_irqrestore ( & pending_packets_lock , flags ) ;
2005-04-17 02:20:36 +04:00
mod_timer ( & host - > timeout , jiffies + host - > timeout_interval ) ;
}
/**
* hpsb_send_phy_config - transmit a PHY configuration packet on the bus
* @ host : host that PHY config packet gets sent through
* @ rootid : root whose force_root bit should get set ( - 1 = don ' t set force_root )
* @ gapcnt : gap count value to set ( - 1 = don ' t set gap count )
*
2007-03-05 05:06:23 +03:00
* This function sends a PHY config packet on the bus through the specified
* host .
2005-04-17 02:20:36 +04:00
*
2007-03-05 05:06:23 +03:00
* Return value : 0 for success or negative error number otherwise .
2005-04-17 02:20:36 +04:00
*/
int hpsb_send_phy_config ( struct hpsb_host * host , int rootid , int gapcnt )
{
struct hpsb_packet * packet ;
2005-12-02 02:52:01 +03:00
quadlet_t d = 0 ;
2005-04-17 02:20:36 +04:00
int retval = 0 ;
if ( rootid > = ALL_NODES | | rootid < - 1 | | gapcnt > 0x3f | | gapcnt < - 1 | |
( rootid = = - 1 & & gapcnt = = - 1 ) ) {
HPSB_DEBUG ( " Invalid Parameter: rootid = %d gapcnt = %d " ,
rootid , gapcnt ) ;
return - EINVAL ;
}
if ( rootid ! = - 1 )
2005-12-02 02:52:01 +03:00
d | = PHYPACKET_PHYCONFIG_R | rootid < < PHYPACKET_PORT_SHIFT ;
2005-04-17 02:20:36 +04:00
if ( gapcnt ! = - 1 )
2005-12-02 02:52:01 +03:00
d | = PHYPACKET_PHYCONFIG_T | gapcnt < < PHYPACKET_GAPCOUNT_SHIFT ;
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:01 +03:00
packet = hpsb_make_phypacket ( host , d ) ;
if ( ! packet )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
packet - > generation = get_hpsb_generation ( host ) ;
retval = hpsb_send_packet_and_wait ( packet ) ;
hpsb_free_packet ( packet ) ;
return retval ;
}
/**
* hpsb_send_packet - transmit a packet on the bus
* @ packet : packet to send
*
* The packet is sent through the host specified in the packet - > host field .
* Before sending , the packet ' s transmit speed is automatically determined
* using the local speed map when it is an async , non - broadcast packet .
*
* Possibilities for failure are that host is either not initialized , in bus
* reset , the packet ' s generation number doesn ' t match the current generation
* number or the host reports a transmit error .
*
* Return value : 0 on success , negative errno on failure .
*/
int hpsb_send_packet ( struct hpsb_packet * packet )
{
struct hpsb_host * host = packet - > host ;
2005-12-02 02:52:03 +03:00
if ( host - > is_shutdown )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
if ( host - > in_bus_reset | |
( packet - > generation ! = get_hpsb_generation ( host ) ) )
2005-12-02 02:52:03 +03:00
return - EAGAIN ;
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
packet - > state = hpsb_queued ;
2005-04-17 02:20:36 +04:00
/* This just seems silly to me */
WARN_ON ( packet - > no_waiter & & packet - > expect_response ) ;
if ( ! packet - > no_waiter | | packet - > expect_response ) {
2007-03-26 00:22:40 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
atomic_inc ( & packet - > refcnt ) ;
2005-07-10 04:01:23 +04:00
/* Set the initial "sendtime" to 10 seconds from now, to
prevent premature expiry . If a packet takes more than
10 seconds to hit the wire , we have bigger problems : ) */
2005-05-17 08:54:05 +04:00
packet - > sendtime = jiffies + 10 * HZ ;
2007-03-26 00:22:40 +04:00
spin_lock_irqsave ( & pending_packets_lock , flags ) ;
list_add_tail ( & packet - > queue , & host - > pending_packets ) ;
spin_unlock_irqrestore ( & pending_packets_lock , flags ) ;
2005-04-17 02:20:36 +04:00
}
2005-12-02 02:52:03 +03:00
if ( packet - > node_id = = host - > node_id ) {
2005-04-17 02:20:36 +04:00
/* it is a local request, so handle it locally */
2005-12-02 02:52:03 +03:00
quadlet_t * data ;
size_t size = packet - > data_size + packet - > header_size ;
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
data = kmalloc ( size , GFP_ATOMIC ) ;
if ( ! data ) {
HPSB_ERR ( " unable to allocate memory for concatenating header and data " ) ;
return - ENOMEM ;
}
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
memcpy ( data , packet - > header , packet - > header_size ) ;
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
if ( packet - > data_size )
2005-04-17 02:20:36 +04:00
memcpy ( ( ( u8 * ) data ) + packet - > header_size , packet - > data , packet - > data_size ) ;
2005-12-02 02:52:03 +03:00
dump_packet ( " send packet local " , packet - > header , packet - > header_size , - 1 ) ;
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
hpsb_packet_sent ( host , packet , packet - > expect_response ? ACK_PENDING : ACK_COMPLETE ) ;
hpsb_packet_received ( host , data , size , 0 ) ;
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
kfree ( data ) ;
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2006-06-13 02:12:37 +04:00
if ( packet - > type = = hpsb_async & &
NODEID_TO_NODE ( packet - > node_id ) ! = ALL_NODES )
2005-12-02 02:52:03 +03:00
packet - > speed_code =
2006-06-13 02:12:37 +04:00
host - > speed [ NODEID_TO_NODE ( packet - > node_id ) ] ;
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
dump_packet ( " send packet " , packet - > header , packet - > header_size , packet - > speed_code ) ;
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
return host - > driver - > transmit_packet ( host , packet ) ;
2005-04-17 02:20:36 +04:00
}
/* We could just use complete() directly as the packet complete
* callback , but this is more typesafe , in the sense that we get a
* compiler error if the prototype for complete ( ) changes . */
static void complete_packet ( void * data )
{
complete ( ( struct completion * ) data ) ;
}
2007-03-05 05:06:23 +03:00
/**
* hpsb_send_packet_and_wait - enqueue packet , block until transaction completes
* @ packet : packet to send
*
* Return value : 0 on success , negative errno on failure .
*/
2005-04-17 02:20:36 +04:00
int hpsb_send_packet_and_wait ( struct hpsb_packet * packet )
{
struct completion done ;
int retval ;
init_completion ( & done ) ;
hpsb_set_packet_complete_task ( packet , complete_packet , & done ) ;
retval = hpsb_send_packet ( packet ) ;
if ( retval = = 0 )
wait_for_completion ( & done ) ;
return retval ;
}
static void send_packet_nocare ( struct hpsb_packet * packet )
{
2005-12-02 02:52:03 +03:00
if ( hpsb_send_packet ( packet ) < 0 ) {
hpsb_free_packet ( packet ) ;
}
2005-04-17 02:20:36 +04:00
}
2007-03-26 00:22:40 +04:00
static size_t packet_size_to_data_size ( size_t packet_size , size_t header_size ,
size_t buffer_size , int tcode )
{
size_t ret = packet_size < = header_size ? 0 : packet_size - header_size ;
if ( unlikely ( ret > buffer_size ) )
ret = buffer_size ;
if ( unlikely ( ret + header_size ! = packet_size ) )
2007-04-04 00:00:47 +04:00
HPSB_ERR ( " unexpected packet size %zd (tcode %d), bug? " ,
2007-03-26 00:22:40 +04:00
packet_size , tcode ) ;
return ret ;
}
2005-04-17 02:20:36 +04:00
static void handle_packet_response ( struct hpsb_host * host , int tcode ,
quadlet_t * data , size_t size )
{
2007-03-26 00:22:40 +04:00
struct hpsb_packet * packet ;
int tlabel = ( data [ 0 ] > > 10 ) & 0x3f ;
size_t header_size ;
2005-12-02 02:52:03 +03:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
2007-03-26 00:22:40 +04:00
spin_lock_irqsave ( & pending_packets_lock , flags ) ;
2005-04-17 02:20:36 +04:00
2007-03-26 00:22:40 +04:00
list_for_each_entry ( packet , & host - > pending_packets , queue )
if ( packet - > tlabel = = tlabel & &
packet - > node_id = = ( data [ 1 ] > > 16 ) )
goto found ;
2005-04-17 02:20:36 +04:00
2007-03-26 00:22:40 +04:00
spin_unlock_irqrestore ( & pending_packets_lock , flags ) ;
HPSB_DEBUG ( " unsolicited response packet received - %s " ,
" no tlabel match " ) ;
dump_packet ( " contents " , data , 16 , - 1 ) ;
return ;
2005-04-17 02:20:36 +04:00
2007-03-26 00:22:40 +04:00
found :
2005-12-02 02:52:03 +03:00
switch ( packet - > tcode ) {
case TCODE_WRITEQ :
case TCODE_WRITEB :
2007-03-26 00:22:40 +04:00
if ( unlikely ( tcode ! = TCODE_WRITE_RESPONSE ) )
2005-04-17 02:20:36 +04:00
break ;
2007-03-26 00:22:40 +04:00
header_size = 12 ;
size = 0 ;
goto dequeue ;
2005-12-02 02:52:03 +03:00
case TCODE_READQ :
2007-03-26 00:22:40 +04:00
if ( unlikely ( tcode ! = TCODE_READQ_RESPONSE ) )
2005-04-17 02:20:36 +04:00
break ;
2007-03-26 00:22:40 +04:00
header_size = 16 ;
size = 0 ;
goto dequeue ;
2005-12-02 02:52:03 +03:00
case TCODE_READB :
2007-03-26 00:22:40 +04:00
if ( unlikely ( tcode ! = TCODE_READB_RESPONSE ) )
2005-04-17 02:20:36 +04:00
break ;
2007-03-26 00:22:40 +04:00
header_size = 16 ;
size = packet_size_to_data_size ( size , header_size ,
packet - > allocated_data_size ,
tcode ) ;
goto dequeue ;
2005-12-02 02:52:03 +03:00
case TCODE_LOCK_REQUEST :
2007-03-26 00:22:40 +04:00
if ( unlikely ( tcode ! = TCODE_LOCK_RESPONSE ) )
2005-04-17 02:20:36 +04:00
break ;
2007-03-26 00:22:40 +04:00
header_size = 16 ;
size = packet_size_to_data_size ( min ( size , ( size_t ) ( 16 + 8 ) ) ,
header_size ,
packet - > allocated_data_size ,
tcode ) ;
goto dequeue ;
2005-12-02 02:52:03 +03:00
}
2005-04-17 02:20:36 +04:00
2007-03-26 00:22:40 +04:00
spin_unlock_irqrestore ( & pending_packets_lock , flags ) ;
HPSB_DEBUG ( " unsolicited response packet received - %s " ,
" tcode mismatch " ) ;
dump_packet ( " contents " , data , 16 , - 1 ) ;
return ;
2005-04-17 02:20:36 +04:00
2007-03-26 00:22:40 +04:00
dequeue :
list_del_init ( & packet - > queue ) ;
spin_unlock_irqrestore ( & pending_packets_lock , flags ) ;
2005-04-17 02:20:36 +04:00
if ( packet - > state = = hpsb_queued ) {
packet - > sendtime = jiffies ;
packet - > ack_code = ACK_PENDING ;
}
packet - > state = hpsb_complete ;
2007-03-26 00:22:40 +04:00
memcpy ( packet - > header , data , header_size ) ;
if ( size )
memcpy ( packet - > data , data + 4 , size ) ;
2005-04-17 02:20:36 +04:00
queue_packet_complete ( packet ) ;
}
static struct hpsb_packet * create_reply_packet ( struct hpsb_host * host ,
quadlet_t * data , size_t dsize )
{
2005-12-02 02:52:03 +03:00
struct hpsb_packet * p ;
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
p = hpsb_alloc_packet ( dsize ) ;
if ( unlikely ( p = = NULL ) ) {
/* FIXME - send data_error response */
2007-03-26 00:22:40 +04:00
HPSB_ERR ( " out of memory, cannot send response packet " ) ;
2005-12-02 02:52:03 +03:00
return NULL ;
}
2005-04-17 02:20:36 +04:00
2005-12-02 02:52:03 +03:00
p - > type = hpsb_async ;
p - > state = hpsb_unused ;
p - > host = host ;
p - > node_id = data [ 1 ] > > 16 ;
p - > tlabel = ( data [ 0 ] > > 10 ) & 0x3f ;
p - > no_waiter = 1 ;
2005-04-17 02:20:36 +04:00
p - > generation = get_hpsb_generation ( host ) ;
if ( dsize % 4 )
p - > data [ dsize / 4 ] = 0 ;
2005-12-02 02:52:03 +03:00
return p ;
2005-04-17 02:20:36 +04:00
}
# define PREP_ASYNC_HEAD_RCODE(tc) \
packet - > tcode = tc ; \
packet - > header [ 0 ] = ( packet - > node_id < < 16 ) | ( packet - > tlabel < < 10 ) \
| ( 1 < < 8 ) | ( tc < < 4 ) ; \
packet - > header [ 1 ] = ( packet - > host - > node_id < < 16 ) | ( rcode < < 12 ) ; \
packet - > header [ 2 ] = 0
static void fill_async_readquad_resp ( struct hpsb_packet * packet , int rcode ,
2005-12-02 02:52:03 +03:00
quadlet_t data )
2005-04-17 02:20:36 +04:00
{
PREP_ASYNC_HEAD_RCODE ( TCODE_READQ_RESPONSE ) ;
packet - > header [ 3 ] = data ;
packet - > header_size = 16 ;
packet - > data_size = 0 ;
}
static void fill_async_readblock_resp ( struct hpsb_packet * packet , int rcode ,
2005-12-02 02:52:03 +03:00
int length )
2005-04-17 02:20:36 +04:00
{
if ( rcode ! = RCODE_COMPLETE )
length = 0 ;
PREP_ASYNC_HEAD_RCODE ( TCODE_READB_RESPONSE ) ;
packet - > header [ 3 ] = length < < 16 ;
packet - > header_size = 16 ;
packet - > data_size = length + ( length % 4 ? 4 - ( length % 4 ) : 0 ) ;
}
static void fill_async_write_resp ( struct hpsb_packet * packet , int rcode )
{
PREP_ASYNC_HEAD_RCODE ( TCODE_WRITE_RESPONSE ) ;
packet - > header_size = 12 ;
packet - > data_size = 0 ;
}
static void fill_async_lock_resp ( struct hpsb_packet * packet , int rcode , int extcode ,
2005-12-02 02:52:03 +03:00
int length )
2005-04-17 02:20:36 +04:00
{
if ( rcode ! = RCODE_COMPLETE )
length = 0 ;
PREP_ASYNC_HEAD_RCODE ( TCODE_LOCK_RESPONSE ) ;
packet - > header [ 3 ] = ( length < < 16 ) | extcode ;
packet - > header_size = 16 ;
packet - > data_size = length ;
}
static void handle_incoming_packet ( struct hpsb_host * host , int tcode ,
2007-03-18 02:55:15 +03:00
quadlet_t * data , size_t size ,
int write_acked )
2005-04-17 02:20:36 +04:00
{
2005-12-02 02:52:03 +03:00
struct hpsb_packet * packet ;
int length , rcode , extcode ;
quadlet_t buffer ;
nodeid_t source = data [ 1 ] > > 16 ;
nodeid_t dest = data [ 0 ] > > 16 ;
u16 flags = ( u16 ) data [ 0 ] ;
u64 addr ;
2007-03-18 02:55:15 +03:00
/* FIXME?
* Out - of - bounds lengths are left for highlevel_read | write to cap . */
2005-12-02 02:52:03 +03:00
switch ( tcode ) {
case TCODE_WRITEQ :
addr = ( ( ( u64 ) ( data [ 1 ] & 0xffff ) ) < < 32 ) | data [ 2 ] ;
2007-03-18 02:55:15 +03:00
rcode = highlevel_write ( host , source , dest , data + 3 ,
2005-04-17 02:20:36 +04:00
addr , 4 , flags ) ;
2007-03-18 02:55:15 +03:00
goto handle_write_request ;
2005-12-02 02:52:03 +03:00
case TCODE_WRITEB :
addr = ( ( ( u64 ) ( data [ 1 ] & 0xffff ) ) < < 32 ) | data [ 2 ] ;
2007-03-18 02:55:15 +03:00
rcode = highlevel_write ( host , source , dest , data + 4 ,
addr , data [ 3 ] > > 16 , flags ) ;
handle_write_request :
if ( rcode < 0 | | write_acked | |
NODEID_TO_NODE ( data [ 0 ] > > 16 ) = = NODE_MASK )
return ;
/* not a broadcast write, reply */
packet = create_reply_packet ( host , data , 0 ) ;
if ( packet ) {
2005-12-02 02:52:03 +03:00
fill_async_write_resp ( packet , rcode ) ;
send_packet_nocare ( packet ) ;
}
2007-03-18 02:55:15 +03:00
return ;
2005-12-02 02:52:03 +03:00
case TCODE_READQ :
addr = ( ( ( u64 ) ( data [ 1 ] & 0xffff ) ) < < 32 ) | data [ 2 ] ;
rcode = highlevel_read ( host , source , & buffer , addr , 4 , flags ) ;
2007-03-18 02:55:15 +03:00
if ( rcode < 0 )
return ;
2005-12-02 02:52:03 +03:00
2007-03-18 02:55:15 +03:00
packet = create_reply_packet ( host , data , 0 ) ;
if ( packet ) {
2005-12-02 02:52:03 +03:00
fill_async_readquad_resp ( packet , rcode , buffer ) ;
send_packet_nocare ( packet ) ;
}
2007-03-18 02:55:15 +03:00
return ;
2005-12-02 02:52:03 +03:00
case TCODE_READB :
length = data [ 3 ] > > 16 ;
2007-03-18 02:55:15 +03:00
packet = create_reply_packet ( host , data , length ) ;
if ( ! packet )
return ;
2005-12-02 02:52:03 +03:00
addr = ( ( ( u64 ) ( data [ 1 ] & 0xffff ) ) < < 32 ) | data [ 2 ] ;
rcode = highlevel_read ( host , source , packet - > data , addr ,
length , flags ) ;
2007-03-18 02:55:15 +03:00
if ( rcode < 0 ) {
2005-12-02 02:52:03 +03:00
hpsb_free_packet ( packet ) ;
2007-03-18 02:55:15 +03:00
return ;
2005-12-02 02:52:03 +03:00
}
2007-03-18 02:55:15 +03:00
fill_async_readblock_resp ( packet , rcode , length ) ;
send_packet_nocare ( packet ) ;
return ;
2005-12-02 02:52:03 +03:00
case TCODE_LOCK_REQUEST :
length = data [ 3 ] > > 16 ;
extcode = data [ 3 ] & 0xffff ;
addr = ( ( ( u64 ) ( data [ 1 ] & 0xffff ) ) < < 32 ) | data [ 2 ] ;
2007-03-18 02:55:15 +03:00
packet = create_reply_packet ( host , data , 8 ) ;
if ( ! packet )
return ;
2005-12-02 02:52:03 +03:00
2007-03-18 02:55:15 +03:00
if ( extcode = = 0 | | extcode > = 7 ) {
2005-12-02 02:52:03 +03:00
/* let switch default handle error */
length = 0 ;
}
switch ( length ) {
case 4 :
rcode = highlevel_lock ( host , source , packet - > data , addr ,
2007-03-18 02:55:15 +03:00
data [ 4 ] , 0 , extcode , flags ) ;
2005-12-02 02:52:03 +03:00
fill_async_lock_resp ( packet , rcode , extcode , 4 ) ;
break ;
case 8 :
2007-03-18 02:55:15 +03:00
if ( extcode ! = EXTCODE_FETCH_ADD & &
extcode ! = EXTCODE_LITTLE_ADD ) {
2005-12-02 02:52:03 +03:00
rcode = highlevel_lock ( host , source ,
packet - > data , addr ,
data [ 5 ] , data [ 4 ] ,
extcode , flags ) ;
fill_async_lock_resp ( packet , rcode , extcode , 4 ) ;
} else {
rcode = highlevel_lock64 ( host , source ,
( octlet_t * ) packet - > data , addr ,
* ( octlet_t * ) ( data + 4 ) , 0ULL ,
extcode , flags ) ;
fill_async_lock_resp ( packet , rcode , extcode , 8 ) ;
}
break ;
case 16 :
rcode = highlevel_lock64 ( host , source ,
( octlet_t * ) packet - > data , addr ,
* ( octlet_t * ) ( data + 6 ) ,
* ( octlet_t * ) ( data + 4 ) ,
extcode , flags ) ;
fill_async_lock_resp ( packet , rcode , extcode , 8 ) ;
break ;
default :
rcode = RCODE_TYPE_ERROR ;
2007-03-18 02:55:15 +03:00
fill_async_lock_resp ( packet , rcode , extcode , 0 ) ;
2005-12-02 02:52:03 +03:00
}
2007-03-18 02:55:15 +03:00
if ( rcode < 0 )
2005-12-02 02:52:03 +03:00
hpsb_free_packet ( packet ) ;
2007-03-18 02:55:15 +03:00
else
send_packet_nocare ( packet ) ;
return ;
2005-12-02 02:52:03 +03:00
}
2005-04-17 02:20:36 +04:00
}
2007-03-05 05:06:23 +03:00
/**
* hpsb_packet_received - hand over received packet to the core
*
* For host driver module usage .
*
* The contents of data are expected to be the full packet but with the CRCs
* left out ( data block follows header immediately ) , with the header ( i . e . the
* first four quadlets ) in machine byte order and the data block in big endian .
* * @ data can be safely overwritten after this call .
*
* If the packet is a write request , @ write_acked is to be set to true if it was
* ack_complete ' d already , false otherwise . This argument is ignored for any
* other packet type .
*/
2005-04-17 02:20:36 +04:00
void hpsb_packet_received ( struct hpsb_host * host , quadlet_t * data , size_t size ,
2005-12-02 02:52:03 +03:00
int write_acked )
2005-04-17 02:20:36 +04:00
{
2005-12-02 02:52:03 +03:00
int tcode ;
2007-03-26 00:22:40 +04:00
if ( unlikely ( host - > in_bus_reset ) ) {
HPSB_DEBUG ( " received packet during reset; ignoring " ) ;
2005-12-02 02:52:03 +03:00
return ;
}
dump_packet ( " received packet " , data , size , - 1 ) ;
tcode = ( data [ 0 ] > > 4 ) & 0xf ;
switch ( tcode ) {
case TCODE_WRITE_RESPONSE :
case TCODE_READQ_RESPONSE :
case TCODE_READB_RESPONSE :
case TCODE_LOCK_RESPONSE :
handle_packet_response ( host , tcode , data , size ) ;
break ;
case TCODE_WRITEQ :
case TCODE_WRITEB :
case TCODE_READQ :
case TCODE_READB :
case TCODE_LOCK_REQUEST :
handle_incoming_packet ( host , tcode , data , size , write_acked ) ;
break ;
case TCODE_CYCLE_START :
/* simply ignore this packet if it is passed on */
break ;
default :
2007-03-26 00:22:40 +04:00
HPSB_DEBUG ( " received packet with bogus transaction code %d " ,
tcode ) ;
2005-12-02 02:52:03 +03:00
break ;
}
2005-04-17 02:20:36 +04:00
}
static void abort_requests ( struct hpsb_host * host )
{
2007-03-26 00:22:40 +04:00
struct hpsb_packet * packet , * p ;
struct list_head tmp ;
unsigned long flags ;
2005-04-17 02:20:36 +04:00
host - > driver - > devctl ( host , CANCEL_REQUESTS , 0 ) ;
2007-03-26 00:22:40 +04:00
INIT_LIST_HEAD ( & tmp ) ;
spin_lock_irqsave ( & pending_packets_lock , flags ) ;
list_splice_init ( & host - > pending_packets , & tmp ) ;
spin_unlock_irqrestore ( & pending_packets_lock , flags ) ;
2005-04-17 02:20:36 +04:00
2007-03-26 00:22:40 +04:00
list_for_each_entry_safe ( packet , p , & tmp , queue ) {
list_del_init ( & packet - > queue ) ;
2005-04-17 02:20:36 +04:00
packet - > state = hpsb_complete ;
packet - > ack_code = ACKX_ABORTED ;
queue_packet_complete ( packet ) ;
}
}
void abort_timedouts ( unsigned long __opaque )
{
struct hpsb_host * host = ( struct hpsb_host * ) __opaque ;
2007-03-26 00:22:40 +04:00
struct hpsb_packet * packet , * p ;
struct list_head tmp ;
unsigned long flags , expire , j ;
2005-04-17 02:20:36 +04:00
spin_lock_irqsave ( & host - > csr . lock , flags ) ;
expire = host - > csr . expire ;
spin_unlock_irqrestore ( & host - > csr . lock , flags ) ;
2007-03-26 00:22:40 +04:00
j = jiffies ;
INIT_LIST_HEAD ( & tmp ) ;
spin_lock_irqsave ( & pending_packets_lock , flags ) ;
2005-04-17 02:20:36 +04:00
2007-03-26 00:22:40 +04:00
list_for_each_entry_safe ( packet , p , & host - > pending_packets , queue ) {
if ( time_before ( packet - > sendtime + expire , j ) )
list_move_tail ( & packet - > queue , & tmp ) ;
else
2005-04-17 02:20:36 +04:00
/* Since packets are added to the tail, the oldest
* ones are first , always . When we get to one that
* isn ' t timed out , the rest aren ' t either . */
break ;
}
2007-03-26 00:22:40 +04:00
if ( ! list_empty ( & host - > pending_packets ) )
mod_timer ( & host - > timeout , j + host - > timeout_interval ) ;
2005-04-17 02:20:36 +04:00
2007-03-26 00:22:40 +04:00
spin_unlock_irqrestore ( & pending_packets_lock , flags ) ;
2005-04-17 02:20:36 +04:00
2007-03-26 00:22:40 +04:00
list_for_each_entry_safe ( packet , p , & tmp , queue ) {
list_del_init ( & packet - > queue ) ;
packet - > state = hpsb_complete ;
packet - > ack_code = ACKX_TIMEOUT ;
queue_packet_complete ( packet ) ;
}
2005-04-17 02:20:36 +04:00
}
2006-06-13 02:15:50 +04:00
static struct task_struct * khpsbpkt_thread ;
2007-03-26 00:22:40 +04:00
static LIST_HEAD ( hpsbpkt_queue ) ;
2005-04-17 02:20:36 +04:00
static void queue_packet_complete ( struct hpsb_packet * packet )
{
2007-03-26 00:22:40 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
if ( packet - > no_waiter ) {
hpsb_free_packet ( packet ) ;
return ;
}
if ( packet - > complete_routine ! = NULL ) {
2007-03-26 00:22:40 +04:00
spin_lock_irqsave ( & pending_packets_lock , flags ) ;
list_add_tail ( & packet - > queue , & hpsbpkt_queue ) ;
spin_unlock_irqrestore ( & pending_packets_lock , flags ) ;
2006-06-13 02:15:50 +04:00
wake_up_process ( khpsbpkt_thread ) ;
2005-04-17 02:20:36 +04:00
}
return ;
}
2007-03-26 00:22:40 +04:00
/*
* Kernel thread which handles packets that are completed . This way the
* packet ' s " complete " function is asynchronously run in process context .
* Only packets which have a " complete " function may be sent here .
*/
2005-04-17 02:20:36 +04:00
static int hpsbpkt_thread ( void * __hi )
{
2007-03-26 00:22:40 +04:00
struct hpsb_packet * packet , * p ;
struct list_head tmp ;
int may_schedule ;
2005-04-17 02:20:36 +04:00
2006-06-13 02:15:50 +04:00
while ( ! kthread_should_stop ( ) ) {
2005-04-17 02:20:36 +04:00
2007-03-26 00:22:40 +04:00
INIT_LIST_HEAD ( & tmp ) ;
spin_lock_irq ( & pending_packets_lock ) ;
list_splice_init ( & hpsbpkt_queue , & tmp ) ;
spin_unlock_irq ( & pending_packets_lock ) ;
2005-04-17 02:20:36 +04:00
2007-03-26 00:22:40 +04:00
list_for_each_entry_safe ( packet , p , & tmp , queue ) {
list_del_init ( & packet - > queue ) ;
packet - > complete_routine ( packet - > complete_data ) ;
2005-04-17 02:20:36 +04:00
}
2006-06-13 02:15:50 +04:00
set_current_state ( TASK_INTERRUPTIBLE ) ;
2007-03-26 00:22:40 +04:00
spin_lock_irq ( & pending_packets_lock ) ;
may_schedule = list_empty ( & hpsbpkt_queue ) ;
spin_unlock_irq ( & pending_packets_lock ) ;
if ( may_schedule )
2006-06-13 02:15:50 +04:00
schedule ( ) ;
__set_current_state ( TASK_RUNNING ) ;
}
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int __init ieee1394_init ( void )
{
int i , ret ;
/* non-fatal error */
if ( hpsb_init_config_roms ( ) ) {
HPSB_ERR ( " Failed to initialize some config rom entries. \n " ) ;
HPSB_ERR ( " Some features may not be available \n " ) ;
}
2006-06-13 02:15:50 +04:00
khpsbpkt_thread = kthread_run ( hpsbpkt_thread , NULL , " khpsbpkt " ) ;
if ( IS_ERR ( khpsbpkt_thread ) ) {
2005-04-17 02:20:36 +04:00
HPSB_ERR ( " Failed to start hpsbpkt thread! \n " ) ;
2006-06-13 02:15:50 +04:00
ret = PTR_ERR ( khpsbpkt_thread ) ;
2005-04-17 02:20:36 +04:00
goto exit_cleanup_config_roms ;
}
if ( register_chrdev_region ( IEEE1394_CORE_DEV , 256 , " ieee1394 " ) ) {
HPSB_ERR ( " unable to register character device major %d! \n " , IEEE1394_MAJOR ) ;
ret = - ENODEV ;
goto exit_release_kernel_thread ;
}
ret = bus_register ( & ieee1394_bus_type ) ;
if ( ret < 0 ) {
HPSB_INFO ( " bus register failed " ) ;
2006-03-29 04:55:41 +04:00
goto release_chrdev ;
2005-04-17 02:20:36 +04:00
}
for ( i = 0 ; fw_bus_attrs [ i ] ; i + + ) {
ret = bus_create_file ( & ieee1394_bus_type , fw_bus_attrs [ i ] ) ;
if ( ret < 0 ) {
while ( i > = 0 ) {
bus_remove_file ( & ieee1394_bus_type ,
fw_bus_attrs [ i - - ] ) ;
}
bus_unregister ( & ieee1394_bus_type ) ;
2006-03-29 04:55:41 +04:00
goto release_chrdev ;
2005-04-17 02:20:36 +04:00
}
}
ret = class_register ( & hpsb_host_class ) ;
if ( ret < 0 )
goto release_all_bus ;
2005-03-23 20:53:36 +03:00
hpsb_protocol_class = class_create ( THIS_MODULE , " ieee1394_protocol " ) ;
2005-04-17 02:20:36 +04:00
if ( IS_ERR ( hpsb_protocol_class ) ) {
ret = PTR_ERR ( hpsb_protocol_class ) ;
goto release_class_host ;
}
ret = init_csr ( ) ;
if ( ret ) {
HPSB_INFO ( " init csr failed " ) ;
ret = - ENOMEM ;
goto release_class_protocol ;
}
if ( disable_nodemgr ) {
HPSB_INFO ( " nodemgr and IRM functionality disabled " ) ;
/* We shouldn't contend for IRM with nodemgr disabled, since
nodemgr implements functionality required of ieee1394a - 2000
IRMs */
hpsb_disable_irm = 1 ;
2005-12-02 02:52:03 +03:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
if ( hpsb_disable_irm ) {
HPSB_INFO ( " IRM functionality disabled " ) ;
}
ret = init_ieee1394_nodemgr ( ) ;
if ( ret < 0 ) {
HPSB_INFO ( " init nodemgr failed " ) ;
goto cleanup_csr ;
}
return 0 ;
cleanup_csr :
cleanup_csr ( ) ;
release_class_protocol :
2005-03-23 20:53:36 +03:00
class_destroy ( hpsb_protocol_class ) ;
2005-04-17 02:20:36 +04:00
release_class_host :
class_unregister ( & hpsb_host_class ) ;
release_all_bus :
for ( i = 0 ; fw_bus_attrs [ i ] ; i + + )
bus_remove_file ( & ieee1394_bus_type , fw_bus_attrs [ i ] ) ;
bus_unregister ( & ieee1394_bus_type ) ;
release_chrdev :
unregister_chrdev_region ( IEEE1394_CORE_DEV , 256 ) ;
exit_release_kernel_thread :
2006-06-13 02:15:50 +04:00
kthread_stop ( khpsbpkt_thread ) ;
2005-04-17 02:20:36 +04:00
exit_cleanup_config_roms :
hpsb_cleanup_config_roms ( ) ;
return ret ;
}
static void __exit ieee1394_cleanup ( void )
{
int i ;
if ( ! disable_nodemgr )
cleanup_ieee1394_nodemgr ( ) ;
cleanup_csr ( ) ;
2005-03-23 20:53:36 +03:00
class_destroy ( hpsb_protocol_class ) ;
2005-04-17 02:20:36 +04:00
class_unregister ( & hpsb_host_class ) ;
for ( i = 0 ; fw_bus_attrs [ i ] ; i + + )
bus_remove_file ( & ieee1394_bus_type , fw_bus_attrs [ i ] ) ;
bus_unregister ( & ieee1394_bus_type ) ;
2006-06-13 02:15:50 +04:00
kthread_stop ( khpsbpkt_thread ) ;
2005-04-17 02:20:36 +04:00
hpsb_cleanup_config_roms ( ) ;
unregister_chrdev_region ( IEEE1394_CORE_DEV , 256 ) ;
}
2007-09-20 23:17:33 +04:00
module_init ( ieee1394_init ) ;
2005-04-17 02:20:36 +04:00
module_exit ( ieee1394_cleanup ) ;
/* Exported symbols */
/** hosts.c **/
EXPORT_SYMBOL ( hpsb_alloc_host ) ;
EXPORT_SYMBOL ( hpsb_add_host ) ;
2007-01-07 23:49:27 +03:00
EXPORT_SYMBOL ( hpsb_resume_host ) ;
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( hpsb_remove_host ) ;
EXPORT_SYMBOL ( hpsb_update_config_rom_image ) ;
/** ieee1394_core.c **/
EXPORT_SYMBOL ( hpsb_speedto_str ) ;
EXPORT_SYMBOL ( hpsb_protocol_class ) ;
EXPORT_SYMBOL ( hpsb_set_packet_complete_task ) ;
EXPORT_SYMBOL ( hpsb_alloc_packet ) ;
EXPORT_SYMBOL ( hpsb_free_packet ) ;
EXPORT_SYMBOL ( hpsb_send_packet ) ;
EXPORT_SYMBOL ( hpsb_reset_bus ) ;
2007-02-03 19:44:39 +03:00
EXPORT_SYMBOL ( hpsb_read_cycle_timer ) ;
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( hpsb_bus_reset ) ;
EXPORT_SYMBOL ( hpsb_selfid_received ) ;
EXPORT_SYMBOL ( hpsb_selfid_complete ) ;
EXPORT_SYMBOL ( hpsb_packet_sent ) ;
EXPORT_SYMBOL ( hpsb_packet_received ) ;
EXPORT_SYMBOL_GPL ( hpsb_disable_irm ) ;
/** ieee1394_transactions.c **/
EXPORT_SYMBOL ( hpsb_get_tlabel ) ;
EXPORT_SYMBOL ( hpsb_free_tlabel ) ;
EXPORT_SYMBOL ( hpsb_make_readpacket ) ;
EXPORT_SYMBOL ( hpsb_make_writepacket ) ;
EXPORT_SYMBOL ( hpsb_make_streampacket ) ;
EXPORT_SYMBOL ( hpsb_make_lockpacket ) ;
EXPORT_SYMBOL ( hpsb_make_lock64packet ) ;
EXPORT_SYMBOL ( hpsb_make_phypacket ) ;
EXPORT_SYMBOL ( hpsb_read ) ;
EXPORT_SYMBOL ( hpsb_write ) ;
EXPORT_SYMBOL ( hpsb_packet_success ) ;
/** highlevel.c **/
EXPORT_SYMBOL ( hpsb_register_highlevel ) ;
EXPORT_SYMBOL ( hpsb_unregister_highlevel ) ;
EXPORT_SYMBOL ( hpsb_register_addrspace ) ;
EXPORT_SYMBOL ( hpsb_unregister_addrspace ) ;
EXPORT_SYMBOL ( hpsb_allocate_and_register_addrspace ) ;
EXPORT_SYMBOL ( hpsb_get_hostinfo ) ;
EXPORT_SYMBOL ( hpsb_create_hostinfo ) ;
EXPORT_SYMBOL ( hpsb_destroy_hostinfo ) ;
EXPORT_SYMBOL ( hpsb_set_hostinfo_key ) ;
EXPORT_SYMBOL ( hpsb_get_hostinfo_bykey ) ;
EXPORT_SYMBOL ( hpsb_set_hostinfo ) ;
/** nodemgr.c **/
EXPORT_SYMBOL ( hpsb_node_fill_packet ) ;
EXPORT_SYMBOL ( hpsb_node_write ) ;
2006-11-23 21:59:48 +03:00
EXPORT_SYMBOL ( __hpsb_register_protocol ) ;
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( hpsb_unregister_protocol ) ;
/** csr.c **/
EXPORT_SYMBOL ( hpsb_update_config_rom ) ;
/** dma.c **/
EXPORT_SYMBOL ( dma_prog_region_init ) ;
EXPORT_SYMBOL ( dma_prog_region_alloc ) ;
EXPORT_SYMBOL ( dma_prog_region_free ) ;
EXPORT_SYMBOL ( dma_region_init ) ;
EXPORT_SYMBOL ( dma_region_alloc ) ;
EXPORT_SYMBOL ( dma_region_free ) ;
EXPORT_SYMBOL ( dma_region_sync_for_cpu ) ;
EXPORT_SYMBOL ( dma_region_sync_for_device ) ;
EXPORT_SYMBOL ( dma_region_mmap ) ;
EXPORT_SYMBOL ( dma_region_offset_to_bus ) ;
/** iso.c **/
EXPORT_SYMBOL ( hpsb_iso_xmit_init ) ;
EXPORT_SYMBOL ( hpsb_iso_recv_init ) ;
EXPORT_SYMBOL ( hpsb_iso_xmit_start ) ;
EXPORT_SYMBOL ( hpsb_iso_recv_start ) ;
EXPORT_SYMBOL ( hpsb_iso_recv_listen_channel ) ;
EXPORT_SYMBOL ( hpsb_iso_recv_unlisten_channel ) ;
EXPORT_SYMBOL ( hpsb_iso_recv_set_channel_mask ) ;
EXPORT_SYMBOL ( hpsb_iso_stop ) ;
EXPORT_SYMBOL ( hpsb_iso_shutdown ) ;
EXPORT_SYMBOL ( hpsb_iso_xmit_queue_packet ) ;
EXPORT_SYMBOL ( hpsb_iso_xmit_sync ) ;
EXPORT_SYMBOL ( hpsb_iso_recv_release_packets ) ;
EXPORT_SYMBOL ( hpsb_iso_n_ready ) ;
EXPORT_SYMBOL ( hpsb_iso_packet_sent ) ;
EXPORT_SYMBOL ( hpsb_iso_packet_received ) ;
EXPORT_SYMBOL ( hpsb_iso_wake ) ;
EXPORT_SYMBOL ( hpsb_iso_recv_flush ) ;
/** csr1212.c **/
EXPORT_SYMBOL ( csr1212_attach_keyval_to_directory ) ;
EXPORT_SYMBOL ( csr1212_detach_keyval_from_directory ) ;
2007-03-14 02:20:53 +03:00
EXPORT_SYMBOL ( csr1212_get_keyval ) ;
EXPORT_SYMBOL ( csr1212_new_directory ) ;
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( csr1212_parse_keyval ) ;
2007-03-14 02:20:53 +03:00
EXPORT_SYMBOL ( csr1212_read ) ;
EXPORT_SYMBOL ( csr1212_release_keyval ) ;