2005-04-16 15:20:36 -07:00
/*
* Copyright ( c ) 2004 Topspin Communications . All rights reserved .
*
* This software is available to you under a choice of one of two
* licenses . You may choose to be licensed under the terms of the GNU
* General Public License ( GPL ) Version 2 , available from the file
* COPYING in the main directory of this source tree , or the
* OpenIB . org BSD license below :
*
* Redistribution and use in source and binary forms , with or
* without modification , are permitted provided that the following
* conditions are met :
*
* - Redistributions of source code must retain the above
* copyright notice , this list of conditions and the following
* disclaimer .
*
* - Redistributions in binary form must reproduce the above
* copyright notice , this list of conditions and the following
* disclaimer in the documentation and / or other materials
* provided with the distribution .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND ,
* EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER IN AN
* ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*/
2005-10-30 15:03:48 -08:00
# include <linux/string.h>
# include <linux/slab.h>
2005-04-16 15:20:36 -07:00
# include "mthca_dev.h"
# include "mthca_cmd.h"
struct mthca_mgm {
2005-08-13 21:05:57 -07:00
__be32 next_gid_index ;
u32 reserved [ 3 ] ;
u8 gid [ 16 ] ;
__be32 qp [ MTHCA_QP_PER_MGM ] ;
2005-04-16 15:20:36 -07:00
} ;
static const u8 zero_gid [ 16 ] ; /* automatically initialized to 0 */
/*
* Caller must hold MCG table semaphore . gid and mgm parameters must
* be properly aligned for command interface .
*
* Returns 0 unless a firmware command error occurs .
*
* If GID is found in MGM or MGM is empty , * index = * hash , * prev = - 1
* and * mgm holds MGM entry .
*
* if GID is found in AMGM , * index = index in AMGM , * prev = index of
* previous entry in hash chain and * mgm holds AMGM entry .
*
* If no AMGM exists for given gid , * index = - 1 , * prev = index of last
* entry in hash chain and * mgm holds end of hash chain .
*/
static int find_mgm ( struct mthca_dev * dev ,
2005-06-27 14:36:45 -07:00
u8 * gid , struct mthca_mailbox * mgm_mailbox ,
2005-04-16 15:20:36 -07:00
u16 * hash , int * prev , int * index )
{
2005-06-27 14:36:45 -07:00
struct mthca_mailbox * mailbox ;
struct mthca_mgm * mgm = mgm_mailbox - > buf ;
2005-04-16 15:20:36 -07:00
u8 * mgid ;
int err ;
u8 status ;
2005-06-27 14:36:45 -07:00
mailbox = mthca_alloc_mailbox ( dev , GFP_KERNEL ) ;
if ( IS_ERR ( mailbox ) )
2005-04-16 15:20:36 -07:00
return - ENOMEM ;
2005-06-27 14:36:45 -07:00
mgid = mailbox - > buf ;
2005-04-16 15:20:36 -07:00
memcpy ( mgid , gid , 16 ) ;
2005-06-27 14:36:45 -07:00
err = mthca_MGID_HASH ( dev , mailbox , hash , & status ) ;
2005-04-16 15:20:36 -07:00
if ( err )
goto out ;
if ( status ) {
mthca_err ( dev , " MGID_HASH returned status %02x \n " , status ) ;
err = - EINVAL ;
goto out ;
}
if ( 0 )
2008-10-29 12:52:50 -07:00
mthca_dbg ( dev , " Hash for %pI6 is %04x \n " , gid , * hash ) ;
2005-04-16 15:20:36 -07:00
* index = * hash ;
* prev = - 1 ;
do {
2005-06-27 14:36:45 -07:00
err = mthca_READ_MGM ( dev , * index , mgm_mailbox , & status ) ;
2005-04-16 15:20:36 -07:00
if ( err )
goto out ;
if ( status ) {
mthca_err ( dev , " READ_MGM returned status %02x \n " , status ) ;
2006-01-06 13:11:07 -08:00
err = - EINVAL ;
goto out ;
2005-04-16 15:20:36 -07:00
}
if ( ! memcmp ( mgm - > gid , zero_gid , 16 ) ) {
if ( * index ! = * hash ) {
mthca_err ( dev , " Found zero MGID in AMGM. \n " ) ;
err = - EINVAL ;
}
goto out ;
}
if ( ! memcmp ( mgm - > gid , gid , 16 ) )
goto out ;
* prev = * index ;
2006-01-06 13:11:07 -08:00
* index = be32_to_cpu ( mgm - > next_gid_index ) > > 6 ;
2005-04-16 15:20:36 -07:00
} while ( * index ) ;
* index = - 1 ;
out :
2005-06-27 14:36:45 -07:00
mthca_free_mailbox ( dev , mailbox ) ;
2005-04-16 15:20:36 -07:00
return err ;
}
int mthca_multicast_attach ( struct ib_qp * ibqp , union ib_gid * gid , u16 lid )
{
struct mthca_dev * dev = to_mdev ( ibqp - > device ) ;
2005-06-27 14:36:45 -07:00
struct mthca_mailbox * mailbox ;
2005-04-16 15:20:36 -07:00
struct mthca_mgm * mgm ;
u16 hash ;
int index , prev ;
int link = 0 ;
int i ;
int err ;
u8 status ;
2005-06-27 14:36:45 -07:00
mailbox = mthca_alloc_mailbox ( dev , GFP_KERNEL ) ;
if ( IS_ERR ( mailbox ) )
return PTR_ERR ( mailbox ) ;
mgm = mailbox - > buf ;
2005-04-16 15:20:36 -07:00
2006-01-30 16:45:11 -08:00
mutex_lock ( & dev - > mcg_table . mutex ) ;
2005-04-16 15:20:36 -07:00
2005-06-27 14:36:45 -07:00
err = find_mgm ( dev , gid - > raw , mailbox , & hash , & prev , & index ) ;
2005-04-16 15:20:36 -07:00
if ( err )
goto out ;
if ( index ! = - 1 ) {
if ( ! memcmp ( mgm - > gid , zero_gid , 16 ) )
memcpy ( mgm - > gid , gid - > raw , 16 ) ;
} else {
link = 1 ;
index = mthca_alloc ( & dev - > mcg_table . alloc ) ;
if ( index = = - 1 ) {
mthca_err ( dev , " No AMGM entries left \n " ) ;
err = - ENOMEM ;
goto out ;
}
2005-06-27 14:36:45 -07:00
err = mthca_READ_MGM ( dev , index , mailbox , & status ) ;
2005-04-16 15:20:36 -07:00
if ( err )
goto out ;
if ( status ) {
mthca_err ( dev , " READ_MGM returned status %02x \n " , status ) ;
err = - EINVAL ;
goto out ;
}
2006-01-06 13:11:07 -08:00
memset ( mgm , 0 , sizeof * mgm ) ;
2005-04-16 15:20:36 -07:00
memcpy ( mgm - > gid , gid - > raw , 16 ) ;
}
for ( i = 0 ; i < MTHCA_QP_PER_MGM ; + + i )
2005-10-18 14:46:38 -07:00
if ( mgm - > qp [ i ] = = cpu_to_be32 ( ibqp - > qp_num | ( 1 < < 31 ) ) ) {
2006-02-01 13:38:24 -08:00
mthca_dbg ( dev , " QP %06x already a member of MGM \n " ,
2005-10-18 14:46:38 -07:00
ibqp - > qp_num ) ;
err = 0 ;
goto out ;
} else if ( ! ( mgm - > qp [ i ] & cpu_to_be32 ( 1 < < 31 ) ) ) {
2005-04-16 15:20:36 -07:00
mgm - > qp [ i ] = cpu_to_be32 ( ibqp - > qp_num | ( 1 < < 31 ) ) ;
break ;
}
if ( i = = MTHCA_QP_PER_MGM ) {
mthca_err ( dev , " MGM at index %x is full. \n " , index ) ;
err = - ENOMEM ;
goto out ;
}
2005-06-27 14:36:45 -07:00
err = mthca_WRITE_MGM ( dev , index , mailbox , & status ) ;
2005-04-16 15:20:36 -07:00
if ( err )
goto out ;
if ( status ) {
mthca_err ( dev , " WRITE_MGM returned status %02x \n " , status ) ;
err = - EINVAL ;
2006-01-06 13:11:07 -08:00
goto out ;
2005-04-16 15:20:36 -07:00
}
if ( ! link )
goto out ;
2005-06-27 14:36:45 -07:00
err = mthca_READ_MGM ( dev , prev , mailbox , & status ) ;
2005-04-16 15:20:36 -07:00
if ( err )
goto out ;
if ( status ) {
mthca_err ( dev , " READ_MGM returned status %02x \n " , status ) ;
err = - EINVAL ;
goto out ;
}
2006-01-06 13:11:07 -08:00
mgm - > next_gid_index = cpu_to_be32 ( index < < 6 ) ;
2005-04-16 15:20:36 -07:00
2005-06-27 14:36:45 -07:00
err = mthca_WRITE_MGM ( dev , prev , mailbox , & status ) ;
2005-04-16 15:20:36 -07:00
if ( err )
goto out ;
if ( status ) {
mthca_err ( dev , " WRITE_MGM returned status %02x \n " , status ) ;
err = - EINVAL ;
}
out :
2006-01-06 13:11:07 -08:00
if ( err & & link & & index ! = - 1 ) {
BUG_ON ( index < dev - > limits . num_mgms ) ;
mthca_free ( & dev - > mcg_table . alloc , index ) ;
}
2006-01-30 16:45:11 -08:00
mutex_unlock ( & dev - > mcg_table . mutex ) ;
2006-01-30 16:22:29 -08:00
2005-06-27 14:36:45 -07:00
mthca_free_mailbox ( dev , mailbox ) ;
2005-04-16 15:20:36 -07:00
return err ;
}
int mthca_multicast_detach ( struct ib_qp * ibqp , union ib_gid * gid , u16 lid )
{
struct mthca_dev * dev = to_mdev ( ibqp - > device ) ;
2005-06-27 14:36:45 -07:00
struct mthca_mailbox * mailbox ;
2005-04-16 15:20:36 -07:00
struct mthca_mgm * mgm ;
u16 hash ;
int prev , index ;
int i , loc ;
int err ;
u8 status ;
2005-06-27 14:36:45 -07:00
mailbox = mthca_alloc_mailbox ( dev , GFP_KERNEL ) ;
if ( IS_ERR ( mailbox ) )
return PTR_ERR ( mailbox ) ;
mgm = mailbox - > buf ;
2005-04-16 15:20:36 -07:00
2006-01-30 16:45:11 -08:00
mutex_lock ( & dev - > mcg_table . mutex ) ;
2005-04-16 15:20:36 -07:00
2005-06-27 14:36:45 -07:00
err = find_mgm ( dev , gid - > raw , mailbox , & hash , & prev , & index ) ;
2005-04-16 15:20:36 -07:00
if ( err )
goto out ;
if ( index = = - 1 ) {
2008-10-29 12:52:50 -07:00
mthca_err ( dev , " MGID %pI6 not found \n " , gid - > raw ) ;
2005-04-16 15:20:36 -07:00
err = - EINVAL ;
goto out ;
}
for ( loc = - 1 , i = 0 ; i < MTHCA_QP_PER_MGM ; + + i ) {
if ( mgm - > qp [ i ] = = cpu_to_be32 ( ibqp - > qp_num | ( 1 < < 31 ) ) )
loc = i ;
if ( ! ( mgm - > qp [ i ] & cpu_to_be32 ( 1 < < 31 ) ) )
break ;
}
if ( loc = = - 1 ) {
mthca_err ( dev , " QP %06x not found in MGM \n " , ibqp - > qp_num ) ;
err = - EINVAL ;
goto out ;
}
mgm - > qp [ loc ] = mgm - > qp [ i - 1 ] ;
mgm - > qp [ i - 1 ] = 0 ;
2005-06-27 14:36:45 -07:00
err = mthca_WRITE_MGM ( dev , index , mailbox , & status ) ;
2005-04-16 15:20:36 -07:00
if ( err )
goto out ;
if ( status ) {
mthca_err ( dev , " WRITE_MGM returned status %02x \n " , status ) ;
err = - EINVAL ;
goto out ;
}
if ( i ! = 1 )
goto out ;
if ( prev = = - 1 ) {
/* Remove entry from MGM */
2006-01-06 13:11:07 -08:00
int amgm_index_to_free = be32_to_cpu ( mgm - > next_gid_index ) > > 6 ;
if ( amgm_index_to_free ) {
err = mthca_READ_MGM ( dev , amgm_index_to_free ,
2005-06-27 14:36:45 -07:00
mailbox , & status ) ;
2005-04-16 15:20:36 -07:00
if ( err )
goto out ;
if ( status ) {
mthca_err ( dev , " READ_MGM returned status %02x \n " ,
status ) ;
err = - EINVAL ;
goto out ;
}
} else
memset ( mgm - > gid , 0 , 16 ) ;
2005-06-27 14:36:45 -07:00
err = mthca_WRITE_MGM ( dev , index , mailbox , & status ) ;
2005-04-16 15:20:36 -07:00
if ( err )
goto out ;
if ( status ) {
mthca_err ( dev , " WRITE_MGM returned status %02x \n " , status ) ;
err = - EINVAL ;
goto out ;
}
2006-01-06 13:11:07 -08:00
if ( amgm_index_to_free ) {
BUG_ON ( amgm_index_to_free < dev - > limits . num_mgms ) ;
mthca_free ( & dev - > mcg_table . alloc , amgm_index_to_free ) ;
}
2005-04-16 15:20:36 -07:00
} else {
/* Remove entry from AMGM */
2006-01-06 13:11:07 -08:00
int curr_next_index = be32_to_cpu ( mgm - > next_gid_index ) > > 6 ;
2005-06-27 14:36:45 -07:00
err = mthca_READ_MGM ( dev , prev , mailbox , & status ) ;
2005-04-16 15:20:36 -07:00
if ( err )
goto out ;
if ( status ) {
mthca_err ( dev , " READ_MGM returned status %02x \n " , status ) ;
err = - EINVAL ;
goto out ;
}
2006-01-06 13:11:07 -08:00
mgm - > next_gid_index = cpu_to_be32 ( curr_next_index < < 6 ) ;
2005-04-16 15:20:36 -07:00
2005-06-27 14:36:45 -07:00
err = mthca_WRITE_MGM ( dev , prev , mailbox , & status ) ;
2005-04-16 15:20:36 -07:00
if ( err )
goto out ;
if ( status ) {
mthca_err ( dev , " WRITE_MGM returned status %02x \n " , status ) ;
err = - EINVAL ;
goto out ;
}
2006-01-06 13:11:07 -08:00
BUG_ON ( index < dev - > limits . num_mgms ) ;
mthca_free ( & dev - > mcg_table . alloc , index ) ;
2005-04-16 15:20:36 -07:00
}
out :
2006-01-30 16:45:11 -08:00
mutex_unlock ( & dev - > mcg_table . mutex ) ;
2006-01-30 16:22:29 -08:00
2005-06-27 14:36:45 -07:00
mthca_free_mailbox ( dev , mailbox ) ;
2005-04-16 15:20:36 -07:00
return err ;
}
2006-11-29 15:33:06 -08:00
int mthca_init_mcg_table ( struct mthca_dev * dev )
2005-04-16 15:20:36 -07:00
{
int err ;
2006-01-06 13:11:07 -08:00
int table_size = dev - > limits . num_mgms + dev - > limits . num_amgms ;
2005-04-16 15:20:36 -07:00
err = mthca_alloc_init ( & dev - > mcg_table . alloc ,
2006-01-06 13:11:07 -08:00
table_size ,
table_size - 1 ,
dev - > limits . num_mgms ) ;
2005-04-16 15:20:36 -07:00
if ( err )
return err ;
2006-01-30 16:45:11 -08:00
mutex_init ( & dev - > mcg_table . mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2006-03-29 09:36:46 -08:00
void mthca_cleanup_mcg_table ( struct mthca_dev * dev )
2005-04-16 15:20:36 -07:00
{
mthca_alloc_cleanup ( & dev - > mcg_table . alloc ) ;
}