#include "lm5706.h"
#if !defined(LINUX) && !defined(SOLARIS)
#include "string.h"
#pragma warning(disable:28718)
#endif
void
lm_abort(
lm_device_t *pdev,
u32_t abort_op,
u32_t idx)
{
if(abort_op == ABORT_OP_RX_CHAIN)
{
lm_recv_abort(pdev, idx);
}
else if(abort_op == ABORT_OP_TX_CHAIN)
{
lm_send_abort(pdev, idx);
}
else
{
DbgBreakMsg("Invalid abort.\n");
}
}
STATIC char *
val_to_decimal_string(
char *str_buf,
u32_t buf_size,
u32_t val)
{
u32_t digit;
if(buf_size == 0)
{
return str_buf;
}
digit = val % 10;
val = val / 10;
if(val)
{
buf_size--;
str_buf = val_to_decimal_string(str_buf, buf_size, val);
}
*str_buf = '0' + digit;
str_buf++;
return str_buf;
}
STATIC u32_t
build_ver_string(
char *str_buf,
u32_t buf_size,
u8_t major_ver,
u8_t minor_ver,
u8_t rel_num,
u8_t fix_num)
{
char *p;
if(buf_size == 0)
{
return 0;
}
p = str_buf;
if(buf_size - (p - str_buf) > 1)
{
*p = 'v';
p++;
}
if(buf_size - (p - str_buf) > 1)
{
p = val_to_decimal_string(
p,
buf_size - (u32_t) PTR_SUB(p, str_buf),
major_ver);
}
if(buf_size - (p - str_buf) > 1)
{
*p = '.';
p++;
}
if(buf_size - (u32_t) PTR_SUB(p, str_buf) > 1)
{
p = val_to_decimal_string(
p,
buf_size - (u32_t) PTR_SUB(p, str_buf),
minor_ver);
}
if(buf_size - (u32_t) PTR_SUB(p, str_buf) > 1)
{
*p = '.';
p++;
}
if(buf_size - (u32_t) PTR_SUB(p, str_buf) > 1)
{
p = val_to_decimal_string(
p,
buf_size - (u32_t) PTR_SUB(p, str_buf),
rel_num);
}
if(buf_size - (u32_t) PTR_SUB(p, str_buf) > 1)
{
*p = '.';
p++;
}
if(buf_size - (u32_t) PTR_SUB(p, str_buf) > 1)
{
p = val_to_decimal_string(
p,
buf_size - (u32_t) PTR_SUB(p, str_buf),
fix_num);
}
if(buf_size - (u32_t) PTR_SUB(p, str_buf) > 1)
{
*p = '.';
p++;
}
if(buf_size - (u32_t) PTR_SUB(p, str_buf) > 1)
{
#if DBG
*p = 'd';
#else
*p = 'r';
#endif
p++;
}
if(buf_size - (u32_t) PTR_SUB(p, str_buf) > 1)
{
#if DBG
*p = 'b';
#else
*p = 't';
#endif
p++;
}
if(buf_size - (u32_t) PTR_SUB(p, str_buf) > 1)
{
#if DBG
*p = 'g';
#else
*p = 'l';
#endif
p++;
}
*p = 0;
p++;
return (u32_t) PTR_SUB(p, str_buf);
}
STATIC void
get_max_conns(
lm_device_t *pdev,
u32_t *max_toe_conn,
u32_t *max_iscsi_conn,
u32_t *max_iscsi_pending_tasks)
{
u32_t max_lic_conn;
u32_t max_res_conn;
u32_t res_flags;
REG_RD_IND(
pdev,
pdev->hw_info.shmem_base +
OFFSETOF(shmem_region_t,
dev_info.port_feature_config.resource.res_cfg),
&res_flags);
REG_RD_IND(
pdev,
pdev->hw_info.shmem_base +
OFFSETOF(shmem_region_t, fw_lic_key.max_toe_conn),
&max_lic_conn);
max_lic_conn &= 0xffff;
if(max_lic_conn)
{
max_lic_conn ^= FW_ENCODE_16BIT_PATTERN;
if(max_lic_conn == 0xffff)
{
max_lic_conn = 1024;
}
}
if(res_flags & RES_RES_CFG_VALID)
{
if(res_flags & RES_RES_CFG_L2)
{
REG_RD_IND(
pdev,
pdev->hw_info.shmem_base +
OFFSETOF(shmem_region_t,
dev_info.port_feature_config.resource.conn_resource1),
&max_res_conn);
if (!(res_flags & RES_RES_CFG_FCFS_DISABLED))
{
max_res_conn = 1024;
}
}
else
{
max_res_conn = 0;
}
}
else
{
max_res_conn = 1024;
}
*max_toe_conn = (max_lic_conn < max_res_conn) ? max_lic_conn: max_res_conn;
if((res_flags & RES_RES_CFG_VALID) && (res_flags & RES_RES_CFG_ISCSI))
{
REG_RD_IND(
pdev,
pdev->hw_info.shmem_base +
OFFSETOF(shmem_region_t,
dev_info.port_feature_config.resource.conn_resource3),
max_iscsi_pending_tasks);
*max_iscsi_pending_tasks &= RES_CONN_ISCSI_PTASK_MASK;
if(*max_iscsi_pending_tasks == 0 || *max_iscsi_pending_tasks > 128)
{
*max_iscsi_pending_tasks = 128;
}
}
else
{
*max_iscsi_pending_tasks = 128;
*max_iscsi_conn = 0;
}
REG_RD_IND(
pdev,
pdev->hw_info.shmem_base +
OFFSETOF(shmem_region_t, fw_lic_key.max_iscsi_trgt_conn),
&max_lic_conn);
if(max_lic_conn)
{
max_lic_conn ^= FW_ENCODE_32BIT_PATTERN;
max_lic_conn >>= 16;
}
*max_iscsi_conn = max_lic_conn;
if(*max_toe_conn == 0)
{
if(pdev->hw_info.svid == 0x103c)
{
*max_toe_conn = 1024;
}
else if(CHIP_REV(pdev) == CHIP_REV_IKOS ||
CHIP_REV(pdev) == CHIP_REV_FPGA)
{
*max_toe_conn = 32;
}
}
if(*max_iscsi_conn == 0)
{
if(pdev->hw_info.svid == 0x103c)
{
*max_iscsi_conn = 1024;
}
else if(CHIP_REV(pdev) == CHIP_REV_IKOS ||
CHIP_REV(pdev) == CHIP_REV_FPGA)
{
*max_iscsi_conn = 32;
}
}
}
lm_status_t
lm_get_dev_info(
lm_device_t *pdev)
{
typedef struct _param_entry_t
{
u32_t offset;
u32_t asic_default;
u32_t fpga_ikos_default;
u32_t min;
u32_t max;
} param_entry_t;
#define _OFFSET(_name) (OFFSETOF(lm_device_t, params._name))
#define PARAM_VAL(_pdev, _entry) \
(*((u32_t *) ((u8_t *) (_pdev) + (_entry)->offset)))
#define SET_PARAM_VAL(_pdev, _entry, _val) \
*((u32_t *) ((u8_t *) (_pdev) + (_entry)->offset)) = (_val)
static param_entry_t param_list[] =
{
{ _OFFSET(mtu), 1500, 1500, 1500, 9018 },
{ _OFFSET(l2_rx_desc_cnt[0]), 200, 150, 0, 0 },
{ _OFFSET(l2_rx_desc_cnt[1]), 0, 0, 0, 0 },
{ _OFFSET(l2_rx_desc_cnt[2]), 0, 0, 0, 0 },
{ _OFFSET(l2_rx_desc_cnt[3]), 0, 0, 0, 0 },
{ _OFFSET(l2_rx_desc_cnt[4]), 0, 0, 0, 0 },
{ _OFFSET(l2_rx_desc_cnt[5]), 0, 0, 0, 0 },
{ _OFFSET(l2_rx_desc_cnt[6]), 0, 0, 0, 0 },
{ _OFFSET(l2_rx_desc_cnt[7]), 0, 0, 0, 0 },
{ _OFFSET(l2_rx_desc_cnt[8]), 0, 0, 0, 0 },
{ _OFFSET(l2_rx_desc_cnt[9]), 0, 0, 0, 0 },
{ _OFFSET(l2_rx_desc_cnt[10]), 0, 0, 0, 0 },
{ _OFFSET(l2_rx_desc_cnt[11]), 0, 0, 0, 0 },
#if 0
{ _OFFSET(l2_rx_desc_cnt[12]), 0, 0, 0, 0 },
{ _OFFSET(l2_rx_desc_cnt[13]), 0, 0, 0, 0 },
{ _OFFSET(l2_rx_desc_cnt[14]), 0, 0, 0, 0 },
{ _OFFSET(l2_rx_desc_cnt[15]), 0, 0, 0, 0 },
#endif
{ _OFFSET(l2_tx_bd_page_cnt[0]), 2, 2, 1, 127 },
{ _OFFSET(l2_tx_bd_page_cnt[1]), 1, 1, 1, 127 },
{ _OFFSET(l2_tx_bd_page_cnt[2]), 1, 1, 1, 127 },
{ _OFFSET(l2_tx_bd_page_cnt[3]), 1, 1, 1, 127 },
{ _OFFSET(l2_tx_bd_page_cnt[4]), 1, 1, 1, 127 },
{ _OFFSET(l2_tx_bd_page_cnt[5]), 1, 1, 1, 127 },
{ _OFFSET(l2_tx_bd_page_cnt[6]), 1, 1, 1, 127 },
{ _OFFSET(l2_tx_bd_page_cnt[7]), 1, 1, 1, 127 },
{ _OFFSET(l2_tx_bd_page_cnt[8]), 1, 1, 1, 127 },
{ _OFFSET(l2_tx_bd_page_cnt[9]), 1, 1, 1, 127 },
{ _OFFSET(l2_tx_bd_page_cnt[10]), 1, 1, 1, 127 },
{ _OFFSET(l2_tx_bd_page_cnt[11]), 1, 1, 1, 127 },
{ _OFFSET(l2_rx_bd_page_cnt[0]), 2, 2, 1, 127 },
{ _OFFSET(l2_rx_bd_page_cnt[1]), 1, 1, 1, 127 },
{ _OFFSET(l2_rx_bd_page_cnt[2]), 1, 1, 1, 127 },
{ _OFFSET(l2_rx_bd_page_cnt[3]), 1, 1, 1, 127 },
{ _OFFSET(l2_rx_bd_page_cnt[4]), 1, 1, 1, 127 },
{ _OFFSET(l2_rx_bd_page_cnt[5]), 1, 1, 1, 127 },
{ _OFFSET(l2_rx_bd_page_cnt[6]), 1, 1, 1, 127 },
{ _OFFSET(l2_rx_bd_page_cnt[7]), 1, 1, 1, 127 },
{ _OFFSET(l2_rx_bd_page_cnt[8]), 1, 1, 1, 127 },
{ _OFFSET(l2_rx_bd_page_cnt[9]), 1, 1, 1, 127 },
{ _OFFSET(l2_rx_bd_page_cnt[10]), 1, 1, 1, 127 },
{ _OFFSET(l2_rx_bd_page_cnt[11]), 1, 1, 1, 127 },
#if 0
{ _OFFSET(l2_rx_bd_page_cnt[12]), 1, 1, 1, 127 },
{ _OFFSET(l2_rx_bd_page_cnt[13]), 1, 1, 1, 127 },
{ _OFFSET(l2_rx_bd_page_cnt[14]), 1, 1, 1, 127 },
{ _OFFSET(l2_rx_bd_page_cnt[15]), 1, 1, 1, 127 },
#endif
{ _OFFSET(l4_tx_bd_page_cnt), 1, 1, 1, 255 },
{ _OFFSET(limit_l4_tx_bd_cnt), 0, 0, 0, 0 },
{ _OFFSET(l4_rx_bd_page_cnt), 1, 1, 1, 255 },
{ _OFFSET(limit_l4_rx_bd_cnt), 0, 0, 0, 0 },
#ifndef EXCLUDE_KQE_SUPPORT
#if INCLUDE_OFLD_SUPPORT
{ _OFFSET(kwq_page_cnt), 4, 2, 1, 255 },
{ _OFFSET(kcq_page_cnt), 32, 32, 1, 255 },
{ _OFFSET(kcq_history_size), 0x80, 0x80, 0, 0 },
#else
{ _OFFSET(kwq_page_cnt), 0, 0, 0, 0 },
{ _OFFSET(kcq_page_cnt), 0, 0, 0, 0 },
{ _OFFSET(kcq_history_size), 0, 0, 0, 0 },
#endif
{ _OFFSET(con_kcqe_history_size), 0, 0, 0, 0 },
{ _OFFSET(con_kwqe_history_size), 0, 0, 0, 0 },
#endif
{ _OFFSET(gen_bd_page_cnt), 2, 2, 1, 127 },
{ _OFFSET(max_gen_buf_cnt), 0x8000, 0x8000, 0, 0 },
{ _OFFSET(gen_buf_per_alloc), 0x4, 0x4, 0, 0 },
{ _OFFSET(copy_buffered_data), 0, 0, 0, 0 },
{ _OFFSET(rcv_buffer_offset), 0x38, 0x38, 0, 0 },
{ _OFFSET(enable_syn_rcvq), 0, 0, 0, 0 },
{ _OFFSET(hcopy_desc_cnt), 0, 0, 0, 0 },
{ _OFFSET(hcopy_bd_page_cnt), 2, 2, 1, 127 },
{ _OFFSET(buffered_kcqe_cnt), 0x80, 0x80, 0, 0 },
{ _OFFSET(deferred_kcqe_cnt), 0x100, 0x100, 0, 0 },
{ _OFFSET(test_mode), 0x60, 0x60, 0, 0 },
{ _OFFSET(ofld_cap), 0, 0, 0, 0 },
{ _OFFSET(wol_cap), 0, 0, 0, 0 },
{ _OFFSET(flow_ctrl_cap), 0, 0, 0, 0 },
{ _OFFSET(req_medium), 0, 0, 0, 0xfffff },
{ _OFFSET(selective_autoneg), 0, 0, 0, 0 },
{ _OFFSET(wire_speed), 1, 0, 0, 0 },
{ _OFFSET(phy_addr), 1, 0, 0, 0 },
{ _OFFSET(phy_int_mode), 2, 2, 0, 0 },
{ _OFFSET(link_chng_mode), 2, 2, 0, 0 },
{ _OFFSET(hc_timer_mode), 0, 0, 0, 0 },
{ _OFFSET(ind_comp_limit), 200, 100, 0, 0 },
{ _OFFSET(tx_quick_cons_trip_int), 3, 10, 0, 0 },
{ _OFFSET(tx_quick_cons_trip), 3, 30, 0, 0 },
{ _OFFSET(tx_ticks_int), 30, 10, 0, 0 },
{ _OFFSET(tx_ticks), 60, 200, 0, 0 },
{ _OFFSET(rx_quick_cons_trip_int), 1, 3, 0, 0 },
{ _OFFSET(rx_quick_cons_trip), 2, 1, 0, 0 },
{ _OFFSET(rx_ticks_int), 15, 5, 0, 0 },
{ _OFFSET(rx_ticks), 45, 1, 0, 0 },
{ _OFFSET(comp_prod_trip_int), 2, 3, 0, 0 },
{ _OFFSET(comp_prod_trip), 4, 1, 0, 0 },
{ _OFFSET(com_ticks_int), 64, 5, 0, 0 },
{ _OFFSET(com_ticks), 220, 1, 0, 0 },
{ _OFFSET(cmd_ticks_int), 64, 5, 0, 0 },
{ _OFFSET(cmd_ticks), 220, 1, 0, 0 },
{ _OFFSET(stats_ticks), 1000000, 1000000, 0, 0 },
{ _OFFSET(psb_tx_cons_trip), 0x100010,0x100010,0, 0 },
{ _OFFSET(psb_tx_ticks), 0x100040,0x100040,0, 0 },
{ _OFFSET(psb_rx_cons_trip), 0x100010,0x100010,0, 0 },
{ _OFFSET(psb_rx_ticks), 0x80020, 0x80020, 0, 0 },
{ _OFFSET(psb_comp_prod_trip), 0x80008, 0x80008, 0, 0 },
{ _OFFSET(psb_com_ticks), 0x400040,0x400040,0, 0 },
{ _OFFSET(psb_cmd_ticks), 0x400040,0x400040,0, 0 },
{ _OFFSET(psb_period_ticks), 0, 0, 0, 0 },
{ _OFFSET(enable_fir), 1, 1, 0, 0 },
{ _OFFSET(num_rchans), 5, 5, 0, 0 },
{ _OFFSET(num_wchans), 3, 3, 0, 0 },
{ _OFFSET(one_tdma), 0, 0, 0, 0 },
{ _OFFSET(ping_pong_dma), 0, 0, 0, 0 },
{ _OFFSET(tmr_reload_value1), 0x6c627970, 0, 0, 0 },
{ _OFFSET(keep_vlan_tag), 0, 0, 0, 0 },
{ _OFFSET(enable_remote_phy), 0, 0, 0, 0 },
{ _OFFSET(rphy_req_medium), 0, 0, 0, 0 },
{ _OFFSET(rphy_flow_ctrl_cap), 0, 0, 0, 0 },
{ _OFFSET(rphy_selective_autoneg), 0, 0, 0, 0 },
{ _OFFSET(rphy_wire_speed), 1, 0, 0, 0 },
{ _OFFSET(bin_mq_mode), 0, 0, 0, 0 },
{ _OFFSET(validate_l4_data), 0, 0, 0, 0 },
{ _OFFSET(disable_pcie_nfr), 0, 0, 0, 0 },
{ _OFFSET(fw_flow_control), 0, 0, 0, 0 },
{ _OFFSET(fw_flow_control_wait), 0xffff, 0xffff, 0, 0xffff },
{ _OFFSET(ena_large_grc_timeout), 0, 0, 0, 0 },
{ _OFFSET(flow_control_reporting_mode), 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 }
};
lm_status_t lm_status;
param_entry_t *param;
u32_t val;
DbgMessage(pdev, INFORMi, "### lm_get_dev_info\n");
lm_status = mm_read_pci(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_vendor_id),
&val);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
pdev->hw_info.vid = (u16_t) val;
DbgMessage1(pdev, INFORMi, "vid 0x%x\n", pdev->hw_info.vid);
pdev->hw_info.did = (u16_t) (val >> 16);
DbgMessage1(pdev, INFORMi, "did 0x%x\n", pdev->hw_info.did);
lm_status = mm_read_pci(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_subsystem_vendor_id),
&val);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
pdev->hw_info.svid = (u16_t) val;
DbgMessage1(pdev, INFORMi, "svid 0x%x\n", pdev->hw_info.svid);
pdev->hw_info.ssid = (u16_t) (val >> 16);
DbgMessage1(pdev, INFORMi, "ssid 0x%x\n", pdev->hw_info.ssid);
lm_status = mm_read_pci(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_int_line),
&val);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
pdev->hw_info.irq = (u8_t) val;
DbgMessage1(pdev, INFORMi, "IRQ 0x%x\n", pdev->hw_info.irq);
pdev->hw_info.int_pin = (u8_t) (val >> 8);
DbgMessage1(pdev, INFORMi, "Int pin 0x%x\n", pdev->hw_info.int_pin);
lm_status = mm_read_pci(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_cache_line_size),
&val);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
pdev->hw_info.cache_line_size = (u8_t) val;
DbgMessage1(pdev, INFORMi, "Cache line size 0x%x\n", (u8_t) val);
pdev->hw_info.latency_timer = (u8_t) (val >> 8);
DbgMessage1(pdev, INFORMi, "Latency timer 0x%x\n", (u8_t) (val >> 8));
lm_status = mm_read_pci(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_class_code),
&val);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
pdev->hw_info.rev_id = (u8_t) val;
DbgMessage1(pdev, INFORMi, "Revision id 0x%x\n", pdev->hw_info.rev_id);
lm_status = mm_read_pci(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_bar_1),
&val);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
#ifndef CONFIG_PPC64
pdev->hw_info.mem_base.as_u32.low = val & 0xfffffff0;
#endif
DbgMessage1(pdev, INFORMi, "Mem base low 0x%x\n", pdev->hw_info.mem_base.as_u32.low);
val = 0;
lm_status = mm_read_pci(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_bar_2),
&val);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
#ifndef CONFIG_PPC64
pdev->hw_info.mem_base.as_u32.high = val;
#endif
DbgMessage1(pdev, INFORMi, "Mem base high 0x%x\n",
pdev->hw_info.mem_base.as_u32.high);
lm_status = mm_read_pci(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_command),
&val);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
if(!(val & PCICFG_COMMAND_MEM_SPACE))
{
DbgBreakMsg("MEM_SPACE not enabled.\n");
return LM_STATUS_FAILURE;
}
val |= PCICFG_COMMAND_BUS_MASTER;
lm_status = mm_write_pci(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_command),
val);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
val = PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
lm_status = mm_write_pci(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_misc_config),
val);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
lm_status = mm_write_pci(
pdev,
OFFSETOF(pci_config_t, pcicfg_reg_window_address),
OFFSETOF(reg_space_t, pci.pci_config_2));
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
lm_status = mm_read_pci(
pdev,
OFFSETOF(pci_config_t, pcicfg_reg_window),
&val);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
val &= PCI_CONFIG_2_BAR1_SIZE;
if(val == PCI_CONFIG_2_BAR1_SIZE_DISABLED ||
val > PCI_CONFIG_2_BAR1_SIZE_1G)
{
DbgBreakMsg("Invalid bar size.\n");
return LM_STATUS_FAILURE;
}
pdev->hw_info.bar_size = 1 << (val+15);
DbgMessage1(pdev, INFORM, "bar_size 0x%x\n", pdev->hw_info.bar_size);
pdev->vars.regview = (reg_space_t *) mm_map_io_base(
pdev,
pdev->hw_info.mem_base,
pdev->hw_info.bar_size);
if(pdev->vars.regview == NULL)
{
return LM_STATUS_FAILURE;
}
DbgMessage1(pdev, INFORMi, "Mapped base %p\n", pdev->vars.regview);
#if DBG
REG_RD(pdev, pci.pci_swap_diag0, &val);
DbgBreakIf(val != 0x1020304);
#endif
REG_RD(pdev, misc.misc_id, &pdev->hw_info.chip_id);
DbgMessage1(pdev, INFORMi, "chip id 0x%x\n", pdev->hw_info.chip_id);
if(CHIP_NUM(pdev) == CHIP_NUM_5709)
{
pdev->hw_info.bus_mode = BUS_MODE_PCIE;
}
else
{
REG_RD(pdev, pci_config.pcicfg_misc_status, &val);
if(val & PCICFG_MISC_STATUS_32BIT_DET)
{
pdev->hw_info.bus_width = BUS_WIDTH_32_BIT;
DbgMessage(pdev, INFORM, "32bit bus width.\n");
}
else
{
pdev->hw_info.bus_width = BUS_WIDTH_64_BIT;
DbgMessage(pdev, INFORM, "64bit bus width.\n");
}
if(val & PCICFG_MISC_STATUS_PCIX_DET)
{
pdev->hw_info.bus_mode = BUS_MODE_PCIX;
DbgMessage(pdev, INFORM, "PCIX bus detected.\n");
REG_RD(pdev, pci_config.pcicfg_pci_clock_control_bits, &val);
switch(val & PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET)
{
case PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
pdev->hw_info.bus_speed = BUS_SPEED_133_MHZ;
DbgMessage(pdev, INFORM, "Bus speed is 133Mhz.\n");
break;
case PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
pdev->hw_info.bus_speed = BUS_SPEED_100_MHZ;
DbgMessage(pdev, INFORM, "Bus speed is 100Mhz.\n");
break;
case PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
case PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
pdev->hw_info.bus_speed = BUS_SPEED_66_MHZ;
DbgMessage(pdev, INFORM, "Bus speed is 66Mhz.\n");
break;
case PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
case PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
pdev->hw_info.bus_speed = BUS_SPEED_50_MHZ;
DbgMessage(pdev, INFORM, "Bus speed is 50Mhz.\n");
break;
case PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET:
case PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
case PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
default:
pdev->hw_info.bus_speed = BUS_SPEED_33_MHZ;
DbgMessage(pdev, INFORM, "Bus speed is 33Mhz.\n");
break;
}
}
else
{
pdev->hw_info.bus_mode = BUS_MODE_PCI;
DbgMessage(pdev, INFORM, "Conventional PCI bus detected.\n");
if(val & PCICFG_MISC_STATUS_M66EN)
{
pdev->hw_info.bus_speed = BUS_SPEED_66_MHZ;
DbgMessage(pdev, INFORM, "Bus speed is 66Mhz.\n");
}
else
{
pdev->hw_info.bus_speed = BUS_SPEED_33_MHZ;
DbgMessage(pdev, INFORM, "Bus speed is 33Mhz.\n");
}
}
}
if(CHIP_ID(pdev) == CHIP_ID_5706_A0 || CHIP_ID(pdev) == CHIP_ID_5706_A1)
{
REG_RD_OFFSET(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_command),
&val);
if(CHIP_ID(pdev) == CHIP_ID_5706_A0)
{
val &= ~(PCICFG_COMMAND_SERR_ENA | PCICFG_COMMAND_PERR_ENA);
}
else if(pdev->hw_info.bus_mode == BUS_MODE_PCI &&
pdev->hw_info.bus_width == BUS_WIDTH_64_BIT)
{
val &= ~PCICFG_COMMAND_PERR_ENA;
}
REG_WR_OFFSET(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_command),
val);
}
else if(CHIP_ID(pdev) == CHIP_ID_5708_A0)
{
REG_RD_OFFSET(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_command),
&val);
val &= ~(PCICFG_COMMAND_SERR_ENA | PCICFG_COMMAND_PERR_ENA);
REG_WR_OFFSET(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_command),
val);
}
if(CHIP_NUM(pdev) == CHIP_NUM_5708)
{
REG_RD_IND(pdev, 0x240000+0x18, &val);
pdev->hw_info.pcie_bus_num = (u8_t) val;
REG_RD_IND(pdev, 0x240000+0x6c, &val);
pdev->hw_info.pcie_max_width = (u8_t) ((val & 0x3f0) >> 4);
switch(val & 0xf)
{
case 1:
pdev->hw_info.pcie_max_speed = PCIE_SPEED_2_5_G;
break;
default:
pdev->hw_info.pcie_max_speed = 0;
break;
}
REG_RD_IND(pdev, 0x240000+0x70, &val);
pdev->hw_info.pcie_width = (u8_t) ((val & 0x3f00000) >> 20);
switch(val & 0xf0000)
{
case 0x10000:
pdev->hw_info.pcie_speed = PCIE_SPEED_2_5_G;
break;
default:
pdev->hw_info.pcie_speed = 0;
break;
}
}
else if(CHIP_NUM(pdev) == CHIP_NUM_5709)
{
REG_RD(pdev, pci_config.pcicfg_link_capability, &val);
pdev->hw_info.pcie_max_width =
(u8_t) ((val & PCICFG_LINK_CAPABILITY_MAX_LINK_WIDTH) >> 4);
switch (val & PCICFG_LINK_CAPABILITY_MAX_LINK_SPEED)
{
case PCICFG_LINK_CAPABILITY_MAX_LINK_SPEED_5:
pdev->hw_info.pcie_max_speed = PCIE_SPEED_5_G;
break;
case PCICFG_LINK_CAPABILITY_MAX_LINK_SPEED_2_5:
pdev->hw_info.pcie_max_speed = PCIE_SPEED_2_5_G;
break;
default:
pdev->hw_info.pcie_max_speed = 0;
break;
}
REG_RD(pdev, pci_config.pcicfg_link_status, &val);
pdev->hw_info.pcie_width =
(u8_t) ((val & PCICFG_LINK_STATUS_NEG_LINK_WIDTH) >> 4);
switch (val & PCICFG_LINK_STATUS_SPEED)
{
case PCICFG_LINK_CAPABILITY_MAX_LINK_SPEED_5:
pdev->hw_info.pcie_speed = PCIE_SPEED_5_G;
break;
case PCICFG_LINK_CAPABILITY_MAX_LINK_SPEED_2_5:
pdev->hw_info.pcie_speed = PCIE_SPEED_2_5_G;
break;
default:
pdev->hw_info.pcie_speed = 0;
break;
}
REG_RD_IND(pdev, OFFSETOF(reg_space_t, mcp.mcp_toe_id), &val);
if(val & MCP_TOE_ID_FUNCTION_ID)
{
pdev->hw_info.mac_id = 1;
}
}
REG_RD_IND(
pdev,
MCP_SCRATCHPAD_START + OFFSETOF(shm_hdr_t, shm_hdr_signature),
&val);
if((val & SHM_ADDR_SIGN_MASK) == SHM_ADDR_SIGNATURE)
{
REG_RD_IND(
pdev,
MCP_SCRATCHPAD_START +
OFFSETOF(shm_hdr_t, shm_addr[pdev->hw_info.mac_id]),
&pdev->hw_info.shmem_base);
}
else
{
pdev->hw_info.shmem_base = HOST_VIEW_SHMEM_BASE;
}
REG_RD_IND(
pdev,
pdev->hw_info.shmem_base +
OFFSETOF(shmem_region_t, dev_info.shared_hw_config.config),
&val);
pdev->hw_info.nvm_hw_config = val;
get_max_conns(
pdev,
&pdev->hw_info.max_toe_conn,
&pdev->hw_info.max_iscsi_conn,
&pdev->hw_info.max_iscsi_pending_tasks);
REG_RD_IND(
pdev,
pdev->hw_info.shmem_base +
OFFSETOF(shmem_region_t, dev_info.port_hw_config.mac_upper),
&val);
pdev->hw_info.mac_addr[0] = (u8_t) (val >> 8);
pdev->hw_info.mac_addr[1] = (u8_t) val;
REG_RD_IND(
pdev,
pdev->hw_info.shmem_base +
OFFSETOF(shmem_region_t, dev_info.port_hw_config.mac_lower),
&val);
pdev->hw_info.mac_addr[2] = (u8_t) (val >> 24);
pdev->hw_info.mac_addr[3] = (u8_t) (val >> 16);
pdev->hw_info.mac_addr[4] = (u8_t) (val >> 8);
pdev->hw_info.mac_addr[5] = (u8_t) val;
REG_RD_IND(
pdev,
pdev->hw_info.shmem_base +
OFFSETOF(
shmem_region_t,
dev_info.port_hw_config.iscsi_mac_upper),
&val);
pdev->hw_info.iscsi_mac_addr[0] = (u8_t) (val >> 8);
pdev->hw_info.iscsi_mac_addr[1] = (u8_t) val;
REG_RD_IND(
pdev,
pdev->hw_info.shmem_base +
OFFSETOF(
shmem_region_t,
dev_info.port_hw_config.iscsi_mac_lower),
&val);
pdev->hw_info.iscsi_mac_addr[2] = (u8_t) (val >> 24);
pdev->hw_info.iscsi_mac_addr[3] = (u8_t) (val >> 16);
pdev->hw_info.iscsi_mac_addr[4] = (u8_t) (val >> 8);
pdev->hw_info.iscsi_mac_addr[5] = (u8_t) val;
DbgMessage6(pdev, INFORM, "mac addr: %02x %02x %02x %02x %02x %02x\n",
pdev->hw_info.mac_addr[0],
pdev->hw_info.mac_addr[1],
pdev->hw_info.mac_addr[2],
pdev->hw_info.mac_addr[3],
pdev->hw_info.mac_addr[4],
pdev->hw_info.mac_addr[5]);
DbgBreakIf(LM_DRIVER_MAJOR_VER > 255);
DbgBreakIf(LM_DRIVER_MINOR_VER > 255);
DbgBreakIf(LM_DRIVER_REL_NUM > 255);
DbgBreakIf(LM_DRIVER_FIX_NUM > 255);
pdev->ver_num =
(LM_DRIVER_MAJOR_VER << 24) |
(LM_DRIVER_MINOR_VER << 16) |
(LM_DRIVER_REL_NUM << 8) |
LM_DRIVER_FIX_NUM;
(void) build_ver_string(
(char *)pdev->ver_str,
sizeof(pdev->ver_str),
LM_DRIVER_MAJOR_VER,
LM_DRIVER_MINOR_VER,
LM_DRIVER_REL_NUM,
LM_DRIVER_FIX_NUM);
pdev->params.mac_addr[0] = pdev->hw_info.mac_addr[0];
pdev->params.mac_addr[1] = pdev->hw_info.mac_addr[1];
pdev->params.mac_addr[2] = pdev->hw_info.mac_addr[2];
pdev->params.mac_addr[3] = pdev->hw_info.mac_addr[3];
pdev->params.mac_addr[4] = pdev->hw_info.mac_addr[4];
pdev->params.mac_addr[5] = pdev->hw_info.mac_addr[5];
param = param_list;
while(param->offset)
{
if(CHIP_REV(pdev) == CHIP_REV_FPGA || CHIP_REV(pdev) == CHIP_REV_IKOS)
{
SET_PARAM_VAL(pdev, param, param->fpga_ikos_default);
}
else
{
SET_PARAM_VAL(pdev, param, param->asic_default);
}
param++;
}
if(CHIP_REV(pdev) == CHIP_REV_FPGA || CHIP_REV(pdev) == CHIP_REV_IKOS)
{
pdev->params.test_mode |= TEST_MODE_INIT_GEN_BUF_DATA;
pdev->params.test_mode |= TEST_MODE_SAVE_DUMMY_DMA_DATA;
pdev->params.test_mode |= TEST_MODE_IGNORE_SHMEM_SIGNATURE;
pdev->params.test_mode |= TEST_MODE_DRIVER_PULSE_ALWAYS_ALIVE;
}
if(pdev->hw_info.bus_mode == BUS_MODE_PCI)
{
if((CHIP_NUM(pdev)==CHIP_NUM_5706 || CHIP_NUM(pdev)==CHIP_NUM_5708) &&
(CHIP_REV(pdev)==CHIP_REV_FPGA || CHIP_REV(pdev)==CHIP_REV_IKOS))
{
pdev->params.ping_pong_dma = FALSE;
}
else
{
pdev->params.ping_pong_dma = TRUE;
}
}
else
{
pdev->params.ping_pong_dma = FALSE;
}
REG_RD_IND(
pdev,
pdev->hw_info.shmem_base +
OFFSETOF(shmem_region_t, dev_info.port_hw_config.config),
&pdev->params.serdes_pre_emphasis);
pdev->params.serdes_pre_emphasis &= PORT_HW_CFG_SERDES_TXCTL3_MASK;
if(CHIP_ID(pdev) == CHIP_ID_5706_A0)
{
if(pdev->hw_info.bus_mode == BUS_MODE_PCIX &&
pdev->hw_info.bus_speed == BUS_SPEED_133_MHZ)
{
pdev->params.num_rchans = 1;
}
}
#if defined(DBG) && !defined(EXCLUDE_KQE_SUPPORT)
pdev->params.con_kcqe_history_size = 256;
pdev->params.con_kwqe_history_size = 256;
#endif
if(CHIP_NUM(pdev) == CHIP_NUM_5708 || CHIP_NUM(pdev) == CHIP_NUM_5709)
{
if(lm_get_medium(pdev) == LM_MEDIUM_TYPE_FIBER)
{
pdev->params.phy_addr = 2;
}
}
if(CHIP_NUM(pdev) == CHIP_NUM_5709)
{
pdev->params.bin_mq_mode = TRUE;
}
DbgBreakIf(NUM_RX_CHAIN != NUM_TX_CHAIN);
pdev->rx_info.num_rxq = NUM_RX_CHAIN;
pdev->tx_info.num_txq = NUM_TX_CHAIN;
pdev->tx_info.cu_idx = TX_CHAIN_IDX1;
if(CHIP_REV(pdev) != CHIP_REV_IKOS)
{
REG_RD_IND(
pdev,
pdev->hw_info.shmem_base +
OFFSETOF(shmem_region_t,
dev_info.port_feature_config.config),
&val);
if(val & PORT_FEATURE_RPHY_ENABLED)
{
pdev->params.enable_remote_phy = 1;
}
}
if (CHIP_NUM(pdev) == CHIP_NUM_5706 ||
CHIP_NUM(pdev) == CHIP_NUM_5708)
{
pdev->params.limit_l4_rx_bd_cnt = 110;
}
lm_status = mm_get_user_config(pdev);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
REG_RD_IND(
pdev,
pdev->hw_info.shmem_base +
OFFSETOF(shmem_region_t, dev_info.signature),
&val);
if((val & DEV_INFO_SIGNATURE_MASK) != DEV_INFO_SIGNATURE)
{
if(!(pdev->params.test_mode & TEST_MODE_IGNORE_SHMEM_SIGNATURE))
{
DbgBreakMsg("Shmem signature not present.\n");
return LM_STATUS_BAD_SIGNATURE;
}
pdev->hw_info.mac_addr[0] = 0x00;
pdev->hw_info.mac_addr[1] = 0x10;
pdev->hw_info.mac_addr[2] = 0x18;
pdev->hw_info.mac_addr[3] = 0xff;
pdev->hw_info.mac_addr[4] = 0xff;
pdev->hw_info.mac_addr[5] = 0xff;
pdev->hw_info.iscsi_mac_addr[0] = 0x00;
pdev->hw_info.iscsi_mac_addr[1] = 0x10;
pdev->hw_info.iscsi_mac_addr[2] = 0x18;
pdev->hw_info.iscsi_mac_addr[3] = 0xff;
pdev->hw_info.iscsi_mac_addr[4] = 0xff;
pdev->hw_info.iscsi_mac_addr[5] = 0xfe;
}
param = param_list;
while(param->offset)
{
if(param->min != 0 || param->max != 0)
{
if(PARAM_VAL(pdev, param) < param->min ||
PARAM_VAL(pdev, param) > param->max)
{
if(CHIP_REV(pdev) == CHIP_REV_FPGA ||
CHIP_REV(pdev) == CHIP_REV_IKOS)
{
SET_PARAM_VAL(pdev, param, param->fpga_ikos_default);
}
else
{
SET_PARAM_VAL(pdev, param, param->asic_default);
}
}
}
param++;
}
#ifndef EXCLUDE_KQE_SUPPORT
if(pdev->params.kcq_history_size > (LM_PAGE_SIZE/sizeof(kcqe_t)) *
pdev->params.kcq_page_cnt - 1)
{
pdev->params.kcq_history_size = ((LM_PAGE_SIZE/sizeof(kcqe_t)) *
pdev->params.kcq_page_cnt) / 2;
}
#endif
if (CHIP_NUM(pdev) == CHIP_NUM_5709)
{
pdev->params.rcv_buffer_offset = 0;
}
if((pdev->params.mac_addr[0] == 0 &&
pdev->params.mac_addr[1] == 0 &&
pdev->params.mac_addr[2] == 0 &&
pdev->params.mac_addr[3] == 0 &&
pdev->params.mac_addr[4] == 0 &&
pdev->params.mac_addr[5] == 0) || (pdev->params.mac_addr[0] & 1))
{
DbgMessage(pdev, WARN, "invalid LAA.\n");
pdev->params.mac_addr[0] = pdev->hw_info.mac_addr[0];
pdev->params.mac_addr[1] = pdev->hw_info.mac_addr[1];
pdev->params.mac_addr[2] = pdev->hw_info.mac_addr[2];
pdev->params.mac_addr[3] = pdev->hw_info.mac_addr[3];
pdev->params.mac_addr[4] = pdev->hw_info.mac_addr[4];
pdev->params.mac_addr[5] = pdev->hw_info.mac_addr[5];
}
if(CHIP_ID(pdev) == CHIP_ID_5706_A0)
{
pdev->params.tx_quick_cons_trip_int = pdev->params.tx_quick_cons_trip;
pdev->params.tx_ticks_int = pdev->params.tx_ticks;
pdev->params.rx_quick_cons_trip_int = pdev->params.rx_quick_cons_trip;
pdev->params.rx_ticks_int = pdev->params.rx_ticks;
pdev->params.comp_prod_trip_int = pdev->params.comp_prod_trip;
pdev->params.com_ticks_int = pdev->params.com_ticks;
pdev->params.cmd_ticks_int = pdev->params.cmd_ticks;
pdev->params.stats_ticks = 0;
}
if(pdev->params.enable_syn_rcvq &&
NUM_RX_CHAIN > 1 &&
pdev->params.l2_rx_desc_cnt[1] == 0)
{
pdev->params.l2_rx_desc_cnt[1] = 60;
}
if(CHIP_ID(pdev) == CHIP_ID_5706_A0 || CHIP_ID(pdev) == CHIP_ID_5706_A1)
{
pdev->params.hc_timer_mode = HC_COLLECT_MODE;
}
REG_RD_IND(
pdev,
pdev->hw_info.shmem_base + OFFSETOF(shmem_region_t, drv_fw_mb.fw_mb),
&val);
pdev->vars.fw_wr_seq = val & DRV_MSG_SEQ;
if(pdev->params.enable_remote_phy)
{
REG_RD_IND(
pdev,
pdev->hw_info.shmem_base +
OFFSETOF(shmem_region_t, drv_fw_cap_mb.fw_cap_mb),
&val);
if((val & CAPABILITY_SIGNATURE_MASK) != FW_CAP_SIGNATURE ||
(val & FW_CAP_REMOTE_PHY_CAPABLE) == 0)
{
pdev->params.enable_remote_phy = 0;
}
}
return LM_STATUS_SUCCESS;
}
#ifndef EXCLUDE_KQE_SUPPORT
STATIC lm_status_t
init_kwq_resc(
lm_device_t *pdev)
{
u32_t mem_size;
if(pdev->params.kwq_page_cnt == 0)
{
return LM_STATUS_SUCCESS;
}
mem_size = pdev->params.kwq_page_cnt * sizeof(lm_address_t);
mem_size = (mem_size + LM_PAGE_MASK) & ~LM_PAGE_MASK;
pdev->kq_info.kwq_pgtbl_virt = mm_alloc_phys_mem(
pdev,
mem_size,
&pdev->kq_info.kwq_pgtbl_phy,
PHYS_MEM_TYPE_NONCACHED,
NULL);
if(pdev->kq_info.kwq_pgtbl_virt == NULL)
{
return LM_STATUS_RESOURCE;
}
DbgBreakIf(pdev->kq_info.kwq_pgtbl_phy.as_u32.low & CACHE_LINE_SIZE_MASK);
mem_size = LM_PAGE_SIZE * pdev->params.kwq_page_cnt;
pdev->kq_info.kwq_virt = (kwqe_t *) mm_alloc_phys_mem(
pdev,
mem_size,
&pdev->kq_info.kwq_phy,
PHYS_MEM_TYPE_NONCACHED,
NULL);
if(pdev->kq_info.kwq_virt == NULL)
{
return LM_STATUS_RESOURCE;
}
DbgBreakIf(pdev->kq_info.kwq_phy.as_u32.low & CACHE_LINE_SIZE_MASK);
DbgBreakIf(((u8_t *) pdev->kq_info.kwq_virt - (u8_t *) 0) & LM_PAGE_MASK);
return LM_STATUS_SUCCESS;
}
STATIC lm_status_t
init_kcq_resc(
lm_device_t *pdev)
{
u32_t mem_size;
if(pdev->params.kcq_page_cnt == 0)
{
return LM_STATUS_SUCCESS;
}
mem_size = pdev->params.kcq_page_cnt * sizeof(lm_address_t);
mem_size = (mem_size + LM_PAGE_MASK) & ~LM_PAGE_MASK;
pdev->kq_info.kcq_pgtbl_virt = mm_alloc_phys_mem(
pdev,
mem_size,
&pdev->kq_info.kcq_pgtbl_phy,
PHYS_MEM_TYPE_NONCACHED,
NULL);
if(pdev->kq_info.kcq_pgtbl_virt == NULL)
{
return LM_STATUS_RESOURCE;
}
DbgBreakIf(pdev->kq_info.kcq_pgtbl_phy.as_u32.low & CACHE_LINE_SIZE_MASK);
mem_size = LM_PAGE_SIZE * pdev->params.kcq_page_cnt;
pdev->kq_info.kcq_virt = (kcqe_t *) mm_alloc_phys_mem(
pdev,
mem_size,
&pdev->kq_info.kcq_phy,
PHYS_MEM_TYPE_NONCACHED,
NULL);
if(pdev->kq_info.kcq_virt == NULL)
{
return LM_STATUS_RESOURCE;
}
DbgBreakIf(pdev->kq_info.kcq_phy.as_u32.low & CACHE_LINE_SIZE_MASK);
DbgBreakIf(((u8_t *) pdev->kq_info.kcq_virt - (u8_t *) 0) & LM_PAGE_MASK);
return LM_STATUS_SUCCESS;
}
#endif
#if INCLUDE_OFLD_SUPPORT
STATIC lm_status_t
init_ofld_resc(
lm_device_t *pdev)
{
lm_offload_info_t *ofld;
u32_t mem_size;
u32_t idx;
ofld = &pdev->ofld;
ofld->pdev = pdev;
ofld->pg_cid_hnd_info.max_pending_pg_oflds = 16;
ofld->pg_cid_hnd_info.pending_pg_ofld_cnt = 0;
s_list_init(&ofld->active_req_list, NULL, NULL, 0);
s_list_init(&ofld->upload_req_list, NULL, NULL, 0);
for(idx = 0; idx < STATE_BLOCK_CNT; idx++)
{
d_list_init(&ofld->state_blks[idx].tcp_list, NULL, NULL, 0);
d_list_init(&ofld->state_blks[idx].path_list, NULL, NULL, 0);
d_list_init(&ofld->state_blks[idx].neigh_list, NULL, NULL, 0);
ofld->state_blks[idx].max_conn = 0xffffffff;
ofld->state_blks[idx].state_block_idx = idx;
ofld->state_blks[idx].ofld = ofld;
ofld->state_blks[idx].params.ticks_per_second = 100;
ofld->state_blks[idx].params.ack_frequency = 2;
ofld->state_blks[idx].params.delayed_ack_ticks = 20;
ofld->state_blks[idx].params.max_retx = 10;
ofld->state_blks[idx].params.doubt_reachability_retx = 8;
ofld->state_blks[idx].params.sws_prevention_ticks = 10;
ofld->state_blks[idx].params.dup_ack_threshold = 3;
ofld->state_blks[idx].params.push_ticks = 20;
ofld->state_blks[idx].params.nce_stale_ticks = 20;
ofld->state_blks[idx].params.starting_ip_id = 0x8000;
}
mem_size = LM_PAGE_SIZE * pdev->params.gen_bd_page_cnt;
ofld->gen_chain.bd_chain_virt = (rx_bd_t *) mm_alloc_phys_mem(
pdev,
mem_size,
&ofld->gen_chain.bd_chain_phy,
PHYS_MEM_TYPE_UNSPECIFIED,
NULL);
if(ofld->gen_chain.bd_chain_virt == NULL)
{
return LM_STATUS_RESOURCE;
}
DbgBreakIf(ofld->gen_chain.bd_chain_phy.as_u32.low & CACHE_LINE_SIZE_MASK);
ofld->gen_chain.cid_addr = GET_CID_ADDR(GEN_CHAIN_CID);
s_list_init(&ofld->gen_chain.block_list, NULL, NULL, 0);
s_list_init(&ofld->gen_chain.free_gen_buf_list, NULL, NULL, 0);
s_list_init(&ofld->gen_chain.active_gen_buf_list, NULL, NULL, 0);
if(pdev->params.hcopy_desc_cnt)
{
mem_size = LM_PAGE_SIZE * pdev->params.hcopy_bd_page_cnt;
ofld->hcopy_chain.bd_chain_virt =(tx_bd_t *) mm_alloc_phys_mem(
pdev,
mem_size,
&ofld->hcopy_chain.bd_chain_phy,
PHYS_MEM_TYPE_UNSPECIFIED,
NULL);
if(ofld->hcopy_chain.bd_chain_virt == NULL)
{
return LM_STATUS_RESOURCE;
}
DbgBreakIf(ofld->hcopy_chain.bd_chain_phy.as_u32.low &
CACHE_LINE_SIZE_MASK);
ofld->hcopy_chain.cid_addr = GET_CID_ADDR(HCOPY_CID);
ofld->hcopy_chain.hw_con_idx_ptr =
&pdev->vars.status_virt->deflt.status_rx_quick_consumer_index15;
s_list_init(&ofld->hcopy_chain.pending_descq, NULL, NULL, 0);
s_list_init(&ofld->hcopy_chain.active_descq, NULL, NULL, 0);
}
ofld->cid_to_state = (lm_state_header_t **) mm_alloc_mem(
pdev,
sizeof(lm_state_header_t *) * MAX_CID,
NULL);
if(ofld->cid_to_state == NULL)
{
return LM_STATUS_RESOURCE;
}
return LM_STATUS_SUCCESS;
}
#endif
STATIC volatile u16_t *
sblk_tx_con_idx_ptr(
lm_device_t *pdev,
lm_tx_chain_t *txq)
{
volatile status_blk_combined_t *sblk;
volatile u16_t *idx_ptr;
sblk = pdev->vars.status_virt;
if(CHIP_NUM(pdev) == CHIP_NUM_5706 || CHIP_NUM(pdev) == CHIP_NUM_5708)
{
switch(txq->idx)
{
case TX_CHAIN_IDX0:
idx_ptr = &sblk->deflt.status_tx_quick_consumer_index0;
break;
case TX_CHAIN_IDX1:
idx_ptr = &sblk->deflt.status_tx_quick_consumer_index1;
break;
case TX_CHAIN_IDX2:
idx_ptr = &sblk->deflt.status_tx_quick_consumer_index2;
break;
case TX_CHAIN_IDX3:
idx_ptr = &sblk->deflt.status_tx_quick_consumer_index3;
break;
default:
idx_ptr = NULL;
DbgBreakIf(txq->idx != pdev->tx_info.cu_idx);
if(txq->idx == pdev->tx_info.cu_idx)
{
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index14;
}
break;
}
}
else
{
switch(txq->idx)
{
case TX_CHAIN_IDX0:
idx_ptr = &sblk->deflt.status_tx_quick_consumer_index0;
break;
case TX_CHAIN_IDX1:
idx_ptr = &sblk->deflt.status_tx_quick_consumer_index1;
break;
case TX_CHAIN_IDX2:
idx_ptr = &sblk->deflt.status_tx_quick_consumer_index2;
break;
case TX_CHAIN_IDX3:
idx_ptr = &sblk->deflt.status_tx_quick_consumer_index3;
break;
case TX_CHAIN_IDX4:
idx_ptr = &sblk->proc[0].status_pcpu_tx_quick_consumer_index;
break;
case TX_CHAIN_IDX5:
idx_ptr = &sblk->proc[1].status_pcpu_tx_quick_consumer_index;
break;
case TX_CHAIN_IDX6:
idx_ptr = &sblk->proc[2].status_pcpu_tx_quick_consumer_index;
break;
case TX_CHAIN_IDX7:
idx_ptr = &sblk->proc[3].status_pcpu_tx_quick_consumer_index;
break;
case TX_CHAIN_IDX8:
idx_ptr = &sblk->proc[4].status_pcpu_tx_quick_consumer_index;
break;
case TX_CHAIN_IDX9:
idx_ptr = &sblk->proc[5].status_pcpu_tx_quick_consumer_index;
break;
case TX_CHAIN_IDX10:
idx_ptr = &sblk->proc[6].status_pcpu_tx_quick_consumer_index;
break;
case TX_CHAIN_IDX11:
idx_ptr = &sblk->proc[7].status_pcpu_tx_quick_consumer_index;
break;
default:
DbgBreakMsg("invalid xinan tx index.\n");
idx_ptr = NULL;
break;
}
}
return idx_ptr;
}
STATIC lm_status_t
init_l2tx_resc(
lm_device_t *pdev)
{
lm_tx_chain_t *txq;
u32_t bd_page_cnt;
u32_t mem_size;
u32_t idx;
u32_t num_tx_chains;
#if defined(LM_NON_LEGACY_MODE_SUPPORT)
num_tx_chains = MAX_TX_CHAIN;
if(CHIP_NUM(pdev) == CHIP_NUM_5706 || CHIP_NUM(pdev) == CHIP_NUM_5708)
{
num_tx_chains = pdev->tx_info.num_txq;
}
#else
DbgBreakIf(pdev->tx_info.num_txq > MAX_TX_CHAIN);
for(idx = pdev->tx_info.num_txq; idx < MAX_TX_CHAIN; idx++)
{
pdev->params.l2_tx_bd_page_cnt[idx] = 0;
}
num_tx_chains = pdev->tx_info.num_txq;
#endif
for(idx = 0; idx < num_tx_chains; idx++)
{
txq = &pdev->tx_info.chain[idx];
txq->idx = idx;
txq->cid_addr = GET_CID_ADDR(L2TX_CID_BASE + 2 * txq->idx);
s_list_init(&txq->active_descq, NULL, NULL, 0);
if(CHIP_NUM(pdev) == CHIP_NUM_5706 || CHIP_NUM(pdev) == CHIP_NUM_5708)
{
DbgBreakIf(idx > 4);
if(txq->idx == pdev->tx_info.cu_idx && txq->idx != TX_CHAIN_IDX1)
{
DbgBreakIf(idx != 4);
txq->cid_addr = GET_CID_ADDR(30);
}
}
else if(txq->idx >= 4)
{
DbgBreakIf(idx > 11);
DbgBreakIf(pdev->tx_info.cu_idx != TX_CHAIN_IDX1);
if(txq->idx >= 4)
{
txq->cid_addr = GET_CID_ADDR(L2TX_TSS_CID_BASE + txq->idx - 4);
}
}
bd_page_cnt = pdev->params.l2_tx_bd_page_cnt[txq->idx];
if(bd_page_cnt)
{
mem_size = LM_PAGE_SIZE * bd_page_cnt;
txq->bd_chain_virt = (tx_bd_t *) mm_alloc_phys_mem(
pdev,
mem_size,
&txq->bd_chain_phy,
PHYS_MEM_TYPE_NONCACHED,
NULL);
if(txq->bd_chain_virt == NULL)
{
return LM_STATUS_RESOURCE;
}
DbgBreakIf(txq->bd_chain_phy.as_u32.low & CACHE_LINE_SIZE_MASK);
}
txq->hw_con_idx_ptr = sblk_tx_con_idx_ptr(pdev, txq);
}
return LM_STATUS_SUCCESS;
}
STATIC volatile u16_t *
sblk_rx_con_idx_ptr(
lm_device_t *pdev,
lm_rx_chain_t *rxq)
{
volatile status_blk_combined_t *sblk;
volatile u16_t *idx_ptr;
sblk = pdev->vars.status_virt;
if(CHIP_NUM(pdev) == CHIP_NUM_5706 || CHIP_NUM(pdev) == CHIP_NUM_5708)
{
switch(rxq->idx)
{
case RX_CHAIN_IDX0:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index0;
break;
case RX_CHAIN_IDX1:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index1;
break;
case RX_CHAIN_IDX2:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index2;
break;
case RX_CHAIN_IDX3:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index3;
break;
case RX_CHAIN_IDX4:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index4;
break;
case RX_CHAIN_IDX5:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index5;
break;
case RX_CHAIN_IDX6:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index6;
break;
case RX_CHAIN_IDX7:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index7;
break;
case RX_CHAIN_IDX8:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index8;
break;
case RX_CHAIN_IDX9:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index9;
break;
case RX_CHAIN_IDX10:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index10;
break;
case RX_CHAIN_IDX11:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index11;
break;
case RX_CHAIN_IDX12:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index12;
break;
case RX_CHAIN_IDX13:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index13;
break;
case RX_CHAIN_IDX14:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index14;
break;
case RX_CHAIN_IDX15:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index15;
break;
default:
DbgBreakMsg("invalid teton rx index.\n");
idx_ptr = NULL;
break;
}
}
else
{
switch(rxq->idx)
{
case RX_CHAIN_IDX0:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index0;
break;
case RX_CHAIN_IDX1:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index1;
break;
case RX_CHAIN_IDX2:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index2;
break;
case RX_CHAIN_IDX3:
idx_ptr = &sblk->deflt.status_rx_quick_consumer_index3;
break;
case RX_CHAIN_IDX4:
idx_ptr = &sblk->proc[0].status_pcpu_rx_quick_consumer_index;
break;
case RX_CHAIN_IDX5:
idx_ptr = &sblk->proc[1].status_pcpu_rx_quick_consumer_index;
break;
case RX_CHAIN_IDX6:
idx_ptr = &sblk->proc[2].status_pcpu_rx_quick_consumer_index;
break;
case RX_CHAIN_IDX7:
idx_ptr = &sblk->proc[3].status_pcpu_rx_quick_consumer_index;
break;
case RX_CHAIN_IDX8:
idx_ptr = &sblk->proc[4].status_pcpu_rx_quick_consumer_index;
break;
case RX_CHAIN_IDX9:
idx_ptr = &sblk->proc[5].status_pcpu_rx_quick_consumer_index;
break;
case RX_CHAIN_IDX10:
idx_ptr = &sblk->proc[6].status_pcpu_rx_quick_consumer_index;
break;
case RX_CHAIN_IDX11:
idx_ptr = &sblk->proc[7].status_pcpu_rx_quick_consumer_index;
break;
default:
DbgBreakMsg("invalid xinan rx index.\n");
idx_ptr = NULL;
break;
}
}
return idx_ptr;
}
STATIC lm_status_t
alloc_l2rx_desc(
lm_device_t *pdev,
lm_rx_chain_t *rxq)
{
u32_t bd_page_cnt;
lm_packet_t *pkt;
u32_t desc_size;
u32_t desc_cnt;
u8_t *mem_virt;
u32_t mem_size;
u32_t idx;
bd_page_cnt = pdev->params.l2_rx_bd_page_cnt[rxq->idx];
desc_cnt = pdev->params.l2_rx_desc_cnt[rxq->idx];
if(bd_page_cnt == 0 || desc_cnt == 0)
{
pdev->params.l2_rx_bd_page_cnt[rxq->idx] = 0;
pdev->params.l2_rx_desc_cnt[rxq->idx] = 0;
return LM_STATUS_SUCCESS;
}
mem_size = LM_PAGE_SIZE * bd_page_cnt;
rxq->bd_chain_virt = (rx_bd_t *) mm_alloc_phys_mem(
pdev,
mem_size,
&rxq->bd_chain_phy,
PHYS_MEM_TYPE_NONCACHED,
NULL);
if(rxq->bd_chain_virt == NULL)
{
return LM_STATUS_RESOURCE;
}
DbgBreakIf(rxq->bd_chain_phy.as_u32.low & CACHE_LINE_SIZE_MASK);
#ifndef LM_NON_LEGACY_MODE_SUPPORT
desc_size = mm_desc_size(pdev, DESC_TYPE_L2RX_PACKET) + SIZEOF_SIG;
mem_size = desc_size * desc_cnt;
mem_virt = (u8_t *) mm_alloc_mem(pdev, mem_size, NULL);
if(mem_virt == NULL)
{
return LM_STATUS_RESOURCE;
}
for(idx = 0; idx < desc_cnt; idx++)
{
pkt = (lm_packet_t *) (mem_virt + SIZEOF_SIG);
mem_virt += desc_size;
mem_size -= desc_size;
SIG(pkt) = L2PACKET_RX_SIG;
pkt->u1.rx.buf_size = pdev->params.mtu + 4;
pkt->u1.rx.buf_size += L2RX_FRAME_HDR_LEN;
pkt->u1.rx.buf_size += pdev->params.rcv_buffer_offset;
pkt->u1.rx.buf_size += CACHE_LINE_SIZE_MASK + 1;
pkt->u1.rx.buf_size &= ~CACHE_LINE_SIZE_MASK;
s_list_push_tail(&rxq->free_descq, &pkt->link);
}
DbgBreakIf(mem_size);
DbgBreakIf(s_list_entry_cnt(&rxq->free_descq) != desc_cnt);
#endif
return LM_STATUS_SUCCESS;
}
STATIC lm_status_t
init_l2rx_resc(
lm_device_t *pdev)
{
lm_status_t lm_status;
lm_rx_chain_t *rxq;
u32_t idx;
#ifndef LM_NON_LEGACY_MODE_SUPPORT
DbgBreakIf(pdev->rx_info.num_rxq > MAX_RX_CHAIN);
for(idx = pdev->rx_info.num_rxq; idx < MAX_RX_CHAIN; idx++)
{
pdev->params.l2_rx_desc_cnt[idx] = 0;
pdev->params.l2_rx_bd_page_cnt[idx] = 0;
}
#endif
for(idx = 0; idx < pdev->rx_info.num_rxq ; idx++)
{
rxq = &pdev->rx_info.chain[idx];
rxq->idx = idx;
rxq->cid_addr = GET_CID_ADDR(L2RX_CID_BASE + rxq->idx);
s_list_init(&rxq->free_descq, NULL, NULL, 0);
s_list_init(&rxq->active_descq, NULL, NULL, 0);
lm_status = alloc_l2rx_desc(pdev, rxq);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
rxq->hw_con_idx_ptr = sblk_rx_con_idx_ptr(pdev, rxq);
}
return LM_STATUS_SUCCESS;
}
STATIC lm_status_t
init_context_resc_5709(
lm_device_t *pdev)
{
phy_mem_block_t *ctx_mem;
u32_t page_align_delta;
lm_address_t mem_phy;
u32_t ctx_in_mblk;
u32_t mem_size;
u8_t *mem_virt;
u32_t ctx_cnt;
DbgBreakIf(CHIP_NUM(pdev) != CHIP_NUM_5709);
DbgBreakIf(CTX_MBLK_SIZE & LM_PAGE_MASK);
DbgBreakIf(MAX_CTX > 16 * 1024);
DbgBreakIf(MAX_CTX * ONE_CTX_SIZE / CTX_MBLK_SIZE != NUM_CTX_MBLKS);
DbgBreakIf((MAX_CTX * ONE_CTX_SIZE) % CTX_MBLK_SIZE);
ctx_mem = &pdev->vars.ctx_mem[0];
ctx_cnt = 0;
while(ctx_cnt < MAX_CTX)
{
ctx_in_mblk = CTX_MBLK_SIZE / ONE_CTX_SIZE;
if(ctx_cnt + ctx_in_mblk > MAX_CTX)
{
ctx_in_mblk = MAX_CTX - ctx_cnt;
}
mem_size = ctx_in_mblk * ONE_CTX_SIZE;
mem_virt = (u8_t *) mm_alloc_phys_mem(
pdev,
mem_size + LM_PAGE_MASK,
&mem_phy,
PHYS_MEM_TYPE_NONCACHED,
NULL);
if(mem_virt == NULL)
{
return LM_STATUS_RESOURCE;
}
page_align_delta = mem_phy.as_u32.low & LM_PAGE_MASK;
if(page_align_delta)
{
page_align_delta = LM_PAGE_SIZE - page_align_delta;
}
mem_virt += page_align_delta;
LM_INC64(&mem_phy, page_align_delta);
ctx_mem->start_phy = mem_phy;
ctx_mem->start = mem_virt;
ctx_mem->size = mem_size;
ctx_mem++;
ctx_cnt += mem_size / ONE_CTX_SIZE;
}
return LM_STATUS_SUCCESS;
}
lm_status_t
lm_init_resc(
lm_device_t *pdev)
{
lm_status_t lm_status;
lm_address_t mem_phy;
u8_t *mem_virt;
u32_t mem_size;
#ifndef EXCLUDE_KQE_SUPPORT
lm_status = init_kwq_resc(pdev);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
lm_status = init_kcq_resc(pdev);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
#endif
#if INCLUDE_OFLD_SUPPORT
lm_status = init_ofld_resc(pdev);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
#endif
DbgBreakIf(sizeof(status_blk_combined_t) > STATUS_BLOCK_BUFFER_SIZE);
DbgBreakIf(sizeof(statistics_block_t) > CHIP_STATS_BUFFER_SIZE);
mem_size = STATUS_BLOCK_BUFFER_SIZE +
#ifndef EXCLUDE_RSS_SUPPORT
RSS_INDIRECTION_TABLE_SIZE +
RSS_LOOKUP_TABLE_WA +
#endif
CHIP_STATS_BUFFER_SIZE;
mem_virt = mm_alloc_phys_mem(
pdev,
mem_size,
&mem_phy,
PHYS_MEM_TYPE_NONCACHED,
NULL);
if(mem_virt == NULL)
{
return LM_STATUS_RESOURCE;
}
DbgBreakIf(mem_phy.as_u32.low & CACHE_LINE_SIZE_MASK);
pdev->vars.status_virt = (status_blk_combined_t *) mem_virt;
pdev->vars.status_phy = mem_phy;
mem_virt += STATUS_BLOCK_BUFFER_SIZE;
LM_INC64(&mem_phy, STATUS_BLOCK_BUFFER_SIZE);
pdev->vars.stats_virt = (statistics_block_t *) mem_virt;
pdev->vars.stats_phy = mem_phy;
mem_virt += CHIP_STATS_BUFFER_SIZE;
LM_INC64(&mem_phy, CHIP_STATS_BUFFER_SIZE);
#ifndef EXCLUDE_RSS_SUPPORT
pdev->rx_info.rss_ind_table_virt = mem_virt;
pdev->rx_info.rss_ind_table_phy = mem_phy;
#endif
if(CHIP_NUM(pdev) == CHIP_NUM_5709)
{
lm_status = init_context_resc_5709(pdev);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
}
lm_status = init_l2tx_resc(pdev);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
lm_status = init_l2rx_resc(pdev);
if(lm_status != LM_STATUS_SUCCESS)
{
return lm_status;
}
lm_clear_nwuf(pdev);
return LM_STATUS_SUCCESS;
}
STATIC u32_t
compute_crc32(
u8_t *buf,
u32_t buf_size)
{
u32_t reg;
u32_t tmp;
u32_t j;
u32_t k;
reg = 0xffffffff;
for(j = 0; j < buf_size; j++)
{
reg ^= buf[j];
for(k = 0; k < 8; k++)
{
tmp = reg & 0x01;
reg >>= 1;
if(tmp)
{
reg ^= 0xedb88320;
}
}
}
return ~reg;
}
#define NUM_MC_HASH_REGISTERS 8
STATIC void
set_mc_hash_reg(
lm_device_t *pdev,
lm_mc_table_t *mc_table)
{
u32_t hash_reg[NUM_MC_HASH_REGISTERS];
u32_t reg_idx;
u32_t bit_pos;
u32_t idx;
u32_t crc32;
for(idx = 0; idx < NUM_MC_HASH_REGISTERS; idx++)
{
hash_reg[idx] = 0;
}
for(idx = 0; idx < mc_table->entry_cnt; idx++)
{
crc32 = compute_crc32(
mc_table->addr_arr[idx].mc_addr,
ETHERNET_ADDRESS_SIZE);
bit_pos = ~crc32 & 0xff;
reg_idx = (bit_pos & 0xe0) >> 5;
bit_pos &= 0x1f;
hash_reg[reg_idx] |= (1 << bit_pos);
}
for(idx = 0; idx < NUM_MC_HASH_REGISTERS; idx++)
{
REG_WR(pdev, emac.emac_multicast_hash[idx], hash_reg[idx]);
}
}
lm_status_t
lm_set_rx_mask(
lm_device_t *pdev,
u32_t user_idx,
lm_rx_mask_t rx_mask)
{
u32_t combined_rx_mask;
u32_t invalid_rx_mask;
u32_t sort_mode;
u32_t rx_mode;
u32_t val;
u32_t idx;
if(user_idx >= MAX_RX_FILTER_USER_CNT)
{
DbgBreakMsg("invalid user index.\n");
return LM_STATUS_FAILURE;
}
combined_rx_mask = rx_mask;
for(idx = 0; idx < MAX_RX_FILTER_USER_CNT; idx++)
{
if(idx != user_idx)
{
combined_rx_mask |= pdev->rx_info.mask[idx];
}
}
invalid_rx_mask = combined_rx_mask;
REG_RD(pdev, emac.emac_rx_mode, &rx_mode);
if(invalid_rx_mask & LM_RX_MASK_ACCEPT_UNICAST)
{
invalid_rx_mask &= ~LM_RX_MASK_ACCEPT_UNICAST;
}
if(invalid_rx_mask & LM_RX_MASK_ACCEPT_MULTICAST)
{
invalid_rx_mask &= ~LM_RX_MASK_ACCEPT_MULTICAST;
}
if(invalid_rx_mask & LM_RX_MASK_ACCEPT_ALL_MULTICAST)
{
invalid_rx_mask &= ~LM_RX_MASK_ACCEPT_ALL_MULTICAST;
}
rx_mode &= ~EMAC_RX_MODE_FILT_BROADCAST;
if(invalid_rx_mask & LM_RX_MASK_ACCEPT_BROADCAST)
{
invalid_rx_mask &= ~LM_RX_MASK_ACCEPT_BROADCAST;
}
else
{
rx_mode |= EMAC_RX_MODE_FILT_BROADCAST;
}
rx_mode &= ~(EMAC_RX_MODE_ACCEPT_RUNTS | EMAC_RX_MODE_ACCEPT_OVERSIZE);
if(invalid_rx_mask & LM_RX_MASK_ACCEPT_ERROR_PACKET)
{
invalid_rx_mask &= ~LM_RX_MASK_ACCEPT_ERROR_PACKET;
rx_mode |= EMAC_RX_MODE_ACCEPT_RUNTS |
EMAC_RX_MODE_ACCEPT_OVERSIZE |
EMAC_RX_MODE_NO_CRC_CHK;
}
rx_mode &= ~EMAC_RX_MODE_PROMISCUOUS;
if(invalid_rx_mask & LM_RX_MASK_PROMISCUOUS_MODE)
{
invalid_rx_mask &= ~LM_RX_MASK_PROMISCUOUS_MODE;
rx_mode |= EMAC_RX_MODE_PROMISCUOUS;
}
if(invalid_rx_mask)
{
DbgBreakMsg("Unknown rx_mask.\n");
return LM_STATUS_FAILURE;
}
if(combined_rx_mask & LM_RX_MASK_ACCEPT_ALL_MULTICAST)
{
for(idx = 0; idx < NUM_MC_HASH_REGISTERS; idx++)
{
REG_WR(pdev, emac.emac_multicast_hash[idx], 0xffffffff);
}
}
else if(combined_rx_mask & LM_RX_MASK_ACCEPT_MULTICAST)
{
set_mc_hash_reg(pdev, &pdev->mc_table);
}
else
{
for(idx = 0; idx < NUM_MC_HASH_REGISTERS; idx++)
{
REG_WR(pdev, emac.emac_multicast_hash[idx], 0);
}
}
pdev->rx_info.mask[user_idx] = rx_mask;
val = rx_mode | EMAC_RX_MODE_SORT_MODE;
if(pdev->params.keep_vlan_tag)
{
val |= EMAC_RX_MODE_KEEP_VLAN_TAG;
}
REG_WR(pdev, emac.emac_rx_mode, val);
sort_mode = 0;
if(rx_mask & LM_RX_MASK_ACCEPT_UNICAST)
{
sort_mode |= 1 << user_idx;
}
if(rx_mask & LM_RX_MASK_ACCEPT_MULTICAST)
{
sort_mode |= RPM_SORT_USER0_MC_HSH_EN;
}
if(rx_mask & LM_RX_MASK_ACCEPT_ALL_MULTICAST)
{
sort_mode |= RPM_SORT_USER0_MC_EN;
}
if(rx_mask & LM_RX_MASK_ACCEPT_BROADCAST)
{
sort_mode |= RPM_SORT_USER0_BC_EN;
}
if(rx_mask & LM_RX_MASK_PROMISCUOUS_MODE)
{
sort_mode |= RPM_SORT_USER0_PROM_EN | RPM_SORT_USER0_PROM_VLAN;
}
switch(user_idx)
{
case RX_FILTER_USER_IDX0:
REG_RD(pdev, rpm.rpm_sort_user0, &val);
REG_WR(pdev, rpm.rpm_sort_user0, 0x00000000);
REG_WR(pdev, rpm.rpm_sort_user0, sort_mode);
val &= 0xffff;
val &= ~(1 << user_idx);
sort_mode |= val | RPM_SORT_USER0_ENA;
REG_WR(pdev, rpm.rpm_sort_user0, sort_mode);
break;
case RX_FILTER_USER_IDX1:
REG_RD(pdev, rpm.rpm_sort_user1, &val);
REG_WR(pdev, rpm.rpm_sort_user1, 0x00000000);
REG_WR(pdev, rpm.rpm_sort_user1, sort_mode);
val &= 0xffff;
val &= ~(1 << user_idx);
sort_mode |= val | RPM_SORT_USER0_ENA;
REG_WR(pdev, rpm.rpm_sort_user1, sort_mode);
break;
case RX_FILTER_USER_IDX2:
REG_RD(pdev, rpm.rpm_sort_user2, &val);
REG_WR(pdev, rpm.rpm_sort_user2, 0x00000000);
REG_WR(pdev, rpm.rpm_sort_user2, sort_mode);
val &= 0xffff;
val &= ~(1 << user_idx);
sort_mode |= val | RPM_SORT_USER0_ENA;
REG_WR(pdev, rpm.rpm_sort_user2, sort_mode);
break;
case RX_FILTER_USER_IDX3:
REG_RD(pdev, rpm.rpm_sort_user3, &val);
REG_WR(pdev, rpm.rpm_sort_user3, 0x00000000);
REG_WR(pdev, rpm.rpm_sort_user3, sort_mode);
val &= 0xffff;
val &= ~(1 << user_idx);
sort_mode |= val | RPM_SORT_USER0_ENA;
REG_WR(pdev, rpm.rpm_sort_user3, sort_mode);
break;
default:
DbgBreakMsg("invalid user idx.\n");
break;
}
REG_RD_IND(pdev, 0xe0024, &val);
val &= ~(1 << user_idx);
if(rx_mask & (LM_RX_MASK_ACCEPT_MULTICAST |
LM_RX_MASK_ACCEPT_ALL_MULTICAST |
LM_RX_MASK_ACCEPT_BROADCAST |
LM_RX_MASK_PROMISCUOUS_MODE))
{
val |= (1 << user_idx);
}
REG_WR_IND(pdev, 0xe0024, val);
return LM_STATUS_SUCCESS;
}
lm_status_t
lm_add_mc(
lm_device_t *pdev,
u8_t *mc_addr)
{
lm_mc_entry_t *mc_entry;
u32_t cnt;
DbgMessage(pdev, VERBOSE, "### lm_add_mc\n");
for(cnt = 0; cnt < pdev->mc_table.entry_cnt; cnt++)
{
mc_entry = &pdev->mc_table.addr_arr[cnt];
if(IS_ETH_ADDRESS_EQUAL(mc_entry->mc_addr, mc_addr))
{
mc_entry->ref_cnt++;
return LM_STATUS_SUCCESS;
}
}
if(pdev->mc_table.entry_cnt >= LM_MAX_MC_TABLE_SIZE)
{
DbgBreakMsg("No entry in MC table\n");
return LM_STATUS_FAILURE;
}
mc_entry = &pdev->mc_table.addr_arr[pdev->mc_table.entry_cnt];
pdev->mc_table.entry_cnt++;
mc_entry->ref_cnt = 1;
COPY_ETH_ADDRESS(mc_addr, mc_entry->mc_addr);
(void) lm_set_rx_mask(
pdev,
RX_FILTER_USER_IDX0,
pdev->rx_info.mask[RX_FILTER_USER_IDX0] | LM_RX_MASK_ACCEPT_MULTICAST);
return LM_STATUS_SUCCESS;
}
lm_status_t
lm_del_mc(
lm_device_t *pdev,
u8_t *mc_addr)
{
lm_mc_entry_t *mc_entry;
u32_t cnt;
for(cnt = 0; cnt < pdev->mc_table.entry_cnt; cnt++)
{
mc_entry = &pdev->mc_table.addr_arr[cnt];
if(IS_ETH_ADDRESS_EQUAL(mc_entry->mc_addr, mc_addr))
{
mc_entry->ref_cnt--;
if(mc_entry->ref_cnt == 0)
{
if(pdev->mc_table.entry_cnt > 1)
{
*mc_entry = pdev->mc_table.addr_arr[pdev->mc_table.entry_cnt-1];
}
pdev->mc_table.entry_cnt--;
if(pdev->mc_table.entry_cnt == 0)
{
pdev->rx_info.mask[RX_FILTER_USER_IDX0] &=
~LM_RX_MASK_ACCEPT_MULTICAST;
}
(void) lm_set_rx_mask(
pdev,
RX_FILTER_USER_IDX0,
pdev->rx_info.mask[RX_FILTER_USER_IDX0]);
}
return LM_STATUS_SUCCESS;
}
}
DbgBreakMsg("Mc address not in the table\n");
return LM_STATUS_FAILURE;
}
void
lm_clear_mc(lm_device_t *pdev)
{
DbgMessage(pdev, VERBOSE, "### lm_clear_mc\n");
pdev->mc_table.entry_cnt = 0;
(void) lm_set_rx_mask(
pdev,
RX_FILTER_USER_IDX0,
pdev->rx_info.mask[RX_FILTER_USER_IDX0] & ~LM_RX_MASK_ACCEPT_MULTICAST);
}
lm_status_t
lm_get_stats(
lm_device_t *pdev,
lm_stats_t stats_type,
u64_t *stats_cnt)
{
volatile statistics_block_t *sb;
lm_status_t lm_status;
lm_u64_t *stats;
u32_t reg_val;
u32_t val;
REG_WR(pdev, hc.hc_command, HC_COMMAND_STATS_NOW);
REG_RD(pdev, hc.hc_command, ®_val);
mm_wait(pdev, 5);
lm_status = LM_STATUS_SUCCESS;
sb = pdev->vars.stats_virt;
stats = (lm_u64_t *) stats_cnt;
switch(stats_type)
{
case LM_STATS_FRAMES_XMITTED_OK:
stats->as_u32.low = sb->stat_IfHCOutUcastPkts_lo;
stats->as_u32.high = sb->stat_IfHCOutUcastPkts_hi;
LM_INC64(stats, sb->stat_IfHCOutMulticastPkts_lo);
stats->as_u32.high += sb->stat_IfHCOutMulticastPkts_hi;
LM_INC64(stats, sb->stat_IfHCOutBroadcastPkts_lo);
stats->as_u32.high += sb->stat_IfHCOutBroadcastPkts_hi;
break;
case LM_STATS_FRAMES_RECEIVED_OK:
stats->as_u32.low = sb->stat_IfHCInUcastPkts_lo;
stats->as_u32.high = sb->stat_IfHCInUcastPkts_hi;
LM_INC64(stats, sb->stat_IfHCInMulticastPkts_lo);
stats->as_u32.high += sb->stat_IfHCInMulticastPkts_hi;
LM_INC64(stats, sb->stat_IfHCInBroadcastPkts_lo);
stats->as_u32.high += sb->stat_IfHCInBroadcastPkts_hi;
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t,
com.com_scratch[0])+
COM_HSI_OFFSETOFF(com_l2_iscsi_no_buffer),
&val);
if((stats->as_u32.high == 0 && stats->as_u32.low) &&
(stats->as_u32.low < val))
{
stats->as_u32.low = 0;
}
else
{
LM_DEC64(stats, val);
}
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t,
com.com_scratch[0])+
COM_HSI_OFFSETOFF(com_l2_no_buffer),
&val);
if((stats->as_u32.high == 0 && stats->as_u32.low) &&
(stats->as_u32.low < val))
{
stats->as_u32.low = 0;
}
else
{
LM_DEC64(stats, val);
}
break;
case LM_STATS_ERRORED_RECEIVE_CNT:
stats->as_u32.low = pdev->rx_info.stats.err;
stats->as_u32.high = 0;
break;
case LM_STATS_RCV_CRC_ERROR:
stats->as_u32.low = sb->stat_Dot3StatsFCSErrors;
stats->as_u32.high = 0;
break;
case LM_STATS_ALIGNMENT_ERROR:
stats->as_u32.low = sb->stat_Dot3StatsAlignmentErrors;
stats->as_u32.high = 0;
break;
case LM_STATS_SINGLE_COLLISION_FRAMES:
stats->as_u32.low = sb->stat_Dot3StatsSingleCollisionFrames;
stats->as_u32.high = 0;
break;
case LM_STATS_MULTIPLE_COLLISION_FRAMES:
stats->as_u32.low = sb->stat_Dot3StatsMultipleCollisionFrames;
stats->as_u32.high = 0;
break;
case LM_STATS_FRAMES_DEFERRED:
stats->as_u32.low = sb->stat_Dot3StatsDeferredTransmissions;
stats->as_u32.high = 0;
break;
case LM_STATS_MAX_COLLISIONS:
stats->as_u32.low = sb->stat_Dot3StatsExcessiveCollisions;
break;
case LM_STATS_UNICAST_FRAMES_XMIT:
stats->as_u32.low = sb->stat_IfHCOutUcastPkts_lo;
stats->as_u32.high = sb->stat_IfHCOutUcastPkts_hi;
break;
case LM_STATS_MULTICAST_FRAMES_XMIT:
stats->as_u32.low = sb->stat_IfHCOutMulticastPkts_lo;
stats->as_u32.high = sb->stat_IfHCOutMulticastPkts_hi;
break;
case LM_STATS_BROADCAST_FRAMES_XMIT:
stats->as_u32.low = sb->stat_IfHCOutBroadcastPkts_lo;
stats->as_u32.high = sb->stat_IfHCOutBroadcastPkts_hi;
break;
case LM_STATS_UNICAST_FRAMES_RCV:
stats->as_u32.low = sb->stat_IfHCInUcastPkts_lo;
stats->as_u32.high = sb->stat_IfHCInUcastPkts_hi;
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t,
com.com_scratch[0])+
COM_HSI_OFFSETOFF(com_unicast_no_buffer),
&val);
if((stats->as_u32.high == 0 && stats->as_u32.low) &&
(stats->as_u32.low < val))
{
stats->as_u32.low = 0;
}
else
{
LM_DEC64(stats, val);
}
break;
case LM_STATS_MULTICAST_FRAMES_RCV:
stats->as_u32.low = sb->stat_IfHCInMulticastPkts_lo;
stats->as_u32.high = sb->stat_IfHCInMulticastPkts_hi;
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t,
com.com_scratch[0])+
COM_HSI_OFFSETOFF(com_mcast_no_buffer),
&val);
if((stats->as_u32.high == 0 && stats->as_u32.low) &&
(stats->as_u32.low < val))
{
stats->as_u32.low = 0;
}
else
{
LM_DEC64(stats, val);
}
break;
case LM_STATS_BROADCAST_FRAMES_RCV:
stats->as_u32.low = sb->stat_IfHCInBroadcastPkts_lo;
stats->as_u32.high = sb->stat_IfHCInBroadcastPkts_hi;
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t,
com.com_scratch[0])+
COM_HSI_OFFSETOFF(com_bcast_no_buffer),
&val);
if((stats->as_u32.high == 0 && stats->as_u32.low) &&
(stats->as_u32.low < val))
{
stats->as_u32.low = 0;
}
else
{
LM_DEC64(stats, val);
}
break;
case LM_STATS_ERRORED_TRANSMIT_CNT:
case LM_STATS_RCV_OVERRUN:
case LM_STATS_XMIT_UNDERRUN:
stats->as_u32.low = 0;
stats->as_u32.high = 0;
break;
case LM_STATS_RCV_NO_BUFFER_DROP:
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, com.com_scratch[0])+COM_HSI_OFFSETOFF(com_unicast_no_buffer),
&val);
stats->as_u32.low = val;
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, com.com_scratch[0])+COM_HSI_OFFSETOFF(com_mcast_no_buffer),
&val);
stats->as_u32.low += val;
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, com.com_scratch[0])+COM_HSI_OFFSETOFF(com_bcast_no_buffer),
&val);
stats->as_u32.low += val;
stats->as_u32.high = 0;
break;
case LM_STATS_BYTES_RCV:
stats->as_u32.low = sb->stat_IfHCInOctets_lo;
stats->as_u32.high = sb->stat_IfHCInOctets_hi;
break;
case LM_STATS_BYTES_XMIT:
stats->as_u32.low = sb->stat_IfHCOutOctets_lo;
stats->as_u32.high = sb->stat_IfHCOutOctets_hi;
break;
case LM_STATS_IF_IN_DISCARDS:
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, com.com_scratch[0])+COM_HSI_OFFSETOFF(com_unicast_no_buffer),
&val);
stats->as_u32.low = val;
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, com.com_scratch[0])+COM_HSI_OFFSETOFF(com_mcast_no_buffer),
&val);
stats->as_u32.low += val;
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, com.com_scratch[0])+COM_HSI_OFFSETOFF(com_bcast_no_buffer),
&val);
stats->as_u32.low += val;
stats->as_u32.low += sb->stat_Dot3StatsFCSErrors;
stats->as_u32.high = 0;
break;
case LM_STATS_XMIT_DISCARDS:
case LM_STATS_IF_IN_ERRORS:
case LM_STATS_IF_OUT_ERRORS:
stats->as_u32.low = 0;
stats->as_u32.high = 0;
break;
case LM_STATS_DIRECTED_BYTES_RCV:
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, rxp.rxp_scratch[0])+RXP_HSI_OFFSETOFF(rxp_unicast_bytes_rcvd)+4,
&stats->as_u32.low);
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, rxp.rxp_scratch[0])+RXP_HSI_OFFSETOFF(rxp_unicast_bytes_rcvd),
&stats->as_u32.high);
break;
case LM_STATS_MULTICAST_BYTES_RCV:
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, rxp.rxp_scratch[0])+RXP_HSI_OFFSETOFF(rxp_multicast_bytes_rcvd)+4,
&stats->as_u32.low);
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, rxp.rxp_scratch[0])+RXP_HSI_OFFSETOFF(rxp_multicast_bytes_rcvd),
&stats->as_u32.high);
break;
case LM_STATS_BROADCAST_BYTES_RCV:
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, rxp.rxp_scratch[0])+RXP_HSI_OFFSETOFF(rxp_broadcast_bytes_rcvd)+4,
&stats->as_u32.low);
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, rxp.rxp_scratch[0])+RXP_HSI_OFFSETOFF(rxp_broadcast_bytes_rcvd),
&stats->as_u32.high);
break;
case LM_STATS_DIRECTED_BYTES_XMIT:
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, tpat.tpat_scratch[0])+TPAT_HSI_OFFSETOFF(unicast_bytes_xmit)+4,
&stats->as_u32.low);
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, tpat.tpat_scratch[0])+TPAT_HSI_OFFSETOFF(unicast_bytes_xmit),
&stats->as_u32.high);
break;
case LM_STATS_MULTICAST_BYTES_XMIT:
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, tpat.tpat_scratch[0])+TPAT_HSI_OFFSETOFF(multicast_bytes_xmit)+4,
&stats->as_u32.low);
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, tpat.tpat_scratch[0])+TPAT_HSI_OFFSETOFF(multicast_bytes_xmit),
&stats->as_u32.high);
break;
case LM_STATS_BROADCAST_BYTES_XMIT:
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, tpat.tpat_scratch[0])+TPAT_HSI_OFFSETOFF(broadcast_bytes_xmit)+4,
&stats->as_u32.low);
REG_RD_IND(
pdev,
OFFSETOF(reg_space_t, tpat.tpat_scratch[0])+TPAT_HSI_OFFSETOFF(broadcast_bytes_xmit),
&stats->as_u32.high);
break;
default:
stats->as_u32.low = 0;
stats->as_u32.high = 0;
lm_status = LM_STATUS_INVALID_PARAMETER;
break;
}
return lm_status;
}
STATIC lm_nwuf_t *
find_nwuf(
lm_nwuf_list_t *nwuf_list,
u32_t mask_size,
u8_t *byte_mask,
u8_t *pattern,
u32_t max_nwuf_cnt)
{
lm_nwuf_t *nwuf;
u8_t found;
u32_t idx;
u32_t j;
u32_t k;
for(idx = 0; idx < max_nwuf_cnt; idx++)
{
nwuf = &nwuf_list->nwuf_arr[idx];
if((nwuf->size&0xffff) != 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 pattern_size,
u32_t mask_size,
u8_t *byte_mask,
u8_t *pattern)
{
lm_nwuf_t *nwuf;
u32_t idx;
u32_t j;
u32_t k;
u32_t l;
u32_t combind_size;
u32_t max_nwuf_cnt;
if(CHIP_NUM(pdev) == CHIP_NUM_5709)
{
max_nwuf_cnt = LM_MAX_NWUF_CNT_5709;
}
else
{
max_nwuf_cnt = LM_MAX_NWUF_CNT;
}
combind_size = (pattern_size<<16) & 0xffff0000;
combind_size |= mask_size;
pattern_size &= 0xffff;
mask_size &= 0xffff;
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,
max_nwuf_cnt);
if(nwuf)
{
DbgMessage(pdev, INFORM, "Duplicated nwuf entry.\n");
return LM_STATUS_EXISTING_OBJECT;
}
nwuf = NULL;
for(idx = 0; idx < max_nwuf_cnt; idx++)
{
if(pdev->nwuf_list.nwuf_arr[idx].size == 0)
{
nwuf = &pdev->nwuf_list.nwuf_arr[idx];
break;
}
}
if(nwuf == NULL)
{
DbgMessage(pdev, WARN, "Cannot add Nwuf, exceeded maximum.\n");
return LM_STATUS_RESOURCE;
}
pdev->nwuf_list.cnt++;
nwuf->size = mask_size;
if (pattern_size)
{
nwuf->size = combind_size;
goto _handle_win7_pattern;
}
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];
}
else
{
nwuf->pattern[j*8 + k] = 0;
}
}
}
if(byte_mask[mask_size-1])
{
k = 8;
while(k)
{
k--;
if(byte_mask[mask_size-1] & (1 << k))
{
break;
}
nwuf->pattern[(mask_size-1)*8 + k] = 0xff;
}
}
for(j = mask_size; j < LM_NWUF_PATTERN_MASK_SIZE; j++)
{
nwuf->mask[j] = 0;
for(k = 0; k < 8; k++)
{
nwuf->pattern[j*8 + k] = 0xff;
}
}
return LM_STATUS_SUCCESS;
_handle_win7_pattern:
l=0;
#ifdef LINUX
{
u8_t idx;
for (idx=0; idx< LM_NWUF_PATTERN_MASK_SIZE; idx++)
nwuf->mask[idx] = 0;
}
#else
memset(nwuf->mask,0,LM_NWUF_PATTERN_MASK_SIZE);
#endif
for(j = 0; j < mask_size ; j++)
{
nwuf->mask[j] = byte_mask[j];
for(k = 0; k < 8 ; k++)
{
if ( l<pattern_size )
{
if(byte_mask[j] & (1 << k))
{
nwuf->pattern[j*8 + k] = pattern[j*8 + k];
}
else
{
nwuf->pattern[j*8 + k] = 0;
}
}
else
{
nwuf->pattern[j*8 + k] = 0xff;
}
l++;
}
}
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;
u32_t max_nwuf_cnt;
if(CHIP_NUM(pdev) == CHIP_NUM_5709)
{
max_nwuf_cnt = LM_MAX_NWUF_CNT_5709;
}
else
{
max_nwuf_cnt = LM_MAX_NWUF_CNT;
}
mask_size &= 0xffff;
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,
max_nwuf_cnt);
if(nwuf == NULL)
{
return LM_STATUS_OBJECT_NOT_FOUND;
}
nwuf->size = 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--;
return LM_STATUS_SUCCESS;
}
void
lm_clear_nwuf(
lm_device_t *pdev)
{
u32_t j;
u32_t k;
u32_t max_nwuf_cnt;
if(CHIP_NUM(pdev) == CHIP_NUM_5709)
{
max_nwuf_cnt = LM_MAX_NWUF_CNT_5709;
}
else
{
max_nwuf_cnt = LM_MAX_NWUF_CNT;
}
for(j = 0; j < 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;
}
STATIC u32_t
init_nwuf_5709(
lm_device_t *pdev,
lm_nwuf_list_t *nwuf_list)
{
lm_nwuf_t *nwuf;
u16_t prev_val;
u32_t nwuf_len;
u32_t nwuf_cnt;
u32_t offset;
u8_t mask;
u32_t val;
u32_t idx;
u8_t bit;
u16_t pattern_size;
u32_t nwuf_size[LM_MAX_NWUF_CNT_5709];
DbgBreakIf(CHIP_NUM(pdev) != CHIP_NUM_5709);
DbgBreakIf(LM_NWUF_PATTERN_SIZE > 128);
DbgBreakIf(LM_MAX_NWUF_CNT_5709 > 8);
REG_WR(pdev, rpm.rpm_acpi_byte_enable_ctrl, RPM_ACPI_BYTE_ENABLE_CTRL_INIT);
for(idx = 0; idx < LM_MAX_NWUF_CNT_5709; idx++)
{
nwuf = &nwuf_list->nwuf_arr[idx];
nwuf_size[idx] = nwuf->size;
}
for(idx = 0; idx < 1000; idx++)
{
mm_wait(pdev, 5);
REG_RD(pdev, rpm.rpm_acpi_byte_enable_ctrl, &val);
if((val & RPM_ACPI_BYTE_ENABLE_CTRL_INIT) == 0)
{
break;
}
}
DbgBreakIf(val & RPM_ACPI_BYTE_ENABLE_CTRL_INIT);
val = 0;
for(idx = 0; idx < 4; idx++)
{
nwuf = &nwuf_list->nwuf_arr[idx];
pattern_size = nwuf->size >>16;
nwuf->size &= 0xffff;
DbgBreakIf(nwuf->size > LM_NWUF_PATTERN_MASK_SIZE);
if(nwuf->size == 0)
{
continue;
}
if (pattern_size)
{
val |= (pattern_size) << ((3 - idx) * 8);
}
else
{
val |= (nwuf->size * 8) << ((3 - idx) * 8);
}
}
REG_WR(pdev, rpm.rpm_acpi_pattern_len0, val);
val = 0;
for(idx = 4; idx < LM_MAX_NWUF_CNT_5709; idx++)
{
nwuf = &nwuf_list->nwuf_arr[idx];
pattern_size = nwuf->size >>16;
nwuf->size &= 0xffff;
DbgBreakIf(nwuf->size > LM_NWUF_PATTERN_MASK_SIZE);
if(nwuf->size == 0)
{
continue;
}
if (pattern_size)
{
val |= (pattern_size) << ((7 - idx) * 8);
}
else
{
val |= (nwuf->size * 8) << ((7 - idx) * 8);
}
}
REG_WR(pdev, rpm.rpm_acpi_pattern_len1, val);
for(offset = 0; offset < LM_NWUF_PATTERN_SIZE; offset++)
{
val = 0;
for(idx = 0; idx < LM_MAX_NWUF_CNT_5709; idx++)
{
nwuf = &nwuf_list->nwuf_arr[idx];
pattern_size = nwuf_size[idx]>>16;
if(nwuf->size == 0 || offset > nwuf->size * 8)
{
continue;
}
mask = nwuf->mask[offset/8];
bit = offset % 8;
if(mask & (1 << bit))
{
val |= 1 << idx;
}
}
REG_WR(pdev, rpm.rpm_acpi_data, val);
REG_WR(
pdev,
rpm.rpm_acpi_byte_enable_ctrl,
RPM_ACPI_BYTE_ENABLE_CTRL_WR | offset);
REG_RD(pdev, rpm.rpm_acpi_byte_enable_ctrl, &val);
DbgBreakIf(val & RPM_ACPI_BYTE_ENABLE_CTRL_WR);
}
nwuf_cnt = 0;
for(idx = 0; idx < LM_MAX_NWUF_CNT_5709; idx++)
{
REG_WR(
pdev,
rpm.rpm_acpi_pattern_ctrl,
RPM_ACPI_PATTERN_CTRL_CRC_SM_CLR|idx);
REG_RD(pdev, rpm.rpm_acpi_pattern_ctrl, &val);
DbgBreakIf(val & RPM_ACPI_PATTERN_CTRL_CRC_SM_CLR);
nwuf = &nwuf_list->nwuf_arr[idx];
if(nwuf->size == 0)
{
continue;
}
pattern_size = nwuf_size[idx]>>16;
if (pattern_size)
{
nwuf_len = pattern_size;
}
else
{
nwuf_len = (nwuf->size * 8);
}
nwuf_len += 2;
nwuf_len = (nwuf_len + 3) & ~3;
prev_val = 0;
for(offset = 0; offset < nwuf_len; offset += 4)
{
val = 0;
for(bit = 0; bit < 4; bit++)
{
if (pattern_size)
{
if(offset < pattern_size)
{
mask = nwuf->mask[offset/8];
}
else
{
mask = 0;
}
}
else
{
if(offset < nwuf->size * 8)
{
mask = nwuf->mask[offset/8];
}
else
{
mask = 0;
}
}
if(mask & (1 << (bit + (offset % 8))))
{
val |= nwuf->pattern[offset+bit] << ((3 - bit) * 8);
}
}
REG_WR(pdev, rpm.rpm_acpi_data, (prev_val << 16) | (val >> 16));
prev_val = (u16_t) val;
REG_WR(
pdev,
rpm.rpm_acpi_pattern_ctrl,
RPM_ACPI_PATTERN_CTRL_WR | idx);
REG_RD(pdev, rpm.rpm_acpi_pattern_ctrl, &val);
DbgBreakIf(val & RPM_ACPI_PATTERN_CTRL_WR);
}
nwuf_cnt++;
}
for(idx = 0; idx < LM_MAX_NWUF_CNT_5709; idx++)
{
nwuf = &nwuf_list->nwuf_arr[idx];
nwuf->size = nwuf_size[idx];
}
return nwuf_cnt;
}
STATIC u32_t
init_nwuf_5706(
lm_device_t *pdev,
lm_nwuf_list_t *nwuf_list)
{
typedef union _acpi_wol_pat_t
{
#if defined(LITTLE_ENDIAN)
struct _acpi_wol_pat_as_u8_t
{
u8_t pat[7];
u8_t ena;
} as_u8;
struct _acpi_wol_pat_as_u32_t
{
u32_t low;
u32_t high;
} as_u32;
#elif defined(BIG_ENDIAN)
struct _acpi_wol_pat_as_u8_t
{
u8_t ena;
u8_t pat[7];
} as_u8;
struct _acpi_wol_pat_as_u32_t
{
u32_t high;
u32_t low;
} as_u32;
#endif
} acpi_wol_pat_t;
u32_t filler_pattern_idx;
acpi_wol_pat_t wol_pat;
u32_t pattern_cnt;
u8_t val;
u32_t j;
u32_t k;
u8_t idx;
u32_t nwuf_size[LM_MAX_NWUF_CNT];
lm_nwuf_t *nwuf;
for(idx = 0; idx < LM_MAX_NWUF_CNT; idx++)
{
nwuf = &nwuf_list->nwuf_arr[idx];
nwuf_size[idx] = nwuf->size;
nwuf->size &= 0xffff;
}
DbgBreakIf(LM_NWUF_PATTERN_SIZE > 128);
DbgBreakIf(LM_MAX_NWUF_CNT > 7);
DbgBreakIf(CHIP_NUM(pdev) != CHIP_NUM_5706 &&
CHIP_NUM(pdev) != CHIP_NUM_5708);
filler_pattern_idx = 0;
pattern_cnt = 0;
for(k = 0; k < LM_MAX_NWUF_CNT; k++)
{
if(nwuf_list->nwuf_arr[k].size)
{
pattern_cnt++;
filler_pattern_idx = k;
}
}
for(j = 0; j < LM_NWUF_PATTERN_SIZE; j++)
{
wol_pat.as_u32.low = 0x0;
wol_pat.as_u32.high = 0x0;
wol_pat.as_u8.ena = 0;
for(k = 0; k < LM_MAX_NWUF_CNT; k++)
{
if(nwuf_list->nwuf_arr[k].size == 0)
{
val = nwuf_list->nwuf_arr[filler_pattern_idx].mask[j/8];
}
else if((j/8) >= nwuf_list->nwuf_arr[k].size)
{
val = 0;
}
else
{
val = nwuf_list->nwuf_arr[k].mask[j/8];
}
if(val & (1 << (j % 8)))
{
wol_pat.as_u8.ena |= 1 << k;
}
}
DbgMessage1(pdev, VERBOSE, "%02x: ", j);
for(k = 0; k < LM_MAX_NWUF_CNT; k++)
{
if(nwuf_list->nwuf_arr[k].size == 0)
{
val = nwuf_list->nwuf_arr[filler_pattern_idx].pattern[j];
DbgMessage(pdev, VERBOSE, "xx ");
}
else if((j/8) >= nwuf_list->nwuf_arr[k].size)
{
val = 0xff;
DbgMessage(pdev, VERBOSE, "ff ");
}
else
{
val = nwuf_list->nwuf_arr[k].pattern[j];
DbgMessage1(pdev, VERBOSE, "%02x ", val);
}
#if defined(LITTLE_ENDIAN)
wol_pat.as_u8.pat[6-k] = val;
#elif defined(BIG_ENDIAN)
wol_pat.as_u8.pat[k] = val;
#endif
}
DbgMessage2(pdev, VERBOSE, " %08x %08x\n",
wol_pat.as_u32.high, wol_pat.as_u32.low);
if(j % 2)
{
REG_WR_IND(
pdev,
OFFSETOF(reg_space_t, tas.tas_thbuf[(j-1) * 2]),
wol_pat.as_u32.high);
REG_WR_IND(
pdev,
OFFSETOF(reg_space_t, tas.tas_thbuf[(j-1) * 2 + 1]),
wol_pat.as_u32.low);
}
else
{
REG_WR_IND(
pdev,
OFFSETOF(reg_space_t, tas.tas_thbuf[(j+1) * 2]),
wol_pat.as_u32.high);
REG_WR_IND(
pdev,
OFFSETOF(reg_space_t, tas.tas_thbuf[(j+1) * 2 + 1]),
wol_pat.as_u32.low);
}
}
for(idx = 0; idx < LM_MAX_NWUF_CNT; idx++)
{
nwuf = &nwuf_list->nwuf_arr[idx];
nwuf->size = nwuf_size[idx];
}
return pattern_cnt;
}
STATIC u32_t
init_nwuf(
lm_device_t *pdev,
lm_nwuf_list_t *nwuf_list)
{
u32_t nwuf_cnt;
if(CHIP_NUM(pdev) == CHIP_NUM_5706 || CHIP_NUM(pdev) == CHIP_NUM_5708)
{
nwuf_cnt = init_nwuf_5706(pdev, nwuf_list);
}
else
{
nwuf_cnt = init_nwuf_5709(pdev, nwuf_list);
}
return nwuf_cnt;
}
STATIC void
set_d0_power_state(
lm_device_t *pdev,
u8_t set_pci_pm)
{
u32_t val;
u32_t idx;
if(set_pci_pm)
{
(void) 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;
(void) mm_write_pci(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_pm_csr),
val);
}
if(CHIP_ID(pdev) == CHIP_ID_5706_A1)
{
for(idx = 0; idx < 1000; idx++)
{
mm_wait(pdev, 15);
}
}
REG_RD(pdev, emac.emac_mode, &val);
val |= EMAC_MODE_MPKT_RCVD | EMAC_MODE_ACPI_RCVD;
val &= ~EMAC_MODE_MPKT;
REG_WR(pdev, emac.emac_mode, val);
REG_RD(pdev, rpm.rpm_config, &val);
val &= ~RPM_CONFIG_ACPI_ENA;
REG_WR(pdev, rpm.rpm_config, val);
}
STATIC void
set_d3_power_state(
lm_device_t *pdev,
lm_wake_up_mode_t wake_up_mode,
u8_t set_pci_pm)
{
u32_t fw_timed_out;
u32_t reset_reason;
u32_t gpio_pin;
u32_t val;
u32_t cnt;
if(wake_up_mode & (LM_WAKE_UP_MODE_MAGIC_PACKET | LM_WAKE_UP_MODE_NWUF))
{
REG_RD(pdev, emac.emac_mode, &val);
if(wake_up_mode & LM_WAKE_UP_MODE_MAGIC_PACKET)
{
val |= EMAC_MODE_MPKT;
}
else
{
val &= ~EMAC_MODE_MPKT;
}
val &= ~EMAC_MODE_PORT;
if(CHIP_REV(pdev) == CHIP_REV_FPGA || CHIP_REV(pdev) == CHIP_REV_IKOS)
{
val |= EMAC_MODE_PORT_GMII;
}
else
{
val |= EMAC_MODE_PORT_MII;
}
val |= EMAC_MODE_MPKT_RCVD | EMAC_MODE_ACPI_RCVD;
REG_WR(pdev, emac.emac_mode, val);
(void) lm_set_rx_mask(
pdev,
RX_FILTER_USER_IDX0,
LM_RX_MASK_ACCEPT_UNICAST |
LM_RX_MASK_ACCEPT_ALL_MULTICAST |
LM_RX_MASK_ACCEPT_BROADCAST);
for(cnt = 0; cnt < 4; cnt++)
{
(void) lm_set_mac_addr(pdev, cnt, pdev->params.mac_addr);
}
REG_WR(
pdev,
misc.misc_enable_set_bits,
MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
MISC_ENABLE_SET_BITS_EMAC_ENABLE);
REG_RD(pdev, rpm.rpm_config, &val);
if(wake_up_mode & LM_WAKE_UP_MODE_NWUF)
{
REG_WR(pdev, rpm.rpm_config, val & ~RPM_CONFIG_ACPI_ENA);
if(init_nwuf(pdev, &pdev->nwuf_list))
{
val |= RPM_CONFIG_ACPI_ENA;
}
else
{
val &= ~RPM_CONFIG_ACPI_ENA;
}
}
else
{
val &= ~RPM_CONFIG_ACPI_ENA;
}
REG_WR(pdev, rpm.rpm_config, val);
REG_WR(
pdev,
misc.misc_enable_set_bits,
MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
reset_reason = LM_REASON_WOL_SUSPEND;
}
else
{
reset_reason = LM_REASON_NO_WOL_SUSPEND;
}
fw_timed_out = fw_reset_sync(
pdev,
reset_reason,
DRV_MSG_DATA_WAIT3,
FW_ACK_TIME_OUT_MS*1000 * 3);
if(fw_timed_out)
{
if(pdev->params.enable_remote_phy == FALSE)
{
if(CHIP_REV(pdev) != CHIP_REV_FPGA &&
CHIP_REV(pdev) != CHIP_REV_IKOS)
{
(void) lm_mwrite(
pdev,
pdev->params.phy_addr,
0x1c,
0xa821);
}
}
REG_RD(pdev, misc.misc_clock_control_bits, &val);
val &= ~(MISC_CLOCK_CONTROL_BITS_CORE_CLK_DISABLE |
MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT |
MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_TE);
REG_WR(
pdev,
misc.misc_clock_control_bits,
MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_12_TE | val);
REG_WR(
pdev,
misc.misc_clock_control_bits,
MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_12_TE |
MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT |
val);
REG_WR(
pdev,
misc.misc_clock_control_bits,
MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT_SRC_12_TE |
MISC_CLOCK_CONTROL_BITS_CORE_CLK_ALT |
MISC_CLOCK_CONTROL_BITS_CORE_CLK_DISABLE |
val);
gpio_pin = 1 << 2;
REG_RD(pdev, misc.misc_spio, &val);
val &= ~(gpio_pin << 24);
val |= gpio_pin << 16;
REG_WR(pdev, misc.misc_spio, val);
if(set_pci_pm)
{
REG_RD_OFFSET(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_pm_csr),
&val);
val &= ~PCICFG_PM_CSR_STATE;
val |= PCICFG_PM_CSR_STATE_D3_HOT;
REG_WR_OFFSET(
pdev,
OFFSETOF(reg_space_t, pci_config.pcicfg_pm_csr),
val);
}
}
}
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)
{
if(power_state == LM_POWER_STATE_D0)
{
set_d0_power_state(pdev, set_pci_pm);
}
else
{
set_d3_power_state(pdev, wake_up_mode, set_pci_pm);
}
}
#ifndef EXCLUDE_KQE_SUPPORT
u32_t
lm_submit_kernel_wqes(
lm_device_t *pdev,
kwqe_t *wqes[],
u32_t num_wqes)
{
kwqe_t *prod_qe;
u16_t prod_idx;
u32_t qe_cnt;
if(num_wqes > pdev->kq_info.kwqe_left)
{
pdev->kq_info.no_kwq_bd_left++;
return 0;
}
pdev->kq_info.kwqe_left -= num_wqes;
prod_qe = pdev->kq_info.kwq_prod_qe;
prod_idx = pdev->kq_info.kwq_prod_idx;
qe_cnt = num_wqes;
while(qe_cnt)
{
*prod_qe = *(*wqes);
if(prod_qe == pdev->kq_info.kwq_last_qe)
{
prod_qe = pdev->kq_info.kwq_virt;
}
else
{
prod_qe++;
}
wqes++;
prod_idx++;
qe_cnt--;
}
pdev->kq_info.kwq_prod_qe = prod_qe;
pdev->kq_info.kwq_prod_idx = prod_idx;
MBQ_WR16(
pdev,
GET_CID(pdev->kq_info.kwq_cid_addr),
OFFSETOF(krnlq_context_t, krnlq_host_qidx),
prod_idx);
return num_wqes;
}
#endif
lm_interrupt_status_t
lm_get_interrupt_status(
lm_device_t *pdev)
{
lm_interrupt_status_t intr_status;
u32_t deasserted_attns;
u32_t asserted_attns;
lm_rx_chain_t *rxq;
lm_tx_chain_t *txq;
u16_t hw_con_idx;
u32_t val;
u32_t idx;
intr_status = LM_NO_EVENT_ACTIVE;
if(pdev->params.link_chng_mode == LINK_CHNG_MODE_USE_STATUS_REG)
{
REG_RD(pdev, emac.emac_status, &val);
if(pdev->params.phy_int_mode == PHY_INT_MODE_MI_INTERRUPT)
{
if(val & EMAC_STATUS_MI_INT)
{
intr_status |= LM_PHY_EVENT_ACTIVE;
}
}
else if(val & EMAC_STATUS_LINK_CHANGE)
{
intr_status |= LM_PHY_EVENT_ACTIVE;
}
GET_ATTN_CHNG_BITS(pdev, &asserted_attns, &deasserted_attns);
}
else
{
GET_ATTN_CHNG_BITS(pdev, &asserted_attns, &deasserted_attns);
if(asserted_attns & STATUS_ATTN_BITS_LINK_STATE)
{
intr_status |= LM_PHY_EVENT_ACTIVE;
}
else if(deasserted_attns & STATUS_ATTN_BITS_LINK_STATE)
{
intr_status |= LM_PHY_EVENT_ACTIVE;
}
}
if((asserted_attns & STATUS_ATTN_BITS_TIMER_ABORT) ||
(deasserted_attns & STATUS_ATTN_BITS_TIMER_ABORT))
{
if(pdev->params.enable_remote_phy)
{
REG_RD_IND(
pdev,
pdev->hw_info.shmem_base +
OFFSETOF(shmem_region_t, fw_evt_mb.fw_evt_code_mb),
&val);
if(val == 0)
{
intr_status |= LM_KNOCK_KNOCK_EVENT;
}
else if(val == FW_EVT_CODE_LINK_STATUS_CHANGE_EVENT)
{
intr_status |= LM_PHY_EVENT_ACTIVE;
}
else
{
DbgBreakMsg("not a valid fw event.\n");
}
}
else
{
intr_status |= LM_KNOCK_KNOCK_EVENT;
}
if(asserted_attns & STATUS_ATTN_BITS_TIMER_ABORT)
{
REG_WR(
pdev,
pci_config.pcicfg_status_bit_set_cmd,
asserted_attns & STATUS_ATTN_BITS_TIMER_ABORT);
}
else
{
REG_WR(
pdev,
pci_config.pcicfg_status_bit_clear_cmd,
deasserted_attns & STATUS_ATTN_BITS_TIMER_ABORT);
}
}
for(idx = 0; idx < pdev->tx_info.num_txq; idx++)
{
txq = &pdev->tx_info.chain[idx];
hw_con_idx = *txq->hw_con_idx_ptr;
if((hw_con_idx & MAX_BD_PER_PAGE) == MAX_BD_PER_PAGE)
{
hw_con_idx++;
}
if(hw_con_idx != txq->con_idx)
{
intr_status |= LM_TX0_EVENT_ACTIVE << txq->idx;
}
}
for(idx = 0; idx < pdev->rx_info.num_rxq; idx++)
{
rxq = &pdev->rx_info.chain[idx];
hw_con_idx = *rxq->hw_con_idx_ptr;
if((hw_con_idx & MAX_BD_PER_PAGE) == MAX_BD_PER_PAGE)
{
hw_con_idx++;
}
if(hw_con_idx != rxq->con_idx)
{
intr_status |= LM_RX0_EVENT_ACTIVE << rxq->idx;
}
}
#ifndef EXCLUDE_KQE_SUPPORT
if(CHIP_NUM(pdev) == CHIP_NUM_5706 || CHIP_NUM(pdev) == CHIP_NUM_5708)
{
if(pdev->kq_info.kwq_con_idx !=
pdev->vars.status_virt->deflt.status_rx_quick_consumer_index15)
{
intr_status |= LM_KWQ_EVENT_ACTIVE;
}
}
else
{
if(pdev->kq_info.kwq_con_idx !=
pdev->vars.status_virt->deflt.status_cmd_consumer_index)
{
intr_status |= LM_KWQ_EVENT_ACTIVE;
}
}
if(pdev->kq_info.kcq_con_idx !=
pdev->vars.status_virt->deflt.status_completion_producer_index)
{
intr_status |= LM_KCQ_EVENT_ACTIVE;
}
#endif
#if INCLUDE_OFLD_SUPPORT
else if(pdev->params.hcopy_desc_cnt)
{
if(pdev->ofld.hcopy_chain.con_idx !=
*(pdev->ofld.hcopy_chain.hw_con_idx_ptr))
{
intr_status |= LM_KCQ_EVENT_ACTIVE;
}
}
#endif
return intr_status;
}
#ifndef EXCLUDE_KQE_SUPPORT
void
lm_ack_completed_wqes(
lm_device_t *pdev)
{
u16_t new_con_idx;
kwqe_t *con_qe;
u16_t num_wqes;
u16_t con_idx;
if(CHIP_NUM(pdev) == CHIP_NUM_5706 || CHIP_NUM(pdev) == CHIP_NUM_5708)
{
new_con_idx =
pdev->vars.status_virt->deflt.status_rx_quick_consumer_index15;
}
else
{
new_con_idx = pdev->vars.status_virt->deflt.status_cmd_consumer_index;
}
num_wqes = (u16_t) S16_SUB(new_con_idx, pdev->kq_info.kwq_con_idx);
pdev->kq_info.kwqe_left += num_wqes;
con_idx = new_con_idx;
con_qe = pdev->kq_info.kwq_con_qe + num_wqes;
if((u8_t *) con_qe > (u8_t *) pdev->kq_info.kwq_last_qe)
{
con_qe = (kwqe_t *) ((u8_t *) pdev->kq_info.kwq_virt +
((u8_t *) con_qe - (u8_t *) pdev->kq_info.kwq_last_qe));
con_qe--;
}
pdev->kq_info.kwq_con_idx = con_idx;
pdev->kq_info.kwq_con_qe = con_qe;
DbgBreakIf(((((u8_t *) con_qe - (u8_t *) pdev->kq_info.kwq_virt) /
sizeof(kwqe_t)) & 0x7f) != (con_idx & 0x7f));
#if DBG
if(S16_SUB(pdev->kq_info.kwq_prod_idx, con_idx) >= 0)
{
num_wqes = pdev->kq_info.kwqe_left +
(u32_t) S16_SUB(pdev->kq_info.kwq_prod_idx, con_idx);
}
else
{
num_wqes = pdev->kq_info.kwqe_left + 0x10000 - con_idx +
pdev->kq_info.kwq_prod_idx;
}
DbgBreakIf(num_wqes != (LM_PAGE_SIZE/sizeof(kwqe_t)) *
pdev->params.kwq_page_cnt - 1);
#endif
}
u32_t
lm_get_kernel_cqes(
lm_device_t *pdev,
kcqe_t *cqe_ptr[],
u32_t ptr_cnt)
{
kcqe_t *con_qe;
u16_t prod_idx;
u32_t num_cqes;
u16_t con_idx;
DbgMessage(pdev, VERBOSEint, "### lm_get_kernel_cqes\n");
con_idx = pdev->kq_info.kcq_con_idx;
con_qe = pdev->kq_info.kcq_con_qe;
DbgBreakIf(((((u8_t *) con_qe - (u8_t *) pdev->kq_info.kcq_virt) /
sizeof(kcqe_t)) & 0x7f) != (con_idx & 0x7f));
num_cqes = 0;
prod_idx = pdev->vars.status_virt->deflt.status_completion_producer_index;
while(con_idx != prod_idx && num_cqes != ptr_cnt)
{
*cqe_ptr = con_qe;
cqe_ptr++;
num_cqes++;
con_idx++;
if(con_qe == pdev->kq_info.kcq_last_qe)
{
con_qe = pdev->kq_info.kcq_virt;
}
else
{
con_qe++;
}
prod_idx =
pdev->vars.status_virt->deflt.status_completion_producer_index;
}
cqe_ptr--;
while(num_cqes && ((*cqe_ptr)->kcqe_flags & KCQE_FLAGS_NEXT))
{
num_cqes--;
cqe_ptr--;
}
DbgBreakIf(num_cqes == 0);
return num_cqes;
}
u8_t
lm_ack_kernel_cqes(
lm_device_t *pdev,
u32_t num_cqes)
{
kcqe_t *con_qe;
u16_t prod_idx;
u16_t con_idx;
DbgMessage(pdev, VERBOSEint, "### lm_ack_kernel_cqes\n");
con_idx = pdev->kq_info.kcq_con_idx;
if(num_cqes)
{
con_idx += (u16_t) num_cqes;
con_qe = pdev->kq_info.kcq_con_qe + num_cqes;
if((u8_t *) con_qe > (u8_t *) pdev->kq_info.kcq_last_qe)
{
con_qe = (kcqe_t *) ((u8_t *) pdev->kq_info.kcq_virt +
((u8_t *) con_qe - (u8_t *) pdev->kq_info.kcq_last_qe));
con_qe--;
}
pdev->kq_info.kcq_con_idx = con_idx;
pdev->kq_info.kcq_con_qe = con_qe;
if(pdev->params.kcq_history_size)
{
DbgBreakIf(S16_SUB(con_idx, pdev->kq_info.history_kcq_con_idx) < 0);
num_cqes = (u32_t) S16_SUB(
con_idx,
pdev->kq_info.history_kcq_con_idx);
if(num_cqes >= pdev->params.kcq_history_size)
{
num_cqes -= pdev->params.kcq_history_size;
DbgBreakIf(num_cqes > pdev->params.kcq_history_size);
pdev->kq_info.history_kcq_con_idx += (u16_t) num_cqes;
con_qe = pdev->kq_info.history_kcq_con_qe + num_cqes;
if((u8_t *) con_qe > (u8_t *) pdev->kq_info.kcq_last_qe)
{
con_qe = (kcqe_t *) ((u8_t *) pdev->kq_info.kcq_virt +
((u8_t *) con_qe -
(u8_t *) pdev->kq_info.kcq_last_qe));
con_qe--;
}
pdev->kq_info.history_kcq_con_qe = con_qe;
MBQ_WR16(
pdev,
GET_CID(pdev->kq_info.kcq_cid_addr),
OFFSETOF(krnlq_context_t, krnlq_host_qidx),
pdev->kq_info.history_kcq_con_idx);
}
}
else
{
MBQ_WR16(
pdev,
GET_CID(pdev->kq_info.kcq_cid_addr),
OFFSETOF(krnlq_context_t, krnlq_host_qidx),
con_idx);
}
}
prod_idx = pdev->vars.status_virt->deflt.status_completion_producer_index;
DbgBreakIf(S16_SUB(prod_idx, con_idx) < 0);
return con_idx != prod_idx;
}
#endif
#ifndef EXCLUDE_RSS_SUPPORT
#if RSS_LOOKUP_TABLE_WA
u64_t
rss_f64(
u8_t* key,
u8_t s,
u8_t e
)
{
u64_t f;
for( f=0; s<=e; ++s )
{
f = (f << 8);
f |= key[s];
}
return f;
}
u32_t
rss_hash_byte(
u8_t* key,
u8_t byte,
u8_t s,
u8_t e,
u32_t rst
)
{
u8_t i;
u64_t key_msb;
key_msb = rss_f64(key, s,e);
for( i=0x80; i!=0; i>>=1 )
{
if( i & byte )
{
u32_t k;
k = (u32_t)(key_msb >> 32);
rst ^= k;
}
key_msb = (key_msb << 1);
}
return rst;
}
void
rss_gen_one_table(
u8_t* key,
u8_t s,
u8_t e,
u32_t* gtbl
)
{
u32_t i;
for( i = 0; i < 256; ++i )
{
gtbl[i] = rss_hash_byte( key, (u8_t)i, s, e, 0 );
}
}
void
rss_gen_tables(
u8_t* key,
u32_t* tables
)
{
u8_t t;
for( t = 0; t < 12; ++t )
{
rss_gen_one_table( key, t, (u8_t)(t+7), tables );
tables += 256;
}
}
#endif
#ifndef LM_NON_LEGACY_MODE_SUPPORT
lm_status_t
lm_enable_rss(
lm_device_t *pdev,
lm_rss_hash_t hash_type,
u8_t *indirection_table,
u32_t table_size,
u8_t *hash_key,
u32_t key_size)
{
l2_kwqe_rss_table_update_t *rss_update;
u8_t rss_key[RSS_HASH_KEY_SIZE];
lm_address_t rss_table_phy;
u8_t *rss_table_virt;
kwqe_t *prod_qe;
u16_t prod_idx;
u32_t idx;
u32_t val;
if(pdev->kq_info.kwqe_left < 2)
{
pdev->kq_info.no_kwq_bd_left++;
return LM_STATUS_RESOURCE;
}
pdev->kq_info.kwqe_left -= 2;
DbgBreakIf(key_size > RSS_HASH_KEY_SIZE);
if(key_size > RSS_HASH_KEY_SIZE)
{
key_size = RSS_HASH_KEY_SIZE;
}
for(idx = 0; idx < key_size; idx++)
{
rss_key[idx] = hash_key[idx];
}
for(idx = key_size; idx < RSS_HASH_KEY_SIZE; idx++)
{
rss_key[idx] = 0;
}
DbgBreakIf(table_size > RSS_INDIRECTION_TABLE_SIZE);
if(table_size > RSS_INDIRECTION_TABLE_SIZE)
{
table_size = RSS_INDIRECTION_TABLE_SIZE;
}
if(CHIP_NUM(pdev) == CHIP_NUM_5709)
{
REG_RD(pdev, rlup.rlup_rss_config, &val);
val &= ~RLUP_RSS_CONFIG_IPV4_RSS_TYPE_OFF_XI;
val &= ~RLUP_RSS_CONFIG_IPV6_RSS_TYPE_OFF_XI;
REG_WR(pdev, rlup.rlup_rss_config, val);
val = (rss_key[0] << 24) |
(rss_key[1] << 16) |
(rss_key[2] << 8) |
rss_key[3];
REG_WR(pdev, rlup.rlup_rss_key1, val);
val = (rss_key[4] << 24) |
(rss_key[5] << 16) |
(rss_key[6] << 8) |
rss_key[7];
REG_WR(pdev, rlup.rlup_rss_key2, val);
val = (rss_key[8] << 24) |
(rss_key[9] << 16) |
(rss_key[10] << 8) |
rss_key[11];
REG_WR(pdev, rlup.rlup_rss_key3, val);
val = (rss_key[12] << 24) |
(rss_key[13] << 16) |
(rss_key[14] << 8) |
rss_key[15];
REG_WR(pdev, rlup.rlup_rss_key4, val);
val = (rss_key[16] << 24) |
(rss_key[17] << 16) |
(rss_key[18] << 8) |
rss_key[19];
REG_WR(pdev, rlup.rlup_ipv6_rss_key5, val);
val = (rss_key[20] << 24) |
(rss_key[21] << 16) |
(rss_key[22] << 8) |
rss_key[23];
REG_WR(pdev, rlup.rlup_ipv6_rss_key6, val);
val = (rss_key[24] << 24) |
(rss_key[25] << 16) |
(rss_key[26] << 8) |
rss_key[27];
REG_WR(pdev, rlup.rlup_ipv6_rss_key7, val);
val = (rss_key[28] << 24) |
(rss_key[29] << 16) |
(rss_key[30] << 8) |
rss_key[31];
REG_WR(pdev, rlup.rlup_ipv6_rss_key8, val);
val = (rss_key[32] << 24) |
(rss_key[33] << 16) |
(rss_key[34] << 8) |
rss_key[35];
REG_WR(pdev, rlup.rlup_ipv6_rss_key9, val);
val = (rss_key[36] << 24) |
(rss_key[37] << 16) |
(rss_key[38] << 8) |
rss_key[39];
REG_WR(pdev, rlup.rlup_ipv6_rss_key10, val);
}
rss_table_virt = pdev->rx_info.rss_ind_table_virt;
rss_table_phy = pdev->rx_info.rss_ind_table_phy;
for(idx = 0; idx < table_size; idx++)
{
rss_table_virt[idx] = indirection_table[idx];
}
prod_qe = pdev->kq_info.kwq_prod_qe;
prod_idx = pdev->kq_info.kwq_prod_idx;
rss_update = (l2_kwqe_rss_table_update_t *) prod_qe;
rss_update->rss_flags = L2_KWQE_FLAGS_LAYER_MASK_L2;
rss_update->rss_opcode = L2_KWQE_OPCODE_VALUE_UPDATE_RSS;
rss_update->rss_table_size = (u16_t) table_size;
rss_update->rss_table_haddr_lo = rss_table_phy.as_u32.low;
rss_update->rss_table_haddr_hi = rss_table_phy.as_u32.high;
rss_update->rss_host_opaque = 0;
rss_update->rss_hash_type = hash_type;
#if RSS_LOOKUP_TABLE_WA
rss_table_virt += RSS_INDIRECTION_TABLE_SIZE;
LM_INC64(&rss_table_phy, RSS_INDIRECTION_TABLE_SIZE);
rss_update->rss_lookup_table_lo = rss_table_phy.as_u32.low;
rss_update->rss_lookup_table_hi = rss_table_phy.as_u32.high;
rss_gen_tables(rss_key, (u32_t *) rss_table_virt);
#endif
if(prod_qe == pdev->kq_info.kwq_last_qe)
{
prod_qe = pdev->kq_info.kwq_virt;
}
else
{
prod_qe++;
}
prod_idx++;
rss_update = (l2_kwqe_rss_table_update_t *) prod_qe;
rss_update->rss_flags = L2_KWQE_FLAGS_LAYER_MASK_L2;
rss_update->rss_opcode = L2_KWQE_OPCODE_VALUE_ENABLE_RSS;
rss_update->rss_host_opaque = 0;
rss_update->rss_hash_type = hash_type;
if(prod_qe == pdev->kq_info.kwq_last_qe)
{
prod_qe = pdev->kq_info.kwq_virt;
}
else
{
prod_qe++;
}
prod_idx++;
pdev->kq_info.kwq_prod_qe = prod_qe;
pdev->kq_info.kwq_prod_idx = prod_idx;
MBQ_WR16(
pdev,
GET_CID(pdev->kq_info.kwq_cid_addr),
OFFSETOF(krnlq_context_t, krnlq_host_qidx),
prod_idx);
return LM_STATUS_SUCCESS;
}
#else
lm_status_t
lm_enable_rss(
lm_device_t *pdev,
lm_rss_hash_t hash_type,
PROCESSOR_NUMBER *indirection_table,
u32_t table_size,
u8_t *hash_key,
u32_t key_size,
u8_t *cpu_tbl,
u8_t *rss_qidx_tbl)
{
l2_kwqe_rss_table_update_t *rss_update;
u8_t rss_key[RSS_HASH_KEY_SIZE];
lm_address_t rss_table_phy;
u8_t *rss_table_virt;
kwqe_t *prod_qe;
u16_t prod_idx;
u32_t idx;
u32_t val;
if(pdev->kq_info.kwqe_left < 2)
{
pdev->kq_info.no_kwq_bd_left++;
return LM_STATUS_RESOURCE;
}
pdev->kq_info.kwqe_left -= 2;
DbgBreakIf(key_size > RSS_HASH_KEY_SIZE);
if(key_size > RSS_HASH_KEY_SIZE)
{
key_size = RSS_HASH_KEY_SIZE;
}
for(idx = 0; idx < key_size; idx++)
{
rss_key[idx] = hash_key[idx];
}
for(idx = key_size; idx < RSS_HASH_KEY_SIZE; idx++)
{
rss_key[idx] = 0;
}
DbgBreakIf(table_size > RSS_INDIRECTION_TABLE_SIZE);
if(table_size > RSS_INDIRECTION_TABLE_SIZE)
{
table_size = RSS_INDIRECTION_TABLE_SIZE;
}
if(CHIP_NUM(pdev) == CHIP_NUM_5709)
{
REG_RD(pdev, rlup.rlup_rss_config, &val);
val &= ~RLUP_RSS_CONFIG_IPV4_RSS_TYPE_OFF_XI;
val &= ~RLUP_RSS_CONFIG_IPV6_RSS_TYPE_OFF_XI;
REG_WR(pdev, rlup.rlup_rss_config, val);
val = (rss_key[0] << 24) |
(rss_key[1] << 16) |
(rss_key[2] << 8) |
rss_key[3];
REG_WR(pdev, rlup.rlup_rss_key1, val);
val = (rss_key[4] << 24) |
(rss_key[5] << 16) |
(rss_key[6] << 8) |
rss_key[7];
REG_WR(pdev, rlup.rlup_rss_key2, val);
val = (rss_key[8] << 24) |
(rss_key[9] << 16) |
(rss_key[10] << 8) |
rss_key[11];
REG_WR(pdev, rlup.rlup_rss_key3, val);
val = (rss_key[12] << 24) |
(rss_key[13] << 16) |
(rss_key[14] << 8) |
rss_key[15];
REG_WR(pdev, rlup.rlup_rss_key4, val);
val = (rss_key[16] << 24) |
(rss_key[17] << 16) |
(rss_key[18] << 8) |
rss_key[19];
REG_WR(pdev, rlup.rlup_ipv6_rss_key5, val);
val = (rss_key[20] << 24) |
(rss_key[21] << 16) |
(rss_key[22] << 8) |
rss_key[23];
REG_WR(pdev, rlup.rlup_ipv6_rss_key6, val);
val = (rss_key[24] << 24) |
(rss_key[25] << 16) |
(rss_key[26] << 8) |
rss_key[27];
REG_WR(pdev, rlup.rlup_ipv6_rss_key7, val);
val = (rss_key[28] << 24) |
(rss_key[29] << 16) |
(rss_key[30] << 8) |
rss_key[31];
REG_WR(pdev, rlup.rlup_ipv6_rss_key8, val);
val = (rss_key[32] << 24) |
(rss_key[33] << 16) |
(rss_key[34] << 8) |
rss_key[35];
REG_WR(pdev, rlup.rlup_ipv6_rss_key9, val);
val = (rss_key[36] << 24) |
(rss_key[37] << 16) |
(rss_key[38] << 8) |
rss_key[39];
REG_WR(pdev, rlup.rlup_ipv6_rss_key10, val);
}
rss_table_virt = pdev->rx_info.rss_ind_table_virt;
rss_table_phy = pdev->rx_info.rss_ind_table_phy;
pdev->rx_info.rss_tbl_size = table_size;
if(!cpu_tbl)
{
for(idx = 0; idx < table_size; idx++)
rss_table_virt[idx] = indirection_table[idx].Number;
}
else
{
u8_t *rss_cpu_tbl = &cpu_tbl[1];
for(idx = 0; idx < table_size; idx++)
{
for(val = 0; val < cpu_tbl[0]; val++)
{
if(indirection_table[idx].Number == rss_cpu_tbl[val])
{
if(pdev->vars.interrupt_mode == IRQ_MODE_MSIX_BASED ||
pdev->vars.interrupt_mode == IRQ_MODE_MSI_BASED)
{
rss_table_virt[idx] = rss_qidx_tbl[rss_cpu_tbl[val] + 1];
}
else
{
rss_table_virt[idx] = (u8_t)val;
}
break;
}
}
}
}
prod_qe = pdev->kq_info.kwq_prod_qe;
prod_idx = pdev->kq_info.kwq_prod_idx;
rss_update = (l2_kwqe_rss_table_update_t *) prod_qe;
rss_update->rss_flags = L2_KWQE_FLAGS_LAYER_MASK_L2;
rss_update->rss_opcode = L2_KWQE_OPCODE_VALUE_UPDATE_RSS;
rss_update->rss_table_size = (u16_t) table_size;
rss_update->rss_table_haddr_lo = rss_table_phy.as_u32.low;
rss_update->rss_table_haddr_hi = rss_table_phy.as_u32.high;
rss_update->rss_host_opaque = 0;
rss_update->rss_hash_type = hash_type;
#if RSS_LOOKUP_TABLE_WA
rss_table_virt += RSS_INDIRECTION_TABLE_SIZE;
LM_INC64(&rss_table_phy, RSS_INDIRECTION_TABLE_SIZE);
rss_update->rss_lookup_table_lo = rss_table_phy.as_u32.low;
rss_update->rss_lookup_table_hi = rss_table_phy.as_u32.high;
rss_gen_tables(rss_key, (u32_t *) rss_table_virt);
#endif
if(prod_qe == pdev->kq_info.kwq_last_qe)
{
prod_qe = pdev->kq_info.kwq_virt;
}
else
{
prod_qe++;
}
prod_idx++;
rss_update = (l2_kwqe_rss_table_update_t *) prod_qe;
rss_update->rss_flags = L2_KWQE_FLAGS_LAYER_MASK_L2;
rss_update->rss_opcode = L2_KWQE_OPCODE_VALUE_ENABLE_RSS;
rss_update->rss_host_opaque = 0;
rss_update->rss_hash_type = hash_type;
if(prod_qe == pdev->kq_info.kwq_last_qe)
{
prod_qe = pdev->kq_info.kwq_virt;
}
else
{
prod_qe++;
}
prod_idx++;
pdev->kq_info.kwq_prod_qe = prod_qe;
pdev->kq_info.kwq_prod_idx = prod_idx;
MBQ_WR16(
pdev,
GET_CID(pdev->kq_info.kwq_cid_addr),
OFFSETOF(krnlq_context_t, krnlq_host_qidx),
prod_idx);
return LM_STATUS_SUCCESS;
}
#endif
lm_status_t
lm_disable_rss(
lm_device_t *pdev)
{
l2_kwqe_rss_table_update_t *rss_update;
kwqe_t *prod_qe;
u16_t prod_idx;
u32_t val;
if(pdev->kq_info.kwqe_left < 1)
{
pdev->kq_info.no_kwq_bd_left++;
return LM_STATUS_RESOURCE;
}
pdev->kq_info.kwqe_left -= 1;
if(CHIP_NUM(pdev) == CHIP_NUM_5709)
{
REG_RD(pdev, rlup.rlup_rss_config, &val);
val &= ~RLUP_RSS_CONFIG_IPV4_RSS_TYPE_OFF_XI;
val &= ~RLUP_RSS_CONFIG_IPV6_RSS_TYPE_OFF_XI;
REG_WR(pdev, rlup.rlup_rss_config, val);
}
prod_qe = pdev->kq_info.kwq_prod_qe;
prod_idx = pdev->kq_info.kwq_prod_idx;
rss_update = (l2_kwqe_rss_table_update_t *) prod_qe;
rss_update->rss_flags = L2_KWQE_FLAGS_LAYER_MASK_L2;
rss_update->rss_opcode = L2_KWQE_OPCODE_VALUE_DISABLE_RSS;
if(prod_qe == pdev->kq_info.kwq_last_qe)
{
prod_qe = pdev->kq_info.kwq_virt;
}
else
{
prod_qe++;
}
prod_idx++;
pdev->kq_info.kwq_prod_qe = prod_qe;
pdev->kq_info.kwq_prod_idx = prod_idx;
MBQ_WR16(
pdev,
GET_CID(pdev->kq_info.kwq_cid_addr),
OFFSETOF(krnlq_context_t, krnlq_host_qidx),
prod_idx);
return LM_STATUS_SUCCESS;
}
#endif
void lm_set_pcie_nfe_report(lm_device_t *pdev)
{
if(CHIP_NUM(pdev) == CHIP_NUM_5709 &&
pdev->params.disable_pcie_nfr)
{
u16_t pci_devctl;
REG_RD(pdev,pci_config.pcicfg_device_control,&pci_devctl);
pci_devctl &= ~PCICFG_DEVICE_CONTROL_NON_FATAL_REP_ENA;
REG_WR(pdev,pci_config.pcicfg_device_control,pci_devctl);
}
}
void lm_clear_coalescing_ticks(lm_device_t *pdev)
{
pdev->params.tx_quick_cons_trip = 1;
pdev->params.tx_quick_cons_trip_int = 1;
pdev->params.rx_quick_cons_trip = 1;
pdev->params.rx_quick_cons_trip_int = 1;
pdev->params.comp_prod_trip = 1;
pdev->params.comp_prod_trip_int = 1;
pdev->params.tx_ticks = 0;
pdev->params.tx_ticks_int = 0;
pdev->params.com_ticks = 0;
pdev->params.com_ticks_int = 0;
pdev->params.cmd_ticks = 0;
pdev->params.cmd_ticks_int = 0;
pdev->params.rx_ticks = 0;
pdev->params.rx_ticks_int = 0;
pdev->params.stats_ticks = 0;
pdev->params.psb_tx_cons_trip = 0x10001;
pdev->params.psb_rx_cons_trip = 0x10001;
pdev->params.psb_comp_prod_trip = 0x10001;
pdev->params.psb_tx_ticks = 0;
pdev->params.psb_rx_ticks = 0;
pdev->params.psb_com_ticks = 0;
pdev->params.psb_cmd_ticks = 0;
pdev->params.psb_period_ticks = 0;
}
u8_t lm_is_mmio_ok(lm_device_t *pdev)
{
u32_t val;
REG_RD(pdev, pci_config.pcicfg_vendor_id, &val);
if (0xffffffff == val)
{
return FALSE;
}
else
{
return TRUE;
}
}
#if defined(LM_NON_LEGACY_MODE_SUPPORT)
void
lm_create_q_group(
lm_device_t *pdev,
u32_t q_group_id,
u32_t lookahead_sz
)
{
u32_t val;
lm_rx_chain_t *rxq;
rxq = &pdev->rx_info.chain[q_group_id];
rxq->vmq_lookahead_size = lookahead_sz;
val = lookahead_sz << 16;
CTX_WR(
pdev,
rxq->cid_addr,
WORD_ALIGNED_OFFSETOF(l2_bd_chain_context_t,
l2ctx_vmq_lookahead_sz),
val);
}
lm_status_t
lm_destroy_q_group(
lm_device_t *pdev,
u32_t q_group_id,
u32_t num_queues
)
{
u32_t num_kwqes_needed;
kwqe_t *prod_qe;
u16_t prod_idx;
l2_kwqe_vm_free_rx_queue_t *kwqe_free_rxq;
num_kwqes_needed = num_queues;
if(pdev->kq_info.kwqe_left < num_kwqes_needed)
{
DbgMessage(pdev, WARN, "No more KWQE left.\n");
pdev->kq_info.no_kwq_bd_left++;
return LM_STATUS_RESOURCE;
}
prod_qe = pdev->kq_info.kwq_prod_qe;
prod_idx = pdev->kq_info.kwq_prod_idx;
kwqe_free_rxq = (l2_kwqe_vm_free_rx_queue_t *) prod_qe;
if(q_group_id <= RX_CHAIN_IDX3)
{
if(q_group_id == RX_CHAIN_IDX0)
{
u8_t idx;
for(idx = 0; idx < num_queues; idx++)
{
kwqe_free_rxq->flags = L2_KWQE_FLAGS_LAYER_MASK_L2;
kwqe_free_rxq->queue_type = L2_NORMAL_QUEUE;
if(idx == 0)
kwqe_free_rxq->qid = (u8_t)q_group_id;
else
{
kwqe_free_rxq->qid = idx + 3;
}
kwqe_free_rxq->opcode = L2_KWQE_OPCODE_VALUE_VM_FREE_RX_QUEUE;
if(prod_qe == pdev->kq_info.kwq_last_qe)
{
prod_qe = pdev->kq_info.kwq_virt;
}
else
{
prod_qe++;
}
prod_idx++;
pdev->kq_info.kwqe_left -= 1;
kwqe_free_rxq = (l2_kwqe_vm_free_rx_queue_t *) prod_qe;
}
pdev->kq_info.kwq_prod_qe = prod_qe;
pdev->kq_info.kwq_prod_idx = prod_idx;
MBQ_WR16(
pdev,
GET_CID(pdev->kq_info.kwq_cid_addr),
OFFSETOF(krnlq_context_t, krnlq_host_qidx),
prod_idx);
return LM_STATUS_SUCCESS;
}
else
{
kwqe_free_rxq->queue_type = L2_NORMAL_QUEUE;
kwqe_free_rxq->qid = (u8_t)q_group_id;
pdev->kq_info.kwqe_left -= 1;
#if INCLUDE_OFLD_SUPPORT
if(q_group_id == RX_CHAIN_IDX2 &&
!s_list_is_empty(&pdev->rx_info.chain[RX_CHAIN_IDX1].active_descq))
{
kwqe_free_rxq->flags = L2_KWQE_FLAGS_LAYER_MASK_L2;
kwqe_free_rxq->opcode = L2_KWQE_OPCODE_VALUE_VM_FREE_RX_QUEUE;
if(prod_qe == pdev->kq_info.kwq_last_qe)
{
prod_qe = pdev->kq_info.kwq_virt;
}
else
{
prod_qe++;
}
prod_idx++;
kwqe_free_rxq = (l2_kwqe_vm_free_rx_queue_t *) prod_qe;
kwqe_free_rxq->queue_type = L2_NORMAL_QUEUE;
kwqe_free_rxq->qid = (u8_t)RX_CHAIN_IDX1;
pdev->kq_info.kwqe_left -= 1;
}
#endif
}
}
else
{
kwqe_free_rxq->queue_type = L2_VM_QUEUE;
kwqe_free_rxq->qid = (u8_t)q_group_id;
pdev->kq_info.kwqe_left -= 1;
}
kwqe_free_rxq->flags = L2_KWQE_FLAGS_LAYER_MASK_L2;
kwqe_free_rxq->opcode = L2_KWQE_OPCODE_VALUE_VM_FREE_RX_QUEUE;
if(prod_qe == pdev->kq_info.kwq_last_qe)
{
prod_qe = pdev->kq_info.kwq_virt;
}
else
{
prod_qe++;
}
prod_idx++;
pdev->kq_info.kwq_prod_qe = prod_qe;
pdev->kq_info.kwq_prod_idx = prod_idx;
MBQ_WR16(
pdev,
GET_CID(pdev->kq_info.kwq_cid_addr),
OFFSETOF(krnlq_context_t, krnlq_host_qidx),
prod_idx);
return LM_STATUS_SUCCESS;
}
VOID
lm_update_defq_filter_ctx(
lm_device_t *pdev,
u8_t valid
)
{
u32_t ctx_offset = pdev->vars.hw_filter_ctx_offset;
u32_t val = 0;
if(valid)
val |= L2_VM_FILTER_MAC << 16;
REG_WR_IND(
pdev,
OFFSETOF(reg_space_t, rxp.rxp_scratch[0])+ctx_offset,
val);
}
lm_status_t
lm_chng_q_group_filter(
lm_device_t *pdev,
u32_t q_group_id,
u8_t *dest_mac,
u16_t *vlan_ptr,
u32_t filter_id
)
{
kwqe_t *prod_qe;
u16_t prod_idx;
if(pdev->kq_info.kwqe_left < 1)
{
DbgMessage(pdev, WARN, "No more KWQE left.\n");
pdev->kq_info.no_kwq_bd_left++;
return LM_STATUS_RESOURCE;
}
prod_qe = pdev->kq_info.kwq_prod_qe;
prod_idx = pdev->kq_info.kwq_prod_idx;
pdev->kq_info.kwqe_left -= 1;
if(dest_mac == NULL && vlan_ptr == NULL)
{
l2_kwqe_vm_remove_rx_filter_t * kwqe_remove_rx_filter =
(l2_kwqe_vm_remove_rx_filter_t *) prod_qe;
kwqe_remove_rx_filter->flags = L2_KWQE_FLAGS_LAYER_MASK_L2;
kwqe_remove_rx_filter->qid = (u8_t)q_group_id;
kwqe_remove_rx_filter->filter_id = (u8_t)filter_id;
kwqe_remove_rx_filter->opcode = L2_KWQE_OPCODE_VALUE_VM_REMOVE_RX_FILTER;
}
else
{
l2_kwqe_vm_set_rx_filter_t * kwqe_set_rx_filter =
(l2_kwqe_vm_set_rx_filter_t *) prod_qe;
kwqe_set_rx_filter->flags = L2_KWQE_FLAGS_LAYER_MASK_L2;
kwqe_set_rx_filter->qid = (u8_t)q_group_id;
kwqe_set_rx_filter->filter_id = (u8_t)filter_id;
if(vlan_ptr)
{
kwqe_set_rx_filter->vlan = *vlan_ptr;
kwqe_set_rx_filter->filter_type = L2_VM_FILTER_MAC_VLAN;
}
else
{
kwqe_set_rx_filter->filter_type = L2_VM_FILTER_MAC;
}
kwqe_set_rx_filter->opcode = L2_KWQE_OPCODE_VALUE_VM_SET_RX_FILTER;
}
if(prod_qe == pdev->kq_info.kwq_last_qe)
{
prod_qe = pdev->kq_info.kwq_virt;
}
else
{
prod_qe++;
}
prod_idx++;
pdev->kq_info.kwq_prod_qe = prod_qe;
pdev->kq_info.kwq_prod_idx = prod_idx;
MBQ_WR16(
pdev,
GET_CID(pdev->kq_info.kwq_cid_addr),
OFFSETOF(krnlq_context_t, krnlq_host_qidx),
prod_idx);
return LM_STATUS_PENDING;
}
u32_t
lm_service_l2_kcqes(
struct _lm_device_t *pdev,
kcqe_t *cqe_ptr[],
u32_t num_cqes)
{
u32_t cqe_serviced_cnt;
u32_t cqe_cnt;
u8_t success;
kcqe_t *kcqe;
lm_status_t lm_status;
cqe_serviced_cnt = 0;
while(num_cqes)
{
cqe_cnt = 0;
while(cqe_ptr[cqe_cnt]->kcqe_flags & KCQE_FLAGS_NEXT)
{
cqe_cnt++;
}
cqe_cnt++;
DbgBreakIf(cqe_cnt > num_cqes);
kcqe = *cqe_ptr;
DbgBreakIf((kcqe->kcqe_flags & KCQE_FLAGS_LAYER_MASK) !=
KCQE_FLAGS_LAYER_MASK_L2);
switch(kcqe->kcqe_opcode)
{
case L2_KCQE_OPCODE_VALUE_VM_FREE_RX_QUEUE:
{
l2_kcqe_vm_free_rx_queue_t *kcqe_free_rxq;
kcqe_free_rxq = (l2_kcqe_vm_free_rx_queue_t *)kcqe;
mm_q_grp_abort_rx_request(
pdev,
kcqe_free_rxq->qid);
}
break;
case L2_KCQE_OPCODE_VALUE_VM_SET_RX_FILTER:
case L2_KCQE_OPCODE_VALUE_VM_REMOVE_RX_FILTER:
{
l2_kcqe_vm_set_rx_filter_t *kcqe_filter;
kcqe_filter = (l2_kcqe_vm_set_rx_filter_t *)kcqe;
if(kcqe_filter->status == SC_SUCCESS)
{
lm_status = LM_STATUS_SUCCESS;
}
else
{
lm_status = LM_STATUS_FAILURE;
}
mm_comp_l2_filter_chng_req(
pdev,
lm_status,
kcqe_filter->qid);
}
break;
case L2_KCQE_OPCODE_VALUE_VM_ALLOC_RX_QUEUE:
case L2_KCQE_OPCODE_VALUE_RX_PACKET:
case L2_KCQE_OPCODE_VALUE_ENABLE_RSS:
case L2_KCQE_OPCODE_VALUE_DISABLE_RSS:
case L2_KCQE_OPCODE_VALUE_UPDATE_RSS:
case L2_KCQE_OPCODE_VALUE_FLUSH_BD_CHAIN:
break;
default:
DbgBreakMsg("invalid l2 kcqe.\n");
break;
}
cqe_ptr += cqe_cnt;
num_cqes -= cqe_cnt;
cqe_serviced_cnt += cqe_cnt;
}
return cqe_serviced_cnt;
}
#endif