#include "lm5710.h"
u32_t
init_nwuf_57710(
lm_device_t *pdev,
lm_nwuf_list_t *nwuf_list)
{
lm_nwuf_t* nwuf = NULL ;
u32_t nwuf_cnt = 0 ;
u32_t offset = 0 ;
u8_t mask = 0 ;
u32_t val = 0 ;
u64_t val_64 = 0 ;
u32_t val_32[2] = {0} ;
u32_t mod = 0 ;
u32_t idx = 0 ;
u32_t bit = 0 ;
u32_t reg_len = 0 ;
u32_t reg_crc = 0 ;
u32_t reg_be = 0 ;
u32_t reg_offset = 0 ;
if CHK_NULL(pdev)
{
return 0 ;
}
ASSERT_STATIC(LM_NWUF_PATTERN_SIZE <= 128 );
for(idx = 0; idx < LM_MAX_NWUF_CNT; idx++)
{
nwuf = &nwuf_list->nwuf_arr[idx];
#define LM_NIG_ACPI_PAT_LEN_IDX(_func,_idx) NIG_REG_LLH##_func##_ACPI_PAT_##_idx##_LEN
#define LM_NIG_ACPI_PAT_CRC_IDX(_func,_idx) NIG_REG_LLH##_func##_ACPI_PAT_##_idx##_CRC
switch( idx )
{
case 0:
reg_len = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_LEN_IDX(0,0) : LM_NIG_ACPI_PAT_LEN_IDX(1,0) ;
reg_crc = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_CRC_IDX(0,0) : LM_NIG_ACPI_PAT_CRC_IDX(1,0) ;
break;
case 1:
reg_len = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_LEN_IDX(0,1) : LM_NIG_ACPI_PAT_LEN_IDX(1,1) ;
reg_crc = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_CRC_IDX(0,1) : LM_NIG_ACPI_PAT_CRC_IDX(1,1) ;
break;
case 2:
reg_len = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_LEN_IDX(0,2) : LM_NIG_ACPI_PAT_LEN_IDX(1,2) ;
reg_crc = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_CRC_IDX(0,2) : LM_NIG_ACPI_PAT_CRC_IDX(1,2) ;
break;
case 3:
reg_len = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_LEN_IDX(0,3) : LM_NIG_ACPI_PAT_LEN_IDX(1,3) ;
reg_crc = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_CRC_IDX(0,3) : LM_NIG_ACPI_PAT_CRC_IDX(1,3) ;
break;
case 4:
reg_len = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_LEN_IDX(0,4) : LM_NIG_ACPI_PAT_LEN_IDX(1,4) ;
reg_crc = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_CRC_IDX(0,4) : LM_NIG_ACPI_PAT_CRC_IDX(1,4) ;
break;
case 5:
reg_len = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_LEN_IDX(0,5) : LM_NIG_ACPI_PAT_LEN_IDX(1,5) ;
reg_crc = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_CRC_IDX(0,5) : LM_NIG_ACPI_PAT_CRC_IDX(1,5) ;
break;
case 6:
reg_len = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_LEN_IDX(0,6) : LM_NIG_ACPI_PAT_LEN_IDX(1,6) ;
reg_crc = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_CRC_IDX(0,6) : LM_NIG_ACPI_PAT_CRC_IDX(1,6) ;
break;
case 7:
reg_len = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_LEN_IDX(0,7) : LM_NIG_ACPI_PAT_LEN_IDX(1,7) ;
reg_crc = (0 == PORT_ID(pdev)) ? LM_NIG_ACPI_PAT_CRC_IDX(0,7) : LM_NIG_ACPI_PAT_CRC_IDX(1,7) ;
break;
default:
DbgBreakMsg("Invalid index\n") ;
return 0 ;
}
val = nwuf->pattern_size;
DbgMessage(pdev, VERBOSE, "init_nwuf_57710: idx[%d] crc_mask=0x%08x size=%d\n", idx, nwuf->crc32, val );
#if !(defined(DOS) || defined(__LINUX))
if (0)
{
val = min( nwuf->size * 8, 64 ) ;
if( val != nwuf->size * 8 )
{
DbgMessage(pdev, WARN, "init_nwuf_57710: idx[%d] Updated size=%03d-->%03d\n", idx, nwuf->size * 8, val ) ;
}
}
#endif
REG_WR( pdev, reg_len, val ) ;
val = nwuf->crc32 ;
REG_WR( pdev, reg_crc, val ) ;
}
reg_be = (0 == PORT_ID(pdev)) ? NIG_REG_LLH0_ACPI_BE_MEM_DATA : NIG_REG_LLH1_ACPI_BE_MEM_DATA ;
for(offset = 0; offset <= LM_NWUF_PATTERN_SIZE; offset++)
{
mod = offset%8 ;
if ( ( 0 == mod ) && ( offset!= 0 ) )
{
reg_offset = ( offset / 8 ) - 1 ;
val = (reg_offset*sizeof(u64_t)) ;
if( 0 )
{
REG_WR_DMAE( pdev, reg_be+val, &val_64 ) ;
}
else
{
val_32[0] = U64_LO(val_64);
val_32[1] = U64_HI(val_64);
REG_WR_IND( pdev, reg_be+val, val_32[0] ) ;
REG_WR_IND( pdev, reg_be+val+4, val_32[1] ) ;
}
val_64 = 0 ;
}
if( LM_NWUF_PATTERN_SIZE == offset )
{
break ;
}
for(idx = 0; idx < LM_MAX_NWUF_CNT; idx++)
{
nwuf = &nwuf_list->nwuf_arr[idx];
if(nwuf->size == 0 || offset > nwuf->size * 8)
{
continue;
}
mask = nwuf->mask[(offset/8)];
bit = mod ;
if( mask & (1 << bit) )
{
val_64 |= 0x1ULL << idx;
}
}
if( mod != 7 )
{
val_64 = val_64 << 8 ;
}
}
nwuf_cnt = 0;
for(idx = 0; idx < LM_MAX_NWUF_CNT; idx++)
{
nwuf = &nwuf_list->nwuf_arr[idx];
if(nwuf->size == 0)
{
continue;
}
nwuf_cnt++ ;
}
return nwuf_cnt;
}
void lm_set_d3_nwuf( lm_device_t* pdev,
const lm_wake_up_mode_t wake_up_mode )
{
const u8_t port_id = PORT_ID(pdev);
u8_t abs_func_id = ABS_FUNC_ID(pdev);
u8_t nwuf_reg_value = 0 ;
u32_t cnt = 0 ;
u32_t offset = 0;
UNREFERENCED_PARAMETER_( abs_func_id );
if ( 0 != GET_FLAGS(wake_up_mode, LM_WAKE_UP_MODE_NWUF) )
{
if( (cnt = init_nwuf_57710(pdev, &pdev->nwuf_list)) )
{
DbgMessage(pdev, WARN, "LM_WAKE_UP_MODE_NWUF is ON cnt=%d\n", cnt );
nwuf_reg_value = 1 ;
}
else
{
DbgMessage(pdev, WARN , "LM_WAKE_UP_MODE_NWUF is ON cnt=0\n" );
nwuf_reg_value = 0 ;
}
offset = (0 == port_id) ? NIG_REG_LLH0_ACPI_ENABLE :NIG_REG_LLH1_ACPI_ENABLE;
REG_WR( pdev, offset, nwuf_reg_value ) ;
if( !CHIP_IS_E1(pdev) )
{
lm_set_func_en(pdev, TRUE);
if ( !CHIP_IS_E1x(pdev) &&
nwuf_reg_value &&
( IS_MF_SI_MODE(pdev) ) )
{
DbgBreakIf( CHIP_IS_E1(pdev) );
DbgBreakIf( !nwuf_reg_value );
offset = (0 == port_id) ? NIG_REG_P0_ACPI_MF_GLOBAL_EN :NIG_REG_P1_ACPI_MF_GLOBAL_EN;
REG_WR( pdev, offset, nwuf_reg_value ) ;
}
}
DbgMessage(pdev, WARN, "ACPI_ENABLE=%d\n", nwuf_reg_value );
}
else
{
DbgMessage(pdev, WARN , "LM_WAKE_UP_MODE_NWUF is OFF\n" );
}
}
void lm_set_d3_mpkt( lm_device_t* pdev,
const lm_wake_up_mode_t wake_up_mode )
{
u32_t emac_base = 0 ;
u32_t val = 0 ;
u32_t offset = 0 ;
u8_t const b_enable_mpkt = ( 0 != GET_FLAGS(wake_up_mode, LM_WAKE_UP_MODE_MAGIC_PACKET) );
u8_t* mac_addr = &pdev->params.mac_addr[0];
if CHK_NULL(pdev)
{
DbgBreakIf(!pdev) ;
return;
}
if( b_enable_mpkt )
{
DbgMessage(pdev, WARN , "LM_WAKE_UP_MODE_MAGIC_PACKET is ON\n" );
}
else
{
DbgMessage(pdev, WARN , "LM_WAKE_UP_MODE_MAGIC_PACKET is OFF\n" );
}
emac_base = ( 0 == PORT_ID(pdev) ) ? GRCBASE_EMAC0 : GRCBASE_EMAC1 ;
val = (mac_addr[0] << 8) | mac_addr[1];
offset = EMAC_REG_EMAC_MAC_MATCH + (VNIC_ID(pdev)+ 1)*8 ;
REG_WR(pdev, emac_base+ offset , b_enable_mpkt ? val:0);
val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
(mac_addr[4] << 8) | mac_addr[5];
offset+= 4;
REG_WR(pdev, emac_base+ offset, b_enable_mpkt ? val:0);
}
STATIC void
set_d0_power_state(
lm_device_t *pdev,
u8_t set_pci_pm)
{
u32_t idx = 0;
UNREFERENCED_PARAMETER_(set_pci_pm);
DbgMessage(pdev, INFORM, "### set_d0_power_state\n");
#if 0
u32_t val;
if(set_pci_pm)
{
mm_read_pci(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_pm_csr),
&val);
val &= ~PCICFG_PM_CSR_STATE;
val |= PCICFG_PM_CSR_STATE_D0 | PCICFG_PM_CSR_PME_STATUS;
mm_write_pci(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_pm_csr),
val);
}
#endif
if(CHIP_ID(pdev) == CHIP_ID_5706_A1)
{
for(idx = 0; idx < 1000; idx++)
{
mm_wait(pdev, 15);
}
}
#if 0
val = REG_RD(pdev, emac.emac_mode);
val |= EMAC_MODE_MPKT_RCVD | EMAC_MODE_ACPI_RCVD;
val &= ~EMAC_MODE_MPKT;
REG_WR(pdev, emac.emac_mode, val);
val = REG_RD(pdev, rpm.rpm_config);
val &= ~RPM_CONFIG_ACPI_ENA;
REG_WR(pdev, rpm.rpm_config, val);
#endif
}
void
lm_set_power_state(
lm_device_t* pdev,
lm_power_state_t power_state,
lm_wake_up_mode_t wake_up_mode,
u8_t set_pci_pm )
{
UNREFERENCED_PARAMETER_(wake_up_mode);
switch( power_state )
{
case LM_POWER_STATE_D0:
set_d0_power_state(pdev, set_pci_pm);
break;
default:
break;
}
}
void lm_set_func_en(struct _lm_device_t *pdev, const u8_t b_enable)
{
const u8_t bus_num = INST_ID_TO_BUS_NUM(PFDEV(pdev)->vars.inst_id) ;
if (pdev->params.pfunc_abs < ARRSIZE(g_lm_chip_global[0].func_en))
{
g_lm_chip_global[bus_num].func_en[pdev->params.pfunc_abs] = b_enable;
}
}
u8_t lm_get_func_en(struct _lm_device_t *pdev, const u8_t pfunc_abs)
{
const u8_t bus_num = INST_ID_TO_BUS_NUM(PFDEV(pdev)->vars.inst_id) ;
if (pfunc_abs < ARRSIZE(g_lm_chip_global[0].func_en))
{
return g_lm_chip_global[bus_num].func_en[pfunc_abs];
}
return 0;
}
#define DEFINITIVE_PF_FOR_MPS 0
void lm_pcie_state_save_for_d3(struct _lm_device_t *pdev)
{
static const u32_t pcicfg_device_control_offset = PCICFG_OFFSET + PCICFG_DEVICE_CONTROL;
static const u32_t PCICFG_DEVICE_CONTROL_MPS_MASK = 0x000000E0;
const u8_t abs_func_id = ABS_FUNC_ID(pdev);
u32_t pf0_pcie_status_control = 0;
if (DEFINITIVE_PF_FOR_MPS != abs_func_id)
{
lm_pretend_func(pdev, DEFINITIVE_PF_FOR_MPS);
pf0_pcie_status_control = REG_RD(pdev, pcicfg_device_control_offset);
pdev->hw_info.saved_pf0_pcie_mps = GET_FLAGS(pf0_pcie_status_control, PCICFG_DEVICE_CONTROL_MPS_MASK);
lm_pretend_func(pdev, abs_func_id);
}
}
void lm_pcie_state_restore_for_d0(struct _lm_device_t *pdev)
{
static const u32_t pcicfg_device_control_offset = PCICFG_OFFSET + PCICFG_DEVICE_CONTROL;
static const u32_t PCICFG_DEVICE_CONTROL_MPS_MASK = 0x000000E0;
const u8_t abs_func_id = ABS_FUNC_ID(pdev);
u32_t pf0_pcie_status_control = 0;
u32_t pf0_mps = 0;
u32_t own_pcie_status_control = REG_RD(pdev, pcicfg_device_control_offset);
u32_t own_mps = GET_FLAGS(own_pcie_status_control, PCICFG_DEVICE_CONTROL_MPS_MASK);
if((DEFINITIVE_PF_FOR_MPS != ABS_FUNC_ID(pdev)) &&
(INVALID_MPS != pdev->hw_info.saved_pf0_pcie_mps))
{
lm_pretend_func(pdev, DEFINITIVE_PF_FOR_MPS);
pf0_pcie_status_control = REG_RD(pdev, pcicfg_device_control_offset);
pf0_mps = GET_FLAGS(pf0_pcie_status_control, PCICFG_DEVICE_CONTROL_MPS_MASK);
if ( ( pf0_mps != pdev->hw_info.saved_pf0_pcie_mps) &&
( pf0_mps != own_mps) )
{
RESET_FLAGS(pf0_pcie_status_control, PCICFG_DEVICE_CONTROL_MPS_MASK);
SET_FLAGS(pf0_pcie_status_control, pdev->hw_info.saved_pf0_pcie_mps);
REG_WR(pdev, pcicfg_device_control_offset, pf0_pcie_status_control);
++pdev->debug_info.pf0_mps_overwrite;
}
lm_pretend_func(pdev, abs_func_id);
}
}
static lm_nwuf_t * find_nwuf( lm_nwuf_list_t* nwuf_list,
u32_t mask_size,
u8_t* byte_mask,
u8_t* pattern )
{
lm_nwuf_t *nwuf;
u8_t found;
u32_t idx;
u32_t j;
u32_t k;
ASSERT_STATIC(LM_MAX_NWUF_CNT==8);
for(idx = 0; idx < LM_MAX_NWUF_CNT; idx++)
{
nwuf = &nwuf_list->nwuf_arr[idx];
if(nwuf->size != mask_size)
{
continue;
}
found = TRUE;
for(j = 0; j < mask_size && found == TRUE; j++)
{
if(nwuf->mask[j] != byte_mask[j])
{
found = FALSE;
break;
}
for(k = 0; k < 8; k++)
{
if((byte_mask[j] & (1 << k)) &&
(nwuf->pattern[j*8 + k] != pattern[j*8 + k]))
{
found = FALSE;
break;
}
}
}
if(found)
{
return nwuf;
}
}
return NULL;
}
lm_status_t lm_add_nwuf( lm_device_t* pdev,
u32_t mask_size,
u8_t* byte_mask,
u8_t* pattern )
{
lm_nwuf_t* nwuf = NULL ;
u32_t idx = 0 ;
u32_t j = 0 ;
u32_t k = 0 ;
u32_t zero_serial = 0 ;
if( ERR_IF(0 == mask_size) || ERR_IF( mask_size > LM_NWUF_PATTERN_MASK_SIZE ) )
{
DbgBreakMsg("Invalid byte mask size\n");
return LM_STATUS_FAILURE;
}
nwuf = find_nwuf(&pdev->nwuf_list, mask_size, byte_mask, pattern);
if( NULL != nwuf )
{
DbgMessage(pdev, WARN, "Duplicated nwuf entry.\n");
return LM_STATUS_EXISTING_OBJECT;
}
nwuf = NULL;
for(idx = 0; idx < LM_MAX_NWUF_CNT; idx++)
{
if(pdev->nwuf_list.nwuf_arr[idx].size == 0)
{
nwuf = &pdev->nwuf_list.nwuf_arr[idx] ;
break;
}
}
if( NULL == nwuf )
{
DbgMessage(pdev, WARN, "Cannot add Nwuf, exceeded maximum.\n");
return LM_STATUS_RESOURCE;
}
pdev->nwuf_list.cnt++;
nwuf->size = mask_size;
for(j = 0; j < mask_size; j++)
{
nwuf->mask[j] = byte_mask[j];
for(k = 0; k < 8; k++)
{
if(byte_mask[j] & (1 << k))
{
nwuf->pattern[j*8 + k] = pattern[j*8 + k];
zero_serial = 0;
}
else
{
nwuf->pattern[j*8 + k] = 0;
++zero_serial;
}
}
}
nwuf->pattern_size = mask_size*8 - zero_serial ;
j = nwuf->pattern_size/8 ;
if( nwuf->pattern_size % 8 )
{
j++;
}
j*= 8;
nwuf->crc32 = calc_crc32( nwuf->pattern, j, 0xffffffff , 1 ) ;
#define WOL_DBG_PRINT 0
#if (WOL_DBG_PRINT)
{
printk("lm_add_nwuf: pattern[%u] mask_size=%03u pattern_size=%03u (%03u) crc calc size=%03u\n",
idx,
nwuf->size,
nwuf->pattern_size,
nwuf->size*8,
j );
printk("pattern[%u] CRC=0x%08x\n",idx, nwuf->crc32 ) ;
for( idx = 0 ; idx < nwuf->size*8 ; idx++ )
{
printk("%02X", pattern[idx] ) ;
if( idx != nwuf->size*8-1 )
{
printk("-") ;
}
if( ( 0!= idx ) && 0 == ( idx % 32 ) )
{
printk("\n") ;
}
}
printk("\nPattern (masked):\n");
for( idx = 0 ; idx < nwuf->size*8 ; idx++ )
{
printk("%02X", nwuf->pattern[idx] ) ;
if( idx != nwuf->size*8-1 )
{
printk("-") ;
}
if( ( 0!= idx ) && 0 == ( idx % 32 ) )
{
printk("\n") ;
}
}
printk("\nmask (size=%03u)\n", nwuf->size) ;
for( idx = 0 ; idx < nwuf->size ; idx++ )
{
printk("%02X", byte_mask[idx] ) ;
if( idx != nwuf->size-1 )
{
printk("-") ;
}
}
printk("\n") ;
}
#endif
if ERR_IF( 0xffffffff == nwuf->crc32 )
{
DbgBreakMsg("Invalid crc32\n") ;
}
return LM_STATUS_SUCCESS;
}
lm_status_t lm_del_nwuf( lm_device_t* pdev,
u32_t mask_size,
u8_t* byte_mask,
u8_t * pattern )
{
lm_nwuf_t *nwuf;
u32_t k;
if(mask_size == 0 || mask_size > LM_NWUF_PATTERN_MASK_SIZE)
{
DbgBreakMsg("Invalid byte mask size\n");
return LM_STATUS_FAILURE;
}
nwuf = find_nwuf(&pdev->nwuf_list, mask_size, byte_mask, pattern);
if(nwuf)
{
nwuf->size = 0;
nwuf->crc32 = 0 ;
for(k = 0; k < LM_NWUF_PATTERN_MASK_SIZE; k++)
{
nwuf->mask[k] = 0;
}
for(k = 0; k < LM_NWUF_PATTERN_SIZE; k++)
{
nwuf->pattern[k] = 0xff;
}
pdev->nwuf_list.cnt--;
}
else
{
DbgMessage(pdev, WARN, "not exists nwuf entry. mask_size=%03d\n", mask_size );
return LM_STATUS_OBJECT_NOT_FOUND;
}
return LM_STATUS_SUCCESS;
}
void
lm_clear_nwuf(
lm_device_t *pdev)
{
u32_t j;
u32_t k;
for(j = 0; j < LM_MAX_NWUF_CNT; j++)
{
pdev->nwuf_list.nwuf_arr[j].size = 0;
for(k = 0; k < LM_NWUF_PATTERN_MASK_SIZE; k++)
{
pdev->nwuf_list.nwuf_arr[j].mask[k] = 0;
}
for(k = 0; k < LM_NWUF_PATTERN_SIZE; k++)
{
pdev->nwuf_list.nwuf_arr[j].pattern[k] = 0xff;
}
}
pdev->nwuf_list.cnt = 0;
}