2015-07-30 15:17:43 -04:00
/*
2016-02-14 20:22:17 -08:00
* Copyright ( c ) 2015 , 2016 Intel Corporation .
2015-07-30 15:17:43 -04:00
*
* This file is provided under a dual BSD / GPLv2 license . When using or
* redistributing this file , you may do so under either license .
*
* GPL LICENSE SUMMARY
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
* BSD LICENSE
*
* 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 .
* - Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* " AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
* SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
* LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*
*/
# include <linux/delay.h>
# include <linux/pci.h>
# include <linux/vmalloc.h>
# include "hfi.h"
2016-07-06 17:28:52 -04:00
/* for the given bus number, return the CSR for reading an i2c line */
static inline u32 i2c_in_csr ( u32 bus_num )
{
return bus_num ? ASIC_QSFP2_IN : ASIC_QSFP1_IN ;
}
/* for the given bus number, return the CSR for writing an i2c line */
static inline u32 i2c_oe_csr ( u32 bus_num )
{
return bus_num ? ASIC_QSFP2_OE : ASIC_QSFP1_OE ;
}
static void hfi1_setsda ( void * data , int state )
{
struct hfi1_i2c_bus * bus = ( struct hfi1_i2c_bus * ) data ;
struct hfi1_devdata * dd = bus - > controlling_dd ;
u64 reg ;
u32 target_oe ;
target_oe = i2c_oe_csr ( bus - > num ) ;
reg = read_csr ( dd , target_oe ) ;
/*
* The OE bit value is inverted and connected to the pin . When
* OE is 0 the pin is left to be pulled up , when the OE is 1
* the pin is driven low . This matches the " open drain " or " open
* collector " convention.
*/
if ( state )
reg & = ~ QSFP_HFI0_I2CDAT ;
else
reg | = QSFP_HFI0_I2CDAT ;
write_csr ( dd , target_oe , reg ) ;
/* do a read to force the write into the chip */
( void ) read_csr ( dd , target_oe ) ;
}
static void hfi1_setscl ( void * data , int state )
{
struct hfi1_i2c_bus * bus = ( struct hfi1_i2c_bus * ) data ;
struct hfi1_devdata * dd = bus - > controlling_dd ;
u64 reg ;
u32 target_oe ;
target_oe = i2c_oe_csr ( bus - > num ) ;
reg = read_csr ( dd , target_oe ) ;
/*
* The OE bit value is inverted and connected to the pin . When
* OE is 0 the pin is left to be pulled up , when the OE is 1
* the pin is driven low . This matches the " open drain " or " open
* collector " convention.
*/
if ( state )
reg & = ~ QSFP_HFI0_I2CCLK ;
else
reg | = QSFP_HFI0_I2CCLK ;
write_csr ( dd , target_oe , reg ) ;
/* do a read to force the write into the chip */
( void ) read_csr ( dd , target_oe ) ;
}
static int hfi1_getsda ( void * data )
{
struct hfi1_i2c_bus * bus = ( struct hfi1_i2c_bus * ) data ;
u64 reg ;
u32 target_in ;
hfi1_setsda ( data , 1 ) ; /* clear OE so we do not pull line down */
udelay ( 2 ) ; /* 1us pull up + 250ns hold */
target_in = i2c_in_csr ( bus - > num ) ;
reg = read_csr ( bus - > controlling_dd , target_in ) ;
return ! ! ( reg & QSFP_HFI0_I2CDAT ) ;
}
static int hfi1_getscl ( void * data )
{
struct hfi1_i2c_bus * bus = ( struct hfi1_i2c_bus * ) data ;
u64 reg ;
u32 target_in ;
hfi1_setscl ( data , 1 ) ; /* clear OE so we do not pull line down */
udelay ( 2 ) ; /* 1us pull up + 250ns hold */
target_in = i2c_in_csr ( bus - > num ) ;
reg = read_csr ( bus - > controlling_dd , target_in ) ;
return ! ! ( reg & QSFP_HFI0_I2CCLK ) ;
}
2015-07-30 15:17:43 -04:00
/*
2016-07-06 17:28:52 -04:00
* Allocate and initialize the given i2c bus number .
* Returns NULL on failure .
2015-07-30 15:17:43 -04:00
*/
2016-07-06 17:28:52 -04:00
static struct hfi1_i2c_bus * init_i2c_bus ( struct hfi1_devdata * dd ,
struct hfi1_asic_data * ad , int num )
{
struct hfi1_i2c_bus * bus ;
int ret ;
bus = kzalloc ( sizeof ( * bus ) , GFP_KERNEL ) ;
if ( ! bus )
return NULL ;
bus - > controlling_dd = dd ;
bus - > num = num ; /* our bus number */
bus - > algo . setsda = hfi1_setsda ;
bus - > algo . setscl = hfi1_setscl ;
bus - > algo . getsda = hfi1_getsda ;
bus - > algo . getscl = hfi1_getscl ;
bus - > algo . udelay = 5 ;
2016-09-25 07:41:25 -07:00
bus - > algo . timeout = usecs_to_jiffies ( 100000 ) ;
2016-07-06 17:28:52 -04:00
bus - > algo . data = bus ;
bus - > adapter . owner = THIS_MODULE ;
bus - > adapter . algo_data = & bus - > algo ;
bus - > adapter . dev . parent = & dd - > pcidev - > dev ;
snprintf ( bus - > adapter . name , sizeof ( bus - > adapter . name ) ,
" hfi1_i2c%d " , num ) ;
ret = i2c_bit_add_bus ( & bus - > adapter ) ;
if ( ret ) {
dd_dev_info ( dd , " %s: unable to add i2c bus %d, err %d \n " ,
__func__ , num , ret ) ;
kfree ( bus ) ;
return NULL ;
}
return bus ;
}
2015-07-30 15:17:43 -04:00
/*
2016-07-06 17:28:52 -04:00
* Initialize i2c buses .
* Return 0 on success , - errno on error .
2015-07-30 15:17:43 -04:00
*/
2016-07-06 17:28:52 -04:00
int set_up_i2c ( struct hfi1_devdata * dd , struct hfi1_asic_data * ad )
2015-07-30 15:17:43 -04:00
{
2016-07-06 17:28:52 -04:00
ad - > i2c_bus0 = init_i2c_bus ( dd , ad , 0 ) ;
ad - > i2c_bus1 = init_i2c_bus ( dd , ad , 1 ) ;
if ( ! ad - > i2c_bus0 | | ! ad - > i2c_bus1 )
return - ENOMEM ;
return 0 ;
} ;
static void clean_i2c_bus ( struct hfi1_i2c_bus * bus )
{
if ( bus ) {
i2c_del_adapter ( & bus - > adapter ) ;
kfree ( bus ) ;
}
}
2015-07-30 15:17:43 -04:00
2016-07-06 17:28:52 -04:00
void clean_up_i2c ( struct hfi1_devdata * dd , struct hfi1_asic_data * ad )
{
2018-05-01 05:36:06 -07:00
if ( ! ad )
return ;
2016-07-06 17:28:52 -04:00
clean_i2c_bus ( ad - > i2c_bus0 ) ;
ad - > i2c_bus0 = NULL ;
clean_i2c_bus ( ad - > i2c_bus1 ) ;
ad - > i2c_bus1 = NULL ;
}
2015-07-30 15:17:43 -04:00
2016-07-06 17:28:52 -04:00
static int i2c_bus_write ( struct hfi1_devdata * dd , struct hfi1_i2c_bus * i2c ,
u8 slave_addr , int offset , int offset_size ,
u8 * data , u16 len )
{
int ret ;
int num_msgs ;
u8 offset_bytes [ 2 ] ;
struct i2c_msg msgs [ 2 ] ;
switch ( offset_size ) {
case 0 :
num_msgs = 1 ;
msgs [ 0 ] . addr = slave_addr ;
msgs [ 0 ] . flags = 0 ;
msgs [ 0 ] . len = len ;
msgs [ 0 ] . buf = data ;
break ;
case 2 :
offset_bytes [ 1 ] = ( offset > > 8 ) & 0xff ;
/* fall through */
case 1 :
num_msgs = 2 ;
offset_bytes [ 0 ] = offset & 0xff ;
msgs [ 0 ] . addr = slave_addr ;
msgs [ 0 ] . flags = 0 ;
msgs [ 0 ] . len = offset_size ;
msgs [ 0 ] . buf = offset_bytes ;
msgs [ 1 ] . addr = slave_addr ;
msgs [ 1 ] . flags = I2C_M_NOSTART ,
msgs [ 1 ] . len = len ;
msgs [ 1 ] . buf = data ;
break ;
default :
return - EINVAL ;
2015-07-30 15:17:43 -04:00
}
2016-07-06 17:28:52 -04:00
i2c - > controlling_dd = dd ;
ret = i2c_transfer ( & i2c - > adapter , msgs , num_msgs ) ;
if ( ret ! = num_msgs ) {
dd_dev_err ( dd , " %s: bus %d, i2c slave 0x%x, offset 0x%x, len 0x%x; write failed, ret %d \n " ,
__func__ , i2c - > num , slave_addr , offset , len , ret ) ;
return ret < 0 ? ret : - EIO ;
}
return 0 ;
}
static int i2c_bus_read ( struct hfi1_devdata * dd , struct hfi1_i2c_bus * bus ,
u8 slave_addr , int offset , int offset_size ,
u8 * data , u16 len )
{
int ret ;
int num_msgs ;
u8 offset_bytes [ 2 ] ;
struct i2c_msg msgs [ 2 ] ;
switch ( offset_size ) {
case 0 :
num_msgs = 1 ;
msgs [ 0 ] . addr = slave_addr ;
msgs [ 0 ] . flags = I2C_M_RD ;
msgs [ 0 ] . len = len ;
msgs [ 0 ] . buf = data ;
break ;
case 2 :
offset_bytes [ 1 ] = ( offset > > 8 ) & 0xff ;
/* fall through */
case 1 :
num_msgs = 2 ;
offset_bytes [ 0 ] = offset & 0xff ;
msgs [ 0 ] . addr = slave_addr ;
msgs [ 0 ] . flags = 0 ;
msgs [ 0 ] . len = offset_size ;
msgs [ 0 ] . buf = offset_bytes ;
msgs [ 1 ] . addr = slave_addr ;
msgs [ 1 ] . flags = I2C_M_RD ,
msgs [ 1 ] . len = len ;
msgs [ 1 ] . buf = data ;
break ;
default :
return - EINVAL ;
}
2015-07-30 15:17:43 -04:00
2016-07-06 17:28:52 -04:00
bus - > controlling_dd = dd ;
ret = i2c_transfer ( & bus - > adapter , msgs , num_msgs ) ;
if ( ret ! = num_msgs ) {
dd_dev_err ( dd , " %s: bus %d, i2c slave 0x%x, offset 0x%x, len 0x%x; read failed, ret %d \n " ,
__func__ , bus - > num , slave_addr , offset , len , ret ) ;
return ret < 0 ? ret : - EIO ;
}
return 0 ;
}
/*
* Raw i2c write . No set - up or lock checking .
*
* Return 0 on success , - errno on error .
*/
static int __i2c_write ( struct hfi1_pportdata * ppd , u32 target , int i2c_addr ,
int offset , void * bp , int len )
{
struct hfi1_devdata * dd = ppd - > dd ;
struct hfi1_i2c_bus * bus ;
u8 slave_addr ;
int offset_size ;
bus = target ? dd - > asic_data - > i2c_bus1 : dd - > asic_data - > i2c_bus0 ;
slave_addr = ( i2c_addr & 0xff ) > > 1 ; /* convert to 7-bit addr */
offset_size = ( i2c_addr > > 8 ) & 0x3 ;
return i2c_bus_write ( dd , bus , slave_addr , offset , offset_size , bp , len ) ;
2015-07-30 15:17:43 -04:00
}
2016-03-05 08:50:06 -08:00
/*
* Caller must hold the i2c chain resource .
2016-07-06 17:28:52 -04:00
*
* Return number of bytes written , or - errno .
2016-03-05 08:50:06 -08:00
*/
2015-07-30 15:17:43 -04:00
int i2c_write ( struct hfi1_pportdata * ppd , u32 target , int i2c_addr , int offset ,
void * bp , int len )
{
int ret ;
2016-04-12 10:50:04 -07:00
if ( ! check_chip_resource ( ppd - > dd , i2c_target ( target ) , __func__ ) )
2016-03-05 08:50:06 -08:00
return - EACCES ;
2016-02-03 14:34:15 -08:00
2016-07-06 17:28:52 -04:00
ret = __i2c_write ( ppd , target , i2c_addr , offset , bp , len ) ;
if ( ret )
2016-03-05 08:50:06 -08:00
return ret ;
2015-07-30 15:17:43 -04:00
2016-07-06 17:28:52 -04:00
return len ;
2015-07-30 15:17:43 -04:00
}
/*
2016-03-05 08:50:06 -08:00
* Raw i2c read . No set - up or lock checking .
2016-07-06 17:28:52 -04:00
*
* Return 0 on success , - errno on error .
2015-07-30 15:17:43 -04:00
*/
static int __i2c_read ( struct hfi1_pportdata * ppd , u32 target , int i2c_addr ,
int offset , void * bp , int len )
{
struct hfi1_devdata * dd = ppd - > dd ;
2016-07-06 17:28:52 -04:00
struct hfi1_i2c_bus * bus ;
u8 slave_addr ;
int offset_size ;
bus = target ? dd - > asic_data - > i2c_bus1 : dd - > asic_data - > i2c_bus0 ;
slave_addr = ( i2c_addr & 0xff ) > > 1 ; /* convert to 7-bit addr */
offset_size = ( i2c_addr > > 8 ) & 0x3 ;
return i2c_bus_read ( dd , bus , slave_addr , offset , offset_size , bp , len ) ;
2015-07-30 15:17:43 -04:00
}
2016-03-05 08:50:06 -08:00
/*
* Caller must hold the i2c chain resource .
2016-07-06 17:28:52 -04:00
*
* Return number of bytes read , or - errno .
2016-03-05 08:50:06 -08:00
*/
2015-07-30 15:17:43 -04:00
int i2c_read ( struct hfi1_pportdata * ppd , u32 target , int i2c_addr , int offset ,
void * bp , int len )
{
int ret ;
2016-04-12 10:50:04 -07:00
if ( ! check_chip_resource ( ppd - > dd , i2c_target ( target ) , __func__ ) )
2016-03-05 08:50:06 -08:00
return - EACCES ;
2016-02-03 14:34:15 -08:00
2016-07-06 17:28:52 -04:00
ret = __i2c_read ( ppd , target , i2c_addr , offset , bp , len ) ;
if ( ret )
2016-03-05 08:50:06 -08:00
return ret ;
2015-07-30 15:17:43 -04:00
2016-07-06 17:28:52 -04:00
return len ;
2015-07-30 15:17:43 -04:00
}
2016-02-03 14:31:05 -08:00
/*
* Write page n , offset m of QSFP memory as defined by SFF 8636
2016-02-18 11:12:16 -08:00
* by writing @ addr = ( ( 256 * n ) + m )
2016-03-05 08:50:06 -08:00
*
* Caller must hold the i2c chain resource .
2016-07-06 17:28:52 -04:00
*
* Return number of bytes written or - errno .
2016-02-03 14:31:05 -08:00
*/
2015-07-30 15:17:43 -04:00
int qsfp_write ( struct hfi1_pportdata * ppd , u32 target , int addr , void * bp ,
int len )
{
int count = 0 ;
int offset ;
int nwrite ;
2016-07-06 17:28:52 -04:00
int ret = 0 ;
2015-07-30 15:17:43 -04:00
u8 page ;
2016-04-12 10:50:04 -07:00
if ( ! check_chip_resource ( ppd - > dd , i2c_target ( target ) , __func__ ) )
2016-03-05 08:50:06 -08:00
return - EACCES ;
2015-07-30 15:17:43 -04:00
while ( count < len ) {
/*
2016-02-14 20:20:58 -08:00
* Set the qsfp page based on a zero - based address
2015-07-30 15:17:43 -04:00
* and a page size of QSFP_PAGESIZE bytes .
*/
page = ( u8 ) ( addr / QSFP_PAGESIZE ) ;
2016-02-03 14:34:15 -08:00
ret = __i2c_write ( ppd , target , QSFP_DEV | QSFP_OFFSET_SIZE ,
QSFP_PAGE_SELECT_BYTE_OFFS , & page , 1 ) ;
2016-07-06 17:28:52 -04:00
/* QSFPs require a 5-10msec delay after write operations */
mdelay ( 5 ) ;
if ( ret ) {
2016-02-18 11:12:34 -08:00
hfi1_dev_porterr ( ppd - > dd , ppd - > port ,
" QSFP chain %d can't write QSFP_PAGE_SELECT_BYTE: %d \n " ,
target , ret ) ;
2015-07-30 15:17:43 -04:00
break ;
}
offset = addr % QSFP_PAGESIZE ;
nwrite = len - count ;
2016-02-03 14:31:05 -08:00
/* truncate write to boundary if crossing boundary */
if ( ( ( addr % QSFP_RW_BOUNDARY ) + nwrite ) > QSFP_RW_BOUNDARY )
nwrite = QSFP_RW_BOUNDARY - ( addr % QSFP_RW_BOUNDARY ) ;
2015-07-30 15:17:43 -04:00
2016-02-03 14:34:15 -08:00
ret = __i2c_write ( ppd , target , QSFP_DEV | QSFP_OFFSET_SIZE ,
offset , bp + count , nwrite ) ;
2016-07-06 17:28:52 -04:00
/* QSFPs require a 5-10msec delay after write operations */
mdelay ( 5 ) ;
if ( ret ) /* stop on error */
2015-07-30 15:17:43 -04:00
break ;
2016-07-06 17:28:52 -04:00
count + = nwrite ;
addr + = nwrite ;
2015-07-30 15:17:43 -04:00
}
if ( ret < 0 )
return ret ;
return count ;
}
2016-03-05 08:50:06 -08:00
/*
* Perform a stand - alone single QSFP write . Acquire the resource , do the
2016-07-01 16:01:00 -07:00
* write , then release the resource .
2016-03-05 08:50:06 -08:00
*/
int one_qsfp_write ( struct hfi1_pportdata * ppd , u32 target , int addr , void * bp ,
int len )
{
struct hfi1_devdata * dd = ppd - > dd ;
u32 resource = qsfp_resource ( dd ) ;
int ret ;
ret = acquire_chip_resource ( dd , resource , QSFP_WAIT ) ;
if ( ret )
return ret ;
ret = qsfp_write ( ppd , target , addr , bp , len ) ;
release_chip_resource ( dd , resource ) ;
return ret ;
}
2016-02-03 14:31:05 -08:00
/*
* Access page n , offset m of QSFP memory as defined by SFF 8636
2016-02-18 11:12:16 -08:00
* by reading @ addr = ( ( 256 * n ) + m )
2016-03-05 08:50:06 -08:00
*
* Caller must hold the i2c chain resource .
2016-07-06 17:28:52 -04:00
*
* Return the number of bytes read or - errno .
2016-02-03 14:31:05 -08:00
*/
2015-07-30 15:17:43 -04:00
int qsfp_read ( struct hfi1_pportdata * ppd , u32 target , int addr , void * bp ,
int len )
{
int count = 0 ;
int offset ;
int nread ;
2016-07-06 17:28:52 -04:00
int ret = 0 ;
2015-07-30 15:17:43 -04:00
u8 page ;
2016-04-12 10:50:04 -07:00
if ( ! check_chip_resource ( ppd - > dd , i2c_target ( target ) , __func__ ) )
2016-03-05 08:50:06 -08:00
return - EACCES ;
2015-07-30 15:17:43 -04:00
while ( count < len ) {
/*
* Set the qsfp page based on a zero - based address
* and a page size of QSFP_PAGESIZE bytes .
*/
page = ( u8 ) ( addr / QSFP_PAGESIZE ) ;
2016-02-03 14:34:15 -08:00
ret = __i2c_write ( ppd , target , QSFP_DEV | QSFP_OFFSET_SIZE ,
QSFP_PAGE_SELECT_BYTE_OFFS , & page , 1 ) ;
2016-07-06 17:28:52 -04:00
/* QSFPs require a 5-10msec delay after write operations */
mdelay ( 5 ) ;
if ( ret ) {
2016-02-18 11:12:34 -08:00
hfi1_dev_porterr ( ppd - > dd , ppd - > port ,
" QSFP chain %d can't write QSFP_PAGE_SELECT_BYTE: %d \n " ,
target , ret ) ;
2015-07-30 15:17:43 -04:00
break ;
}
offset = addr % QSFP_PAGESIZE ;
nread = len - count ;
2016-02-03 14:31:05 -08:00
/* truncate read to boundary if crossing boundary */
if ( ( ( addr % QSFP_RW_BOUNDARY ) + nread ) > QSFP_RW_BOUNDARY )
nread = QSFP_RW_BOUNDARY - ( addr % QSFP_RW_BOUNDARY ) ;
2015-07-30 15:17:43 -04:00
2016-02-03 14:34:15 -08:00
ret = __i2c_read ( ppd , target , QSFP_DEV | QSFP_OFFSET_SIZE ,
offset , bp + count , nread ) ;
2016-07-06 17:28:52 -04:00
if ( ret ) /* stop on error */
2015-07-30 15:17:43 -04:00
break ;
2016-07-06 17:28:52 -04:00
count + = nread ;
addr + = nread ;
2015-07-30 15:17:43 -04:00
}
if ( ret < 0 )
return ret ;
return count ;
}
2016-03-05 08:50:06 -08:00
/*
* Perform a stand - alone single QSFP read . Acquire the resource , do the
* read , then release the resource .
*/
int one_qsfp_read ( struct hfi1_pportdata * ppd , u32 target , int addr , void * bp ,
int len )
{
struct hfi1_devdata * dd = ppd - > dd ;
u32 resource = qsfp_resource ( dd ) ;
int ret ;
ret = acquire_chip_resource ( dd , resource , QSFP_WAIT ) ;
if ( ret )
return ret ;
ret = qsfp_read ( ppd , target , addr , bp , len ) ;
release_chip_resource ( dd , resource ) ;
return ret ;
}
2015-07-30 15:17:43 -04:00
/*
* This function caches the QSFP memory range in 128 byte chunks .
* As an example , the next byte after address 255 is byte 128 from
* upper page 01 H ( if existing ) rather than byte 0 from lower page 00 H .
2016-02-03 14:31:05 -08:00
* Access page n , offset m of QSFP memory as defined by SFF 8636
* in the cache by reading byte ( ( 128 * n ) + m )
* The calls to qsfp_ { read , write } in this function correctly handle the
* address map difference between this mapping and the mapping implemented
* by those functions
2016-04-12 11:28:36 -07:00
*
* The caller must be holding the QSFP i2c chain resource .
2015-07-30 15:17:43 -04:00
*/
int refresh_qsfp_cache ( struct hfi1_pportdata * ppd , struct qsfp_data * cp )
{
u32 target = ppd - > dd - > hfi1_id ;
int ret ;
unsigned long flags ;
u8 * cache = & cp - > cache [ 0 ] ;
/* ensure sane contents on invalid reads, for cable swaps */
2016-02-14 20:19:24 -08:00
memset ( cache , 0 , ( QSFP_MAX_NUM_PAGES * 128 ) ) ;
2016-02-03 14:31:05 -08:00
spin_lock_irqsave ( & ppd - > qsfp_info . qsfp_lock , flags ) ;
ppd - > qsfp_info . cache_valid = 0 ;
spin_unlock_irqrestore ( & ppd - > qsfp_info . qsfp_lock , flags ) ;
2015-07-30 15:17:43 -04:00
if ( ! qsfp_mod_present ( ppd ) ) {
ret = - ENODEV ;
2016-04-12 11:28:36 -07:00
goto bail ;
2015-07-30 15:17:43 -04:00
}
2016-02-03 14:31:05 -08:00
ret = qsfp_read ( ppd , target , 0 , cache , QSFP_PAGESIZE ) ;
if ( ret ! = QSFP_PAGESIZE ) {
2015-07-30 15:17:43 -04:00
dd_dev_info ( ppd - > dd ,
2016-02-03 14:31:05 -08:00
" %s: Page 0 read failed, expected %d, got %d \n " ,
__func__ , QSFP_PAGESIZE , ret ) ;
2015-07-30 15:17:43 -04:00
goto bail ;
}
/* Is paging enabled? */
if ( ! ( cache [ 2 ] & 4 ) ) {
/* Paging enabled, page 03 required */
if ( ( cache [ 195 ] & 0xC0 ) = = 0xC0 ) {
/* all */
ret = qsfp_read ( ppd , target , 384 , cache + 256 , 128 ) ;
if ( ret < = 0 | | ret ! = 128 ) {
2016-02-03 14:30:57 -08:00
dd_dev_info ( ppd - > dd , " %s failed \n " , __func__ ) ;
2015-07-30 15:17:43 -04:00
goto bail ;
}
ret = qsfp_read ( ppd , target , 640 , cache + 384 , 128 ) ;
if ( ret < = 0 | | ret ! = 128 ) {
2016-02-03 14:30:57 -08:00
dd_dev_info ( ppd - > dd , " %s failed \n " , __func__ ) ;
2015-07-30 15:17:43 -04:00
goto bail ;
}
ret = qsfp_read ( ppd , target , 896 , cache + 512 , 128 ) ;
if ( ret < = 0 | | ret ! = 128 ) {
2016-02-03 14:30:57 -08:00
dd_dev_info ( ppd - > dd , " %s failed \n " , __func__ ) ;
2015-07-30 15:17:43 -04:00
goto bail ;
}
} else if ( ( cache [ 195 ] & 0x80 ) = = 0x80 ) {
/* only page 2 and 3 */
ret = qsfp_read ( ppd , target , 640 , cache + 384 , 128 ) ;
if ( ret < = 0 | | ret ! = 128 ) {
2016-02-03 14:30:57 -08:00
dd_dev_info ( ppd - > dd , " %s failed \n " , __func__ ) ;
2015-07-30 15:17:43 -04:00
goto bail ;
}
ret = qsfp_read ( ppd , target , 896 , cache + 512 , 128 ) ;
if ( ret < = 0 | | ret ! = 128 ) {
2016-02-03 14:30:57 -08:00
dd_dev_info ( ppd - > dd , " %s failed \n " , __func__ ) ;
2015-07-30 15:17:43 -04:00
goto bail ;
}
} else if ( ( cache [ 195 ] & 0x40 ) = = 0x40 ) {
/* only page 1 and 3 */
ret = qsfp_read ( ppd , target , 384 , cache + 256 , 128 ) ;
if ( ret < = 0 | | ret ! = 128 ) {
2016-02-03 14:30:57 -08:00
dd_dev_info ( ppd - > dd , " %s failed \n " , __func__ ) ;
2015-07-30 15:17:43 -04:00
goto bail ;
}
ret = qsfp_read ( ppd , target , 896 , cache + 512 , 128 ) ;
if ( ret < = 0 | | ret ! = 128 ) {
2016-02-03 14:30:57 -08:00
dd_dev_info ( ppd - > dd , " %s failed \n " , __func__ ) ;
2015-07-30 15:17:43 -04:00
goto bail ;
}
} else {
/* only page 3 */
ret = qsfp_read ( ppd , target , 896 , cache + 512 , 128 ) ;
if ( ret < = 0 | | ret ! = 128 ) {
2016-02-03 14:30:57 -08:00
dd_dev_info ( ppd - > dd , " %s failed \n " , __func__ ) ;
2015-07-30 15:17:43 -04:00
goto bail ;
}
}
}
spin_lock_irqsave ( & ppd - > qsfp_info . qsfp_lock , flags ) ;
ppd - > qsfp_info . cache_valid = 1 ;
ppd - > qsfp_info . cache_refresh_required = 0 ;
spin_unlock_irqrestore ( & ppd - > qsfp_info . qsfp_lock , flags ) ;
return 0 ;
bail :
2016-02-14 20:19:24 -08:00
memset ( cache , 0 , ( QSFP_MAX_NUM_PAGES * 128 ) ) ;
2015-07-30 15:17:43 -04:00
return ret ;
}
const char * const hfi1_qsfp_devtech [ 16 ] = {
" 850nm VCSEL " , " 1310nm VCSEL " , " 1550nm VCSEL " , " 1310nm FP " ,
" 1310nm DFB " , " 1550nm DFB " , " 1310nm EML " , " 1550nm EML " ,
" Cu Misc " , " 1490nm DFB " , " Cu NoEq " , " Cu Eq " ,
" Undef " , " Cu Active BothEq " , " Cu FarEq " , " Cu NearEq "
} ;
# define QSFP_DUMP_CHUNK 16 /* Holds longest string */
# define QSFP_DEFAULT_HDR_CNT 224
2016-04-12 11:25:31 -07:00
# define QSFP_PWR(pbyte) (((pbyte) >> 6) & 3)
# define QSFP_HIGH_PWR(pbyte) ((pbyte) & 3)
/* For use with QSFP_HIGH_PWR macro */
# define QSFP_HIGH_PWR_UNUSED 0 /* Bits [1:0] = 00 implies low power module */
/*
* Takes power class byte [ Page 00 Byte 129 ] in SFF 8636
* Returns power class as integer ( 1 through 7 , per SFF 8636 rev 2.4 )
*/
int get_qsfp_power_class ( u8 power_byte )
{
if ( QSFP_HIGH_PWR ( power_byte ) = = QSFP_HIGH_PWR_UNUSED )
/* power classes count from 1, their bit encodings from 0 */
return ( QSFP_PWR ( power_byte ) + 1 ) ;
/*
* 00 in the high power classes stands for unused , bringing
* balance to the off - by - 1 offset above , we add 4 here to
* account for the difference between the low and high power
* groups
*/
return ( QSFP_HIGH_PWR ( power_byte ) + 4 ) ;
}
2015-07-30 15:17:43 -04:00
int qsfp_mod_present ( struct hfi1_pportdata * ppd )
{
2015-10-26 10:28:31 -04:00
struct hfi1_devdata * dd = ppd - > dd ;
u64 reg ;
2015-07-30 15:17:43 -04:00
2015-10-26 10:28:31 -04:00
reg = read_csr ( dd , dd - > hfi1_id ? ASIC_QSFP2_IN : ASIC_QSFP1_IN ) ;
return ! ( reg & QSFP_HFI0_MODPRST_N ) ;
2015-07-30 15:17:43 -04:00
}
/*
* This function maps QSFP memory addresses in 128 byte chunks in the following
* fashion per the CableInfo SMA query definition in the IBA 1.3 spec / OPA Gen 1
* spec
* For addr 000 - 127 , lower page 00 h
* For addr 128 - 255 , upper page 00 h
* For addr 256 - 383 , upper page 01 h
* For addr 384 - 511 , upper page 02 h
* For addr 512 - 639 , upper page 03 h
*
* For addresses beyond this range , it returns the invalid range of data buffer
* set to 0.
* For upper pages that are optional , if they are not valid , returns the
* particular range of bytes in the data buffer set to 0.
*/
int get_cable_info ( struct hfi1_devdata * dd , u32 port_num , u32 addr , u32 len ,
u8 * data )
{
struct hfi1_pportdata * ppd ;
2016-08-09 11:17:18 -04:00
u32 excess_len = len ;
int ret = 0 , offset = 0 ;
2015-07-30 15:17:43 -04:00
if ( port_num > dd - > num_pports | | port_num < 1 ) {
dd_dev_info ( dd , " %s: Invalid port number %d \n " ,
2016-02-14 20:21:52 -08:00
__func__ , port_num ) ;
2015-07-30 15:17:43 -04:00
ret = - EINVAL ;
goto set_zeroes ;
}
ppd = dd - > pport + ( port_num - 1 ) ;
if ( ! qsfp_mod_present ( ppd ) ) {
ret = - ENODEV ;
goto set_zeroes ;
}
if ( ! ppd - > qsfp_info . cache_valid ) {
ret = - EINVAL ;
goto set_zeroes ;
}
if ( addr > = ( QSFP_MAX_NUM_PAGES * 128 ) ) {
ret = - ERANGE ;
goto set_zeroes ;
}
if ( ( addr + len ) > ( QSFP_MAX_NUM_PAGES * 128 ) ) {
excess_len = ( addr + len ) - ( QSFP_MAX_NUM_PAGES * 128 ) ;
memcpy ( data , & ppd - > qsfp_info . cache [ addr ] , ( len - excess_len ) ) ;
data + = ( len - excess_len ) ;
goto set_zeroes ;
}
memcpy ( data , & ppd - > qsfp_info . cache [ addr ] , len ) ;
2016-08-09 11:17:18 -04:00
if ( addr < = QSFP_MONITOR_VAL_END & &
( addr + len ) > = QSFP_MONITOR_VAL_START ) {
/* Overlap with the dynamic channel monitor range */
if ( addr < QSFP_MONITOR_VAL_START ) {
if ( addr + len < = QSFP_MONITOR_VAL_END )
len = addr + len - QSFP_MONITOR_VAL_START ;
else
len = QSFP_MONITOR_RANGE ;
offset = QSFP_MONITOR_VAL_START - addr ;
addr = QSFP_MONITOR_VAL_START ;
} else if ( addr = = QSFP_MONITOR_VAL_START ) {
offset = 0 ;
if ( addr + len > QSFP_MONITOR_VAL_END )
len = QSFP_MONITOR_RANGE ;
} else {
offset = 0 ;
if ( addr + len > QSFP_MONITOR_VAL_END )
len = QSFP_MONITOR_VAL_END - addr + 1 ;
}
/* Refresh the values of the dynamic monitors from the cable */
ret = one_qsfp_read ( ppd , dd - > hfi1_id , addr , data + offset , len ) ;
if ( ret ! = len ) {
ret = - EAGAIN ;
goto set_zeroes ;
}
}
2015-07-30 15:17:43 -04:00
return 0 ;
set_zeroes :
memset ( data , 0 , excess_len ) ;
return ret ;
}
2016-04-12 11:25:31 -07:00
static const char * pwr_codes [ 8 ] = { " N/AW " ,
" 1.5W " ,
" 2.0W " ,
" 2.5W " ,
" 3.5W " ,
" 4.0W " ,
" 4.5W " ,
" 5.0W "
} ;
2015-07-30 15:17:43 -04:00
int qsfp_dump ( struct hfi1_pportdata * ppd , char * buf , int len )
{
u8 * cache = & ppd - > qsfp_info . cache [ 0 ] ;
u8 bin_buff [ QSFP_DUMP_CHUNK ] ;
char lenstr [ 6 ] ;
2015-10-29 13:35:06 +05:30
int sofar ;
2015-07-30 15:17:43 -04:00
int bidx = 0 ;
u8 * atten = & cache [ QSFP_ATTEN_OFFS ] ;
u8 * vendor_oui = & cache [ QSFP_VOUI_OFFS ] ;
2016-04-12 11:25:31 -07:00
u8 power_byte = 0 ;
2015-07-30 15:17:43 -04:00
sofar = 0 ;
lenstr [ 0 ] = ' ' ;
lenstr [ 1 ] = ' \0 ' ;
if ( ppd - > qsfp_info . cache_valid ) {
if ( QSFP_IS_CU ( cache [ QSFP_MOD_TECH_OFFS ] ) )
2016-06-09 07:51:51 -07:00
snprintf ( lenstr , sizeof ( lenstr ) , " %dM " ,
cache [ QSFP_MOD_LEN_OFFS ] ) ;
2015-07-30 15:17:43 -04:00
2016-04-12 11:25:31 -07:00
power_byte = cache [ QSFP_MOD_PWR_OFFS ] ;
2015-07-30 15:17:43 -04:00
sofar + = scnprintf ( buf + sofar , len - sofar , " PWR:%.3sW \n " ,
2016-04-12 11:25:31 -07:00
pwr_codes [ get_qsfp_power_class ( power_byte ) ] ) ;
2015-07-30 15:17:43 -04:00
sofar + = scnprintf ( buf + sofar , len - sofar , " TECH:%s%s \n " ,
lenstr ,
hfi1_qsfp_devtech [ ( cache [ QSFP_MOD_TECH_OFFS ] ) > > 4 ] ) ;
sofar + = scnprintf ( buf + sofar , len - sofar , " Vendor:%.*s \n " ,
QSFP_VEND_LEN , & cache [ QSFP_VEND_OFFS ] ) ;
sofar + = scnprintf ( buf + sofar , len - sofar , " OUI:%06X \n " ,
QSFP_OUI ( vendor_oui ) ) ;
sofar + = scnprintf ( buf + sofar , len - sofar , " Part#:%.*s \n " ,
QSFP_PN_LEN , & cache [ QSFP_PN_OFFS ] ) ;
sofar + = scnprintf ( buf + sofar , len - sofar , " Rev:%.*s \n " ,
QSFP_REV_LEN , & cache [ QSFP_REV_OFFS ] ) ;
if ( QSFP_IS_CU ( cache [ QSFP_MOD_TECH_OFFS ] ) )
sofar + = scnprintf ( buf + sofar , len - sofar ,
" Atten:%d, %d \n " ,
QSFP_ATTEN_SDR ( atten ) ,
QSFP_ATTEN_DDR ( atten ) ) ;
sofar + = scnprintf ( buf + sofar , len - sofar , " Serial:%.*s \n " ,
QSFP_SN_LEN , & cache [ QSFP_SN_OFFS ] ) ;
sofar + = scnprintf ( buf + sofar , len - sofar , " Date:%.*s \n " ,
QSFP_DATE_LEN , & cache [ QSFP_DATE_OFFS ] ) ;
sofar + = scnprintf ( buf + sofar , len - sofar , " Lot:%.*s \n " ,
QSFP_LOT_LEN , & cache [ QSFP_LOT_OFFS ] ) ;
while ( bidx < QSFP_DEFAULT_HDR_CNT ) {
int iidx ;
memcpy ( bin_buff , & cache [ bidx ] , QSFP_DUMP_CHUNK ) ;
for ( iidx = 0 ; iidx < QSFP_DUMP_CHUNK ; + + iidx ) {
2016-02-14 20:19:24 -08:00
sofar + = scnprintf ( buf + sofar , len - sofar ,
2015-07-30 15:17:43 -04:00
" %02X " , bin_buff [ iidx ] ) ;
}
sofar + = scnprintf ( buf + sofar , len - sofar , " \n " ) ;
bidx + = QSFP_DUMP_CHUNK ;
}
}
2015-10-29 13:35:06 +05:30
return sofar ;
2015-07-30 15:17:43 -04:00
}