freebsd-dev/sys/dev/nxge/xgehal/xgehal-device.c
Pedro F. Giffuni 2aa858536f nxge(4): Remove useless self-assignment.
Apparently the original implementation brought a self-assignment
to work around some bogus lint issue that is not relevant anymore.

CID:	1347070
2016-06-03 15:33:21 +00:00

7267 lines
225 KiB
C

/*-
* Copyright (c) 2002-2007 Neterion, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <dev/nxge/include/xgehal-device.h>
#include <dev/nxge/include/xgehal-channel.h>
#include <dev/nxge/include/xgehal-fifo.h>
#include <dev/nxge/include/xgehal-ring.h>
#include <dev/nxge/include/xgehal-driver.h>
#include <dev/nxge/include/xgehal-mgmt.h>
#define SWITCH_SIGN 0xA5A5A5A5A5A5A5A5ULL
#define END_SIGN 0x0
#ifdef XGE_HAL_HERC_EMULATION
#undef XGE_HAL_PROCESS_LINK_INT_IN_ISR
#endif
/*
* Jenkins hash key length(in bytes)
*/
#define XGE_HAL_JHASH_MSG_LEN 50
/*
* mix(a,b,c) used in Jenkins hash algorithm
*/
#define mix(a,b,c) { \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<<8); \
c -= a; c -= b; c ^= (b>>13); \
a -= b; a -= c; a ^= (c>>12); \
b -= c; b -= a; b ^= (a<<16); \
c -= a; c -= b; c ^= (b>>5); \
a -= b; a -= c; a ^= (c>>3); \
b -= c; b -= a; b ^= (a<<10); \
c -= a; c -= b; c ^= (b>>15); \
}
/*
* __hal_device_event_queued
* @data: pointer to xge_hal_device_t structure
*
* Will be called when new event succesfully queued.
*/
void
__hal_device_event_queued(void *data, int event_type)
{
xge_assert(((xge_hal_device_t*)data)->magic == XGE_HAL_MAGIC);
if (g_xge_hal_driver->uld_callbacks.event_queued) {
g_xge_hal_driver->uld_callbacks.event_queued(data, event_type);
}
}
/*
* __hal_pio_mem_write32_upper
*
* Endiann-aware implementation of xge_os_pio_mem_write32().
* Since Xframe has 64bit registers, we differintiate uppper and lower
* parts.
*/
void
__hal_pio_mem_write32_upper(pci_dev_h pdev, pci_reg_h regh, u32 val, void *addr)
{
#if defined(XGE_OS_HOST_BIG_ENDIAN) && !defined(XGE_OS_PIO_LITTLE_ENDIAN)
xge_os_pio_mem_write32(pdev, regh, val, addr);
#else
xge_os_pio_mem_write32(pdev, regh, val, (void *)((char *)addr + 4));
#endif
}
/*
* __hal_pio_mem_write32_upper
*
* Endiann-aware implementation of xge_os_pio_mem_write32().
* Since Xframe has 64bit registers, we differintiate uppper and lower
* parts.
*/
void
__hal_pio_mem_write32_lower(pci_dev_h pdev, pci_reg_h regh, u32 val,
void *addr)
{
#if defined(XGE_OS_HOST_BIG_ENDIAN) && !defined(XGE_OS_PIO_LITTLE_ENDIAN)
xge_os_pio_mem_write32(pdev, regh, val,
(void *) ((char *)addr + 4));
#else
xge_os_pio_mem_write32(pdev, regh, val, addr);
#endif
}
/*
* __hal_device_register_poll
* @hldev: pointer to xge_hal_device_t structure
* @reg: register to poll for
* @op: 0 - bit reset, 1 - bit set
* @mask: mask for logical "and" condition based on %op
* @max_millis: maximum time to try to poll in milliseconds
*
* Will poll certain register for specified amount of time.
* Will poll until masked bit is not cleared.
*/
xge_hal_status_e
__hal_device_register_poll(xge_hal_device_t *hldev, u64 *reg,
int op, u64 mask, int max_millis)
{
u64 val64;
int i = 0;
xge_hal_status_e ret = XGE_HAL_FAIL;
xge_os_udelay(10);
do {
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0, reg);
if (op == 0 && !(val64 & mask))
return XGE_HAL_OK;
else if (op == 1 && (val64 & mask) == mask)
return XGE_HAL_OK;
xge_os_udelay(100);
} while (++i <= 9);
do {
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0, reg);
if (op == 0 && !(val64 & mask))
return XGE_HAL_OK;
else if (op == 1 && (val64 & mask) == mask)
return XGE_HAL_OK;
xge_os_udelay(1000);
} while (++i < max_millis);
return ret;
}
/*
* __hal_device_wait_quiescent
* @hldev: the device
* @hw_status: hw_status in case of error
*
* Will wait until device is quiescent for some blocks.
*/
static xge_hal_status_e
__hal_device_wait_quiescent(xge_hal_device_t *hldev, u64 *hw_status)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
/* poll and wait first */
#ifdef XGE_HAL_HERC_EMULATION
(void) __hal_device_register_poll(hldev, &bar0->adapter_status, 1,
(XGE_HAL_ADAPTER_STATUS_TDMA_READY |
XGE_HAL_ADAPTER_STATUS_RDMA_READY |
XGE_HAL_ADAPTER_STATUS_PFC_READY |
XGE_HAL_ADAPTER_STATUS_TMAC_BUF_EMPTY |
XGE_HAL_ADAPTER_STATUS_PIC_QUIESCENT |
XGE_HAL_ADAPTER_STATUS_MC_DRAM_READY |
XGE_HAL_ADAPTER_STATUS_MC_QUEUES_READY |
XGE_HAL_ADAPTER_STATUS_M_PLL_LOCK),
XGE_HAL_DEVICE_QUIESCENT_WAIT_MAX_MILLIS);
#else
(void) __hal_device_register_poll(hldev, &bar0->adapter_status, 1,
(XGE_HAL_ADAPTER_STATUS_TDMA_READY |
XGE_HAL_ADAPTER_STATUS_RDMA_READY |
XGE_HAL_ADAPTER_STATUS_PFC_READY |
XGE_HAL_ADAPTER_STATUS_TMAC_BUF_EMPTY |
XGE_HAL_ADAPTER_STATUS_PIC_QUIESCENT |
XGE_HAL_ADAPTER_STATUS_MC_DRAM_READY |
XGE_HAL_ADAPTER_STATUS_MC_QUEUES_READY |
XGE_HAL_ADAPTER_STATUS_M_PLL_LOCK |
XGE_HAL_ADAPTER_STATUS_P_PLL_LOCK),
XGE_HAL_DEVICE_QUIESCENT_WAIT_MAX_MILLIS);
#endif
return xge_hal_device_status(hldev, hw_status);
}
/**
* xge_hal_device_is_slot_freeze
* @devh: the device
*
* Returns non-zero if the slot is freezed.
* The determination is made based on the adapter_status
* register which will never give all FFs, unless PCI read
* cannot go through.
*/
int
xge_hal_device_is_slot_freeze(xge_hal_device_h devh)
{
xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u16 device_id;
u64 adapter_status =
xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_status);
xge_os_pci_read16(hldev->pdev,hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, device_id),
&device_id);
#ifdef TX_DEBUG
if (adapter_status == XGE_HAL_ALL_FOXES)
{
u64 dummy;
dummy = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->pcc_enable);
printf(">>> Slot is frozen!\n");
brkpoint(0);
}
#endif
return((adapter_status == XGE_HAL_ALL_FOXES) || (device_id == 0xffff));
}
/*
* __hal_device_led_actifity_fix
* @hldev: pointer to xge_hal_device_t structure
*
* SXE-002: Configure link and activity LED to turn it off
*/
static void
__hal_device_led_actifity_fix(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u16 subid;
u64 val64;
xge_os_pci_read16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, subsystem_id), &subid);
/*
* In the case of Herc, there is a new register named beacon control
* is added which was not present in Xena.
* Beacon control register in Herc is at the same offset as
* gpio control register in Xena. It means they are one and same in
* the case of Xena. Also, gpio control register offset in Herc and
* Xena is different.
* The current register map represents Herc(It means we have
* both beacon and gpio control registers in register map).
* WRT transition from Xena to Herc, all the code in Xena which was
* using gpio control register for LED handling would have to
* use beacon control register in Herc and the rest of the code
* which uses gpio control in Xena would use the same register
* in Herc.
* WRT LED handling(following code), In the case of Herc, beacon
* control register has to be used. This is applicable for Xena also,
* since it represents the gpio control register in Xena.
*/
if ((subid & 0xFF) >= 0x07) {
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->beacon_control);
val64 |= 0x0000800000000000ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->beacon_control);
val64 = 0x0411040400000000ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
(void *) ((u8 *)bar0 + 0x2700));
}
}
/* Constants for Fixing the MacAddress problem seen mostly on
* Alpha machines.
*/
static u64 xena_fix_mac[] = {
0x0060000000000000ULL, 0x0060600000000000ULL,
0x0040600000000000ULL, 0x0000600000000000ULL,
0x0020600000000000ULL, 0x0060600000000000ULL,
0x0020600000000000ULL, 0x0060600000000000ULL,
0x0020600000000000ULL, 0x0060600000000000ULL,
0x0020600000000000ULL, 0x0060600000000000ULL,
0x0020600000000000ULL, 0x0060600000000000ULL,
0x0020600000000000ULL, 0x0060600000000000ULL,
0x0020600000000000ULL, 0x0060600000000000ULL,
0x0020600000000000ULL, 0x0060600000000000ULL,
0x0020600000000000ULL, 0x0060600000000000ULL,
0x0020600000000000ULL, 0x0060600000000000ULL,
0x0020600000000000ULL, 0x0000600000000000ULL,
0x0040600000000000ULL, 0x0060600000000000ULL,
END_SIGN
};
/*
* __hal_device_fix_mac
* @hldev: HAL device handle.
*
* Fix for all "FFs" MAC address problems observed on Alpha platforms.
*/
static void
__hal_device_xena_fix_mac(xge_hal_device_t *hldev)
{
int i = 0;
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
/*
* In the case of Herc, there is a new register named beacon control
* is added which was not present in Xena.
* Beacon control register in Herc is at the same offset as
* gpio control register in Xena. It means they are one and same in
* the case of Xena. Also, gpio control register offset in Herc and
* Xena is different.
* The current register map represents Herc(It means we have
* both beacon and gpio control registers in register map).
* WRT transition from Xena to Herc, all the code in Xena which was
* using gpio control register for LED handling would have to
* use beacon control register in Herc and the rest of the code
* which uses gpio control in Xena would use the same register
* in Herc.
* In the following code(xena_fix_mac), beacon control register has
* to be used in the case of Xena, since it represents gpio control
* register. In the case of Herc, there is no change required.
*/
while (xena_fix_mac[i] != END_SIGN) {
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
xena_fix_mac[i++], &bar0->beacon_control);
xge_os_mdelay(1);
}
}
/*
* xge_hal_device_bcast_enable
* @hldev: HAL device handle.
*
* Enable receiving broadcasts.
* The host must first write RMAC_CFG_KEY "key"
* register, and then - MAC_CFG register.
*/
void
xge_hal_device_bcast_enable(xge_hal_device_h devh)
{
xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->mac_cfg);
val64 |= XGE_HAL_MAC_RMAC_BCAST_ENABLE;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
__hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0,
(u32)(val64 >> 32), &bar0->mac_cfg);
xge_debug_device(XGE_TRACE, "mac_cfg 0x"XGE_OS_LLXFMT": broadcast %s",
(unsigned long long)val64,
hldev->config.mac.rmac_bcast_en ? "enabled" : "disabled");
}
/*
* xge_hal_device_bcast_disable
* @hldev: HAL device handle.
*
* Disable receiving broadcasts.
* The host must first write RMAC_CFG_KEY "key"
* register, and then - MAC_CFG register.
*/
void
xge_hal_device_bcast_disable(xge_hal_device_h devh)
{
xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->mac_cfg);
val64 &= ~(XGE_HAL_MAC_RMAC_BCAST_ENABLE);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
__hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0,
(u32)(val64 >> 32), &bar0->mac_cfg);
xge_debug_device(XGE_TRACE, "mac_cfg 0x"XGE_OS_LLXFMT": broadcast %s",
(unsigned long long)val64,
hldev->config.mac.rmac_bcast_en ? "enabled" : "disabled");
}
/*
* __hal_device_shared_splits_configure
* @hldev: HAL device handle.
*
* TxDMA will stop Read request if the number of read split had exceeded
* the limit set by shared_splits
*/
static void
__hal_device_shared_splits_configure(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->pic_control);
val64 |=
XGE_HAL_PIC_CNTL_SHARED_SPLITS(hldev->config.shared_splits);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->pic_control);
xge_debug_device(XGE_TRACE, "%s", "shared splits configured");
}
/*
* __hal_device_rmac_padding_configure
* @hldev: HAL device handle.
*
* Configure RMAC frame padding. Depends on configuration, it
* can be send to host or removed by MAC.
*/
static void
__hal_device_rmac_padding_configure(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->mac_cfg);
val64 &= ( ~XGE_HAL_MAC_RMAC_ALL_ADDR_ENABLE );
val64 &= ( ~XGE_HAL_MAC_CFG_RMAC_PROM_ENABLE );
val64 |= XGE_HAL_MAC_CFG_TMAC_APPEND_PAD;
/*
* If the RTH enable bit is not set, strip the FCS
*/
if (!hldev->config.rth_en ||
!(xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->rts_rth_cfg) & XGE_HAL_RTS_RTH_EN)) {
val64 |= XGE_HAL_MAC_CFG_RMAC_STRIP_FCS;
}
val64 &= ( ~XGE_HAL_MAC_CFG_RMAC_STRIP_PAD );
val64 |= XGE_HAL_MAC_RMAC_DISCARD_PFRM;
__hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0,
(u32)(val64 >> 32), (char*)&bar0->mac_cfg);
xge_os_mdelay(1);
xge_debug_device(XGE_TRACE,
"mac_cfg 0x"XGE_OS_LLXFMT": frame padding configured",
(unsigned long long)val64);
}
/*
* __hal_device_pause_frames_configure
* @hldev: HAL device handle.
*
* Set Pause threshold.
*
* Pause frame is generated if the amount of data outstanding
* on any queue exceeded the ratio of
* (mac_control.mc_pause_threshold_q0q3 or q4q7)/256
*/
static void
__hal_device_pause_frames_configure(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
int i;
u64 val64;
switch (hldev->config.mac.media) {
case XGE_HAL_MEDIA_SR:
case XGE_HAL_MEDIA_SW:
val64=0xfffbfffbfffbfffbULL;
break;
case XGE_HAL_MEDIA_LR:
case XGE_HAL_MEDIA_LW:
val64=0xffbbffbbffbbffbbULL;
break;
case XGE_HAL_MEDIA_ER:
case XGE_HAL_MEDIA_EW:
default:
val64=0xffbbffbbffbbffbbULL;
break;
}
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->mc_pause_thresh_q0q3);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->mc_pause_thresh_q4q7);
/* Set the time value to be inserted in the pause frame generated
* by Xframe */
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->rmac_pause_cfg);
if (hldev->config.mac.rmac_pause_gen_en)
val64 |= XGE_HAL_RMAC_PAUSE_GEN_EN;
else
val64 &= ~(XGE_HAL_RMAC_PAUSE_GEN_EN);
if (hldev->config.mac.rmac_pause_rcv_en)
val64 |= XGE_HAL_RMAC_PAUSE_RCV_EN;
else
val64 &= ~(XGE_HAL_RMAC_PAUSE_RCV_EN);
val64 &= ~(XGE_HAL_RMAC_PAUSE_HG_PTIME(0xffff));
val64 |= XGE_HAL_RMAC_PAUSE_HG_PTIME(hldev->config.mac.rmac_pause_time);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rmac_pause_cfg);
val64 = 0;
for (i = 0; i<4; i++) {
val64 |=
(((u64)0xFF00|hldev->config.mac.mc_pause_threshold_q0q3)
<<(i*2*8));
}
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->mc_pause_thresh_q0q3);
val64 = 0;
for (i = 0; i<4; i++) {
val64 |=
(((u64)0xFF00|hldev->config.mac.mc_pause_threshold_q4q7)
<<(i*2*8));
}
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->mc_pause_thresh_q4q7);
xge_debug_device(XGE_TRACE, "%s", "pause frames configured");
}
/*
* Herc's clock rate doubled, unless the slot is 33MHz.
*/
unsigned int __hal_fix_time_ival_herc(xge_hal_device_t *hldev,
unsigned int time_ival)
{
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA)
return time_ival;
xge_assert(xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC);
if (hldev->bus_frequency != XGE_HAL_PCI_BUS_FREQUENCY_UNKNOWN &&
hldev->bus_frequency != XGE_HAL_PCI_BUS_FREQUENCY_33MHZ)
time_ival *= 2;
return time_ival;
}
/*
* __hal_device_bus_master_disable
* @hldev: HAL device handle.
*
* Disable bus mastership.
*/
static void
__hal_device_bus_master_disable (xge_hal_device_t *hldev)
{
u16 cmd;
u16 bus_master = 4;
xge_os_pci_read16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, command), &cmd);
cmd &= ~bus_master;
xge_os_pci_write16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, command), cmd);
}
/*
* __hal_device_bus_master_enable
* @hldev: HAL device handle.
*
* Disable bus mastership.
*/
static void
__hal_device_bus_master_enable (xge_hal_device_t *hldev)
{
u16 cmd;
u16 bus_master = 4;
xge_os_pci_read16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, command), &cmd);
/* already enabled? do nothing */
if (cmd & bus_master)
return;
cmd |= bus_master;
xge_os_pci_write16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, command), cmd);
}
/*
* __hal_device_intr_mgmt
* @hldev: HAL device handle.
* @mask: mask indicating which Intr block must be modified.
* @flag: if true - enable, otherwise - disable interrupts.
*
* Disable or enable device interrupts. Mask is used to specify
* which hardware blocks should produce interrupts. For details
* please refer to Xframe User Guide.
*/
static void
__hal_device_intr_mgmt(xge_hal_device_t *hldev, u64 mask, int flag)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64 = 0, temp64 = 0;
u64 gim, gim_saved;
gim_saved = gim = xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->general_int_mask);
/* Top level interrupt classification */
/* PIC Interrupts */
if ((mask & (XGE_HAL_TX_PIC_INTR/* | XGE_HAL_RX_PIC_INTR*/))) {
/* Enable PIC Intrs in the general intr mask register */
val64 = XGE_HAL_TXPIC_INT_M/* | XGE_HAL_PIC_RX_INT_M*/;
if (flag) {
gim &= ~((u64) val64);
temp64 = xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->pic_int_mask);
temp64 &= ~XGE_HAL_PIC_INT_TX;
#ifdef XGE_HAL_PROCESS_LINK_INT_IN_ISR
if (xge_hal_device_check_id(hldev) ==
XGE_HAL_CARD_HERC) {
temp64 &= ~XGE_HAL_PIC_INT_MISC;
}
#endif
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
temp64, &bar0->pic_int_mask);
#ifdef XGE_HAL_PROCESS_LINK_INT_IN_ISR
if (xge_hal_device_check_id(hldev) ==
XGE_HAL_CARD_HERC) {
/*
* Unmask only Link Up interrupt
*/
temp64 = xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->misc_int_mask);
temp64 &= ~XGE_HAL_MISC_INT_REG_LINK_UP_INT;
xge_os_pio_mem_write64(hldev->pdev,
hldev->regh0, temp64,
&bar0->misc_int_mask);
xge_debug_device(XGE_TRACE,
"unmask link up flag "XGE_OS_LLXFMT,
(unsigned long long)temp64);
}
#endif
} else { /* flag == 0 */
#ifdef XGE_HAL_PROCESS_LINK_INT_IN_ISR
if (xge_hal_device_check_id(hldev) ==
XGE_HAL_CARD_HERC) {
/*
* Mask both Link Up and Down interrupts
*/
temp64 = xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->misc_int_mask);
temp64 |= XGE_HAL_MISC_INT_REG_LINK_UP_INT;
temp64 |= XGE_HAL_MISC_INT_REG_LINK_DOWN_INT;
xge_os_pio_mem_write64(hldev->pdev,
hldev->regh0, temp64,
&bar0->misc_int_mask);
xge_debug_device(XGE_TRACE,
"mask link up/down flag "XGE_OS_LLXFMT,
(unsigned long long)temp64);
}
#endif
/* Disable PIC Intrs in the general intr mask
* register */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_ALL_INTRS_DIS,
&bar0->pic_int_mask);
gim |= val64;
}
}
/* DMA Interrupts */
/* Enabling/Disabling Tx DMA interrupts */
if (mask & XGE_HAL_TX_DMA_INTR) {
/* Enable TxDMA Intrs in the general intr mask register */
val64 = XGE_HAL_TXDMA_INT_M;
if (flag) {
gim &= ~((u64) val64);
/* Enable all TxDMA interrupts */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
0x0, &bar0->txdma_int_mask);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
0x0, &bar0->pfc_err_mask);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
0x0, &bar0->tda_err_mask);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
0x0, &bar0->pcc_err_mask);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
0x0, &bar0->tti_err_mask);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
0x0, &bar0->lso_err_mask);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
0x0, &bar0->tpa_err_mask);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
0x0, &bar0->sm_err_mask);
} else { /* flag == 0 */
/* Disable TxDMA Intrs in the general intr mask
* register */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_ALL_INTRS_DIS,
&bar0->txdma_int_mask);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_ALL_INTRS_DIS,
&bar0->pfc_err_mask);
gim |= val64;
}
}
/* Enabling/Disabling Rx DMA interrupts */
if (mask & XGE_HAL_RX_DMA_INTR) {
/* Enable RxDMA Intrs in the general intr mask register */
val64 = XGE_HAL_RXDMA_INT_M;
if (flag) {
gim &= ~((u64) val64);
/* All RxDMA block interrupts are disabled for now
* TODO */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_ALL_INTRS_DIS,
&bar0->rxdma_int_mask);
} else { /* flag == 0 */
/* Disable RxDMA Intrs in the general intr mask
* register */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_ALL_INTRS_DIS,
&bar0->rxdma_int_mask);
gim |= val64;
}
}
/* MAC Interrupts */
/* Enabling/Disabling MAC interrupts */
if (mask & (XGE_HAL_TX_MAC_INTR | XGE_HAL_RX_MAC_INTR)) {
val64 = XGE_HAL_TXMAC_INT_M | XGE_HAL_RXMAC_INT_M;
if (flag) {
gim &= ~((u64) val64);
/* All MAC block error inter. are disabled for now. */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_ALL_INTRS_DIS, &bar0->mac_int_mask);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_ALL_INTRS_DIS, &bar0->mac_rmac_err_mask);
} else { /* flag == 0 */
/* Disable MAC Intrs in the general intr mask
* register */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_ALL_INTRS_DIS, &bar0->mac_int_mask);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_ALL_INTRS_DIS, &bar0->mac_rmac_err_mask);
gim |= val64;
}
}
/* XGXS Interrupts */
if (mask & (XGE_HAL_TX_XGXS_INTR | XGE_HAL_RX_XGXS_INTR)) {
val64 = XGE_HAL_TXXGXS_INT_M | XGE_HAL_RXXGXS_INT_M;
if (flag) {
gim &= ~((u64) val64);
/* All XGXS block error interrupts are disabled for now
* TODO */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_ALL_INTRS_DIS, &bar0->xgxs_int_mask);
} else { /* flag == 0 */
/* Disable MC Intrs in the general intr mask register */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_ALL_INTRS_DIS, &bar0->xgxs_int_mask);
gim |= val64;
}
}
/* Memory Controller(MC) interrupts */
if (mask & XGE_HAL_MC_INTR) {
val64 = XGE_HAL_MC_INT_M;
if (flag) {
gim &= ~((u64) val64);
/* Enable all MC blocks error interrupts */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
0x0ULL, &bar0->mc_int_mask);
} else { /* flag == 0 */
/* Disable MC Intrs in the general intr mask
* register */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_ALL_INTRS_DIS, &bar0->mc_int_mask);
gim |= val64;
}
}
/* Tx traffic interrupts */
if (mask & XGE_HAL_TX_TRAFFIC_INTR) {
val64 = XGE_HAL_TXTRAFFIC_INT_M;
if (flag) {
gim &= ~((u64) val64);
/* Enable all the Tx side interrupts */
/* '0' Enables all 64 TX interrupt levels. */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, 0x0,
&bar0->tx_traffic_mask);
} else { /* flag == 0 */
/* Disable Tx Traffic Intrs in the general intr mask
* register. */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_ALL_INTRS_DIS,
&bar0->tx_traffic_mask);
gim |= val64;
}
}
/* Rx traffic interrupts */
if (mask & XGE_HAL_RX_TRAFFIC_INTR) {
val64 = XGE_HAL_RXTRAFFIC_INT_M;
if (flag) {
gim &= ~((u64) val64);
/* '0' Enables all 8 RX interrupt levels. */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, 0x0,
&bar0->rx_traffic_mask);
} else { /* flag == 0 */
/* Disable Rx Traffic Intrs in the general intr mask
* register.
*/
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_ALL_INTRS_DIS,
&bar0->rx_traffic_mask);
gim |= val64;
}
}
/* Sched Timer interrupt */
if (mask & XGE_HAL_SCHED_INTR) {
if (flag) {
temp64 = xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->txpic_int_mask);
temp64 &= ~XGE_HAL_TXPIC_INT_SCHED_INTR;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
temp64, &bar0->txpic_int_mask);
xge_hal_device_sched_timer(hldev,
hldev->config.sched_timer_us,
hldev->config.sched_timer_one_shot);
} else {
temp64 = xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->txpic_int_mask);
temp64 |= XGE_HAL_TXPIC_INT_SCHED_INTR;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
temp64, &bar0->txpic_int_mask);
xge_hal_device_sched_timer(hldev,
XGE_HAL_SCHED_TIMER_DISABLED,
XGE_HAL_SCHED_TIMER_ON_SHOT_ENABLE);
}
}
if (gim != gim_saved) {
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, gim,
&bar0->general_int_mask);
xge_debug_device(XGE_TRACE, "general_int_mask updated "
XGE_OS_LLXFMT" => "XGE_OS_LLXFMT,
(unsigned long long)gim_saved, (unsigned long long)gim);
}
}
/*
* __hal_device_bimodal_configure
* @hldev: HAL device handle.
*
* Bimodal parameters initialization.
*/
static void
__hal_device_bimodal_configure(xge_hal_device_t *hldev)
{
int i;
for (i=0; i<XGE_HAL_MAX_RING_NUM; i++) {
xge_hal_tti_config_t *tti;
xge_hal_rti_config_t *rti;
if (!hldev->config.ring.queue[i].configured)
continue;
rti = &hldev->config.ring.queue[i].rti;
tti = &hldev->bimodal_tti[i];
tti->enabled = 1;
tti->urange_a = hldev->bimodal_urange_a_en * 10;
tti->urange_b = 20;
tti->urange_c = 30;
tti->ufc_a = hldev->bimodal_urange_a_en * 8;
tti->ufc_b = 16;
tti->ufc_c = 32;
tti->ufc_d = 64;
tti->timer_val_us = hldev->bimodal_timer_val_us;
tti->timer_ac_en = 1;
tti->timer_ci_en = 0;
rti->urange_a = 10;
rti->urange_b = 20;
rti->urange_c = 30;
rti->ufc_a = 1; /* <= for netpipe type of tests */
rti->ufc_b = 4;
rti->ufc_c = 4;
rti->ufc_d = 4; /* <= 99% of a bandwidth traffic counts here */
rti->timer_ac_en = 1;
rti->timer_val_us = 5; /* for optimal bus efficiency usage */
}
}
/*
* __hal_device_tti_apply
* @hldev: HAL device handle.
*
* apply TTI configuration.
*/
static xge_hal_status_e
__hal_device_tti_apply(xge_hal_device_t *hldev, xge_hal_tti_config_t *tti,
int num, int runtime)
{
u64 val64, data1 = 0, data2 = 0;
xge_hal_pci_bar0_t *bar0;
if (runtime)
bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
else
bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
if (tti->timer_val_us) {
unsigned int tx_interval;
if (hldev->config.pci_freq_mherz) {
tx_interval = hldev->config.pci_freq_mherz *
tti->timer_val_us / 64;
tx_interval =
__hal_fix_time_ival_herc(hldev,
tx_interval);
} else {
tx_interval = tti->timer_val_us;
}
data1 |= XGE_HAL_TTI_DATA1_MEM_TX_TIMER_VAL(tx_interval);
if (tti->timer_ac_en) {
data1 |= XGE_HAL_TTI_DATA1_MEM_TX_TIMER_AC_EN;
}
if (tti->timer_ci_en) {
data1 |= XGE_HAL_TTI_DATA1_MEM_TX_TIMER_CI_EN;
}
if (!runtime) {
xge_debug_device(XGE_TRACE, "TTI[%d] timer enabled to %d, ci %s",
num, tx_interval, tti->timer_ci_en ?
"enabled": "disabled");
}
}
if (tti->urange_a ||
tti->urange_b ||
tti->urange_c ||
tti->ufc_a ||
tti->ufc_b ||
tti->ufc_c ||
tti->ufc_d ) {
data1 |= XGE_HAL_TTI_DATA1_MEM_TX_URNG_A(tti->urange_a) |
XGE_HAL_TTI_DATA1_MEM_TX_URNG_B(tti->urange_b) |
XGE_HAL_TTI_DATA1_MEM_TX_URNG_C(tti->urange_c);
data2 |= XGE_HAL_TTI_DATA2_MEM_TX_UFC_A(tti->ufc_a) |
XGE_HAL_TTI_DATA2_MEM_TX_UFC_B(tti->ufc_b) |
XGE_HAL_TTI_DATA2_MEM_TX_UFC_C(tti->ufc_c) |
XGE_HAL_TTI_DATA2_MEM_TX_UFC_D(tti->ufc_d);
}
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, data1,
&bar0->tti_data1_mem);
(void)xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->tti_data1_mem);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, data2,
&bar0->tti_data2_mem);
(void)xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->tti_data2_mem);
xge_os_wmb();
val64 = XGE_HAL_TTI_CMD_MEM_WE | XGE_HAL_TTI_CMD_MEM_STROBE_NEW_CMD |
XGE_HAL_TTI_CMD_MEM_OFFSET(num);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->tti_command_mem);
if (!runtime && __hal_device_register_poll(hldev, &bar0->tti_command_mem,
0, XGE_HAL_TTI_CMD_MEM_STROBE_NEW_CMD,
XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
/* upper layer may require to repeat */
return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
}
if (!runtime) {
xge_debug_device(XGE_TRACE, "TTI[%d] configured: tti_data1_mem 0x"
XGE_OS_LLXFMT, num,
(unsigned long long)xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->tti_data1_mem));
}
return XGE_HAL_OK;
}
/*
* __hal_device_tti_configure
* @hldev: HAL device handle.
*
* TTI Initialization.
* Initialize Transmit Traffic Interrupt Scheme.
*/
static xge_hal_status_e
__hal_device_tti_configure(xge_hal_device_t *hldev, int runtime)
{
int i;
for (i=0; i<XGE_HAL_MAX_FIFO_NUM; i++) {
int j;
if (!hldev->config.fifo.queue[i].configured)
continue;
for (j=0; j<XGE_HAL_MAX_FIFO_TTI_NUM; j++) {
xge_hal_status_e status;
if (!hldev->config.fifo.queue[i].tti[j].enabled)
continue;
/* at least some TTI enabled. Record it. */
hldev->tti_enabled = 1;
status = __hal_device_tti_apply(hldev,
&hldev->config.fifo.queue[i].tti[j],
i * XGE_HAL_MAX_FIFO_TTI_NUM + j, runtime);
if (status != XGE_HAL_OK)
return status;
}
}
/* processing bimodal TTIs */
for (i=0; i<XGE_HAL_MAX_RING_NUM; i++) {
xge_hal_status_e status;
if (!hldev->bimodal_tti[i].enabled)
continue;
/* at least some bimodal TTI enabled. Record it. */
hldev->tti_enabled = 1;
status = __hal_device_tti_apply(hldev, &hldev->bimodal_tti[i],
XGE_HAL_MAX_FIFO_TTI_RING_0 + i, runtime);
if (status != XGE_HAL_OK)
return status;
}
return XGE_HAL_OK;
}
/*
* __hal_device_rti_configure
* @hldev: HAL device handle.
*
* RTI Initialization.
* Initialize Receive Traffic Interrupt Scheme.
*/
xge_hal_status_e
__hal_device_rti_configure(xge_hal_device_t *hldev, int runtime)
{
xge_hal_pci_bar0_t *bar0;
u64 val64, data1 = 0, data2 = 0;
int i;
if (runtime) {
/*
* we don't want to re-configure RTI in case when
* bimodal interrupts are in use. Instead reconfigure TTI
* with new RTI values.
*/
if (hldev->config.bimodal_interrupts) {
__hal_device_bimodal_configure(hldev);
return __hal_device_tti_configure(hldev, 1);
}
bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
} else
bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
for (i=0; i<XGE_HAL_MAX_RING_NUM; i++) {
xge_hal_rti_config_t *rti = &hldev->config.ring.queue[i].rti;
if (!hldev->config.ring.queue[i].configured)
continue;
if (rti->timer_val_us) {
unsigned int rx_interval;
if (hldev->config.pci_freq_mherz) {
rx_interval = hldev->config.pci_freq_mherz *
rti->timer_val_us / 8;
rx_interval =
__hal_fix_time_ival_herc(hldev,
rx_interval);
} else {
rx_interval = rti->timer_val_us;
}
data1 |=XGE_HAL_RTI_DATA1_MEM_RX_TIMER_VAL(rx_interval);
if (rti->timer_ac_en) {
data1 |= XGE_HAL_RTI_DATA1_MEM_RX_TIMER_AC_EN;
}
data1 |= XGE_HAL_RTI_DATA1_MEM_RX_TIMER_CI_EN;
}
if (rti->urange_a ||
rti->urange_b ||
rti->urange_c ||
rti->ufc_a ||
rti->ufc_b ||
rti->ufc_c ||
rti->ufc_d) {
data1 |=XGE_HAL_RTI_DATA1_MEM_RX_URNG_A(rti->urange_a) |
XGE_HAL_RTI_DATA1_MEM_RX_URNG_B(rti->urange_b) |
XGE_HAL_RTI_DATA1_MEM_RX_URNG_C(rti->urange_c);
data2 |= XGE_HAL_RTI_DATA2_MEM_RX_UFC_A(rti->ufc_a) |
XGE_HAL_RTI_DATA2_MEM_RX_UFC_B(rti->ufc_b) |
XGE_HAL_RTI_DATA2_MEM_RX_UFC_C(rti->ufc_c) |
XGE_HAL_RTI_DATA2_MEM_RX_UFC_D(rti->ufc_d);
}
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, data1,
&bar0->rti_data1_mem);
(void)xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->rti_data1_mem);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, data2,
&bar0->rti_data2_mem);
(void)xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->rti_data2_mem);
xge_os_wmb();
val64 = XGE_HAL_RTI_CMD_MEM_WE |
XGE_HAL_RTI_CMD_MEM_STROBE_NEW_CMD;
val64 |= XGE_HAL_RTI_CMD_MEM_OFFSET(i);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rti_command_mem);
if (!runtime && __hal_device_register_poll(hldev,
&bar0->rti_command_mem, 0,
XGE_HAL_RTI_CMD_MEM_STROBE_NEW_CMD,
XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
/* upper layer may require to repeat */
return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
}
if (!runtime) {
xge_debug_device(XGE_TRACE,
"RTI[%d] configured: rti_data1_mem 0x"XGE_OS_LLXFMT,
i,
(unsigned long long)xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->rti_data1_mem));
}
}
return XGE_HAL_OK;
}
/* Constants to be programmed into the Xena's registers to configure
* the XAUI. */
static u64 default_xena_mdio_cfg[] = {
/* Reset PMA PLL */
0xC001010000000000ULL, 0xC0010100000000E0ULL,
0xC0010100008000E4ULL,
/* Remove Reset from PMA PLL */
0xC001010000000000ULL, 0xC0010100000000E0ULL,
0xC0010100000000E4ULL,
END_SIGN
};
static u64 default_herc_mdio_cfg[] = {
END_SIGN
};
static u64 default_xena_dtx_cfg[] = {
0x8000051500000000ULL, 0x80000515000000E0ULL,
0x80000515D93500E4ULL, 0x8001051500000000ULL,
0x80010515000000E0ULL, 0x80010515001E00E4ULL,
0x8002051500000000ULL, 0x80020515000000E0ULL,
0x80020515F21000E4ULL,
/* Set PADLOOPBACKN */
0x8002051500000000ULL, 0x80020515000000E0ULL,
0x80020515B20000E4ULL, 0x8003051500000000ULL,
0x80030515000000E0ULL, 0x80030515B20000E4ULL,
0x8004051500000000ULL, 0x80040515000000E0ULL,
0x80040515B20000E4ULL, 0x8005051500000000ULL,
0x80050515000000E0ULL, 0x80050515B20000E4ULL,
SWITCH_SIGN,
/* Remove PADLOOPBACKN */
0x8002051500000000ULL, 0x80020515000000E0ULL,
0x80020515F20000E4ULL, 0x8003051500000000ULL,
0x80030515000000E0ULL, 0x80030515F20000E4ULL,
0x8004051500000000ULL, 0x80040515000000E0ULL,
0x80040515F20000E4ULL, 0x8005051500000000ULL,
0x80050515000000E0ULL, 0x80050515F20000E4ULL,
END_SIGN
};
/*
static u64 default_herc_dtx_cfg[] = {
0x80000515BA750000ULL, 0x80000515BA7500E0ULL,
0x80000515BA750004ULL, 0x80000515BA7500E4ULL,
0x80010515003F0000ULL, 0x80010515003F00E0ULL,
0x80010515003F0004ULL, 0x80010515003F00E4ULL,
0x80020515F2100000ULL, 0x80020515F21000E0ULL,
0x80020515F2100004ULL, 0x80020515F21000E4ULL,
END_SIGN
};
*/
static u64 default_herc_dtx_cfg[] = {
0x8000051536750000ULL, 0x80000515367500E0ULL,
0x8000051536750004ULL, 0x80000515367500E4ULL,
0x80010515003F0000ULL, 0x80010515003F00E0ULL,
0x80010515003F0004ULL, 0x80010515003F00E4ULL,
0x801205150D440000ULL, 0x801205150D4400E0ULL,
0x801205150D440004ULL, 0x801205150D4400E4ULL,
0x80020515F2100000ULL, 0x80020515F21000E0ULL,
0x80020515F2100004ULL, 0x80020515F21000E4ULL,
END_SIGN
};
void
__hal_serial_mem_write64(xge_hal_device_t *hldev, u64 value, u64 *reg)
{
__hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0,
(u32)(value>>32), reg);
xge_os_wmb();
__hal_pio_mem_write32_lower(hldev->pdev, hldev->regh0,
(u32)value, reg);
xge_os_wmb();
xge_os_mdelay(1);
}
u64
__hal_serial_mem_read64(xge_hal_device_t *hldev, u64 *reg)
{
u64 val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
reg);
xge_os_mdelay(1);
return val64;
}
/*
* __hal_device_xaui_configure
* @hldev: HAL device handle.
*
* Configure XAUI Interface of Xena.
*
* To Configure the Xena's XAUI, one has to write a series
* of 64 bit values into two registers in a particular
* sequence. Hence a macro 'SWITCH_SIGN' has been defined
* which will be defined in the array of configuration values
* (default_dtx_cfg & default_mdio_cfg) at appropriate places
* to switch writing from one regsiter to another. We continue
* writing these values until we encounter the 'END_SIGN' macro.
* For example, After making a series of 21 writes into
* dtx_control register the 'SWITCH_SIGN' appears and hence we
* start writing into mdio_control until we encounter END_SIGN.
*/
static void
__hal_device_xaui_configure(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
int mdio_cnt = 0, dtx_cnt = 0;
u64 *default_dtx_cfg = NULL, *default_mdio_cfg = NULL;
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA) {
default_dtx_cfg = default_xena_dtx_cfg;
default_mdio_cfg = default_xena_mdio_cfg;
} else if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
default_dtx_cfg = default_herc_dtx_cfg;
default_mdio_cfg = default_herc_mdio_cfg;
} else {
xge_assert(default_dtx_cfg);
return;
}
do {
dtx_cfg:
while (default_dtx_cfg[dtx_cnt] != END_SIGN) {
if (default_dtx_cfg[dtx_cnt] == SWITCH_SIGN) {
dtx_cnt++;
goto mdio_cfg;
}
__hal_serial_mem_write64(hldev, default_dtx_cfg[dtx_cnt],
&bar0->dtx_control);
dtx_cnt++;
}
mdio_cfg:
while (default_mdio_cfg[mdio_cnt] != END_SIGN) {
if (default_mdio_cfg[mdio_cnt] == SWITCH_SIGN) {
mdio_cnt++;
goto dtx_cfg;
}
__hal_serial_mem_write64(hldev, default_mdio_cfg[mdio_cnt],
&bar0->mdio_control);
mdio_cnt++;
}
} while ( !((default_dtx_cfg[dtx_cnt] == END_SIGN) &&
(default_mdio_cfg[mdio_cnt] == END_SIGN)) );
xge_debug_device(XGE_TRACE, "%s", "XAUI interface configured");
}
/*
* __hal_device_mac_link_util_set
* @hldev: HAL device handle.
*
* Set sampling rate to calculate link utilization.
*/
static void
__hal_device_mac_link_util_set(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
val64 = XGE_HAL_MAC_TX_LINK_UTIL_VAL(
hldev->config.mac.tmac_util_period) |
XGE_HAL_MAC_RX_LINK_UTIL_VAL(
hldev->config.mac.rmac_util_period);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->mac_link_util);
xge_debug_device(XGE_TRACE, "%s",
"bandwidth link utilization configured");
}
/*
* __hal_device_set_swapper
* @hldev: HAL device handle.
*
* Set the Xframe's byte "swapper" in accordance with
* endianness of the host.
*/
xge_hal_status_e
__hal_device_set_swapper(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
/*
* from 32bit errarta:
*
* The SWAPPER_CONTROL register determines how the adapter accesses
* host memory as well as how it responds to read and write requests
* from the host system. Writes to this register should be performed
* carefully, since the byte swappers could reverse the order of bytes.
* When configuring this register keep in mind that writes to the PIF
* read and write swappers could reverse the order of the upper and
* lower 32-bit words. This means that the driver may have to write
* to the upper 32 bits of the SWAPPER_CONTROL twice in order to
* configure the entire register. */
/*
* The device by default set to a big endian format, so a big endian
* driver need not set anything.
*/
#if defined(XGE_HAL_CUSTOM_HW_SWAPPER)
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
0xffffffffffffffffULL, &bar0->swapper_ctrl);
val64 = XGE_HAL_CUSTOM_HW_SWAPPER;
xge_os_wmb();
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->swapper_ctrl);
xge_debug_device(XGE_TRACE, "using custom HW swapper 0x"XGE_OS_LLXFMT,
(unsigned long long)val64);
#elif !defined(XGE_OS_HOST_BIG_ENDIAN)
/*
* Initially we enable all bits to make it accessible by the driver,
* then we selectively enable only those bits that we want to set.
* i.e. force swapper to swap for the first time since second write
* will overwrite with the final settings.
*
* Use only for little endian platforms.
*/
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
0xffffffffffffffffULL, &bar0->swapper_ctrl);
xge_os_wmb();
val64 = (XGE_HAL_SWAPPER_CTRL_PIF_R_FE |
XGE_HAL_SWAPPER_CTRL_PIF_R_SE |
XGE_HAL_SWAPPER_CTRL_PIF_W_FE |
XGE_HAL_SWAPPER_CTRL_PIF_W_SE |
XGE_HAL_SWAPPER_CTRL_RTH_FE |
XGE_HAL_SWAPPER_CTRL_RTH_SE |
XGE_HAL_SWAPPER_CTRL_TXP_FE |
XGE_HAL_SWAPPER_CTRL_TXP_SE |
XGE_HAL_SWAPPER_CTRL_TXD_R_FE |
XGE_HAL_SWAPPER_CTRL_TXD_R_SE |
XGE_HAL_SWAPPER_CTRL_TXD_W_FE |
XGE_HAL_SWAPPER_CTRL_TXD_W_SE |
XGE_HAL_SWAPPER_CTRL_TXF_R_FE |
XGE_HAL_SWAPPER_CTRL_RXD_R_FE |
XGE_HAL_SWAPPER_CTRL_RXD_R_SE |
XGE_HAL_SWAPPER_CTRL_RXD_W_FE |
XGE_HAL_SWAPPER_CTRL_RXD_W_SE |
XGE_HAL_SWAPPER_CTRL_RXF_W_FE |
XGE_HAL_SWAPPER_CTRL_XMSI_FE |
XGE_HAL_SWAPPER_CTRL_STATS_FE | XGE_HAL_SWAPPER_CTRL_STATS_SE);
/*
if (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX) {
val64 |= XGE_HAL_SWAPPER_CTRL_XMSI_SE;
} */
__hal_pio_mem_write32_lower(hldev->pdev, hldev->regh0, (u32)val64,
&bar0->swapper_ctrl);
xge_os_wmb();
__hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0, (u32)(val64>>32),
&bar0->swapper_ctrl);
xge_os_wmb();
__hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0, (u32)(val64>>32),
&bar0->swapper_ctrl);
xge_debug_device(XGE_TRACE, "%s", "using little endian set");
#endif
/* Verifying if endian settings are accurate by reading a feedback
* register. */
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->pif_rd_swapper_fb);
if (val64 != XGE_HAL_IF_RD_SWAPPER_FB) {
xge_debug_device(XGE_ERR, "pif_rd_swapper_fb read "XGE_OS_LLXFMT,
(unsigned long long) val64);
return XGE_HAL_ERR_SWAPPER_CTRL;
}
xge_debug_device(XGE_TRACE, "%s", "be/le swapper enabled");
return XGE_HAL_OK;
}
/*
* __hal_device_rts_mac_configure - Configure RTS steering based on
* destination mac address.
* @hldev: HAL device handle.
*
*/
xge_hal_status_e
__hal_device_rts_mac_configure(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
if (!hldev->config.rts_mac_en) {
return XGE_HAL_OK;
}
/*
* Set the receive traffic steering mode from default(classic)
* to enhanced.
*/
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->rts_ctrl);
val64 |= XGE_HAL_RTS_CTRL_ENHANCED_MODE;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->rts_ctrl);
return XGE_HAL_OK;
}
/*
* __hal_device_rts_port_configure - Configure RTS steering based on
* destination or source port number.
* @hldev: HAL device handle.
*
*/
xge_hal_status_e
__hal_device_rts_port_configure(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
int rnum;
if (!hldev->config.rts_port_en) {
return XGE_HAL_OK;
}
/*
* Set the receive traffic steering mode from default(classic)
* to enhanced.
*/
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->rts_ctrl);
val64 |= XGE_HAL_RTS_CTRL_ENHANCED_MODE;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->rts_ctrl);
/*
* Initiate port steering according to per-ring configuration
*/
for (rnum = 0; rnum < XGE_HAL_MAX_RING_NUM; rnum++) {
int pnum;
xge_hal_ring_queue_t *queue = &hldev->config.ring.queue[rnum];
if (!queue->configured || queue->rts_port_en)
continue;
for (pnum = 0; pnum < XGE_HAL_MAX_STEERABLE_PORTS; pnum++) {
xge_hal_rts_port_t *port = &queue->rts_ports[pnum];
/*
* Skip and clear empty ports
*/
if (!port->num) {
/*
* Clear CAM memory
*/
xge_os_pio_mem_write64(hldev->pdev,
hldev->regh0, 0ULL,
&bar0->rts_pn_cam_data);
val64 = BIT(7) | BIT(15);
} else {
/*
* Assign new Port values according
* to configuration
*/
val64 = vBIT(port->num,8,16) |
vBIT(rnum,37,3) | BIT(63);
if (port->src)
val64 = BIT(47);
if (!port->udp)
val64 = BIT(7);
xge_os_pio_mem_write64(hldev->pdev,
hldev->regh0, val64,
&bar0->rts_pn_cam_data);
val64 = BIT(7) | BIT(15) | vBIT(pnum,24,8);
}
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->rts_pn_cam_ctrl);
/* poll until done */
if (__hal_device_register_poll(hldev,
&bar0->rts_pn_cam_ctrl, 0,
XGE_HAL_RTS_PN_CAM_CTRL_STROBE_BEING_EXECUTED,
XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) !=
XGE_HAL_OK) {
/* upper layer may require to repeat */
return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
}
}
}
return XGE_HAL_OK;
}
/*
* __hal_device_rts_qos_configure - Configure RTS steering based on
* qos.
* @hldev: HAL device handle.
*
*/
xge_hal_status_e
__hal_device_rts_qos_configure(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
int j, rx_ring_num;
if (!hldev->config.rts_qos_en) {
return XGE_HAL_OK;
}
/* First clear the RTS_DS_MEM_DATA */
val64 = 0;
for (j = 0; j < 64; j++ )
{
/* First clear the value */
val64 = XGE_HAL_RTS_DS_MEM_DATA(0);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rts_ds_mem_data);
val64 = XGE_HAL_RTS_DS_MEM_CTRL_WE |
XGE_HAL_RTS_DS_MEM_CTRL_STROBE_NEW_CMD |
XGE_HAL_RTS_DS_MEM_CTRL_OFFSET ( j );
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rts_ds_mem_ctrl);
/* poll until done */
if (__hal_device_register_poll(hldev,
&bar0->rts_ds_mem_ctrl, 0,
XGE_HAL_RTS_DS_MEM_CTRL_STROBE_CMD_BEING_EXECUTED,
XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
/* upper layer may require to repeat */
return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
}
}
rx_ring_num = 0;
for (j = 0; j < XGE_HAL_MAX_RING_NUM; j++) {
if (hldev->config.ring.queue[j].configured)
rx_ring_num++;
}
switch (rx_ring_num) {
case 1:
val64 = 0x0;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_0);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_1);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_2);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_3);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_4);
break;
case 2:
val64 = 0x0001000100010001ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_0);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_1);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_2);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_3);
val64 = 0x0001000100000000ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_4);
break;
case 3:
val64 = 0x0001020001020001ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_0);
val64 = 0x0200010200010200ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_1);
val64 = 0x0102000102000102ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_2);
val64 = 0x0001020001020001ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_3);
val64 = 0x0200010200000000ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_4);
break;
case 4:
val64 = 0x0001020300010203ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_0);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_1);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_2);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_3);
val64 = 0x0001020300000000ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_4);
break;
case 5:
val64 = 0x0001020304000102ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_0);
val64 = 0x0304000102030400ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_1);
val64 = 0x0102030400010203ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_2);
val64 = 0x0400010203040001ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_3);
val64 = 0x0203040000000000ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_4);
break;
case 6:
val64 = 0x0001020304050001ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_0);
val64 = 0x0203040500010203ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_1);
val64 = 0x0405000102030405ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_2);
val64 = 0x0001020304050001ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_3);
val64 = 0x0203040500000000ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_4);
break;
case 7:
val64 = 0x0001020304050600ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_0);
val64 = 0x0102030405060001ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_1);
val64 = 0x0203040506000102ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_2);
val64 = 0x0304050600010203ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_3);
val64 = 0x0405060000000000ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_4);
break;
case 8:
val64 = 0x0001020304050607ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_0);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_1);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_2);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_3);
val64 = 0x0001020300000000ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64, &bar0->rx_w_round_robin_4);
break;
}
return XGE_HAL_OK;
}
/*
* xge__hal_device_rts_mac_enable
*
* @devh: HAL device handle.
* @index: index number where the MAC addr will be stored
* @macaddr: MAC address
*
* - Enable RTS steering for the given MAC address. This function has to be
* called with lock acquired.
*
* NOTE:
* 1. ULD has to call this function with the index value which
* statisfies the following condition:
* ring_num = (index % 8)
* 2.ULD also needs to make sure that the index is not
* occupied by any MAC address. If that index has any MAC address
* it will be overwritten and HAL will not check for it.
*
*/
xge_hal_status_e
xge_hal_device_rts_mac_enable(xge_hal_device_h devh, int index, macaddr_t macaddr)
{
int max_addr = XGE_HAL_MAX_MAC_ADDRESSES;
xge_hal_status_e status;
xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)
max_addr = XGE_HAL_MAX_MAC_ADDRESSES_HERC;
if ( index >= max_addr )
return XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES;
/*
* Set the MAC address at the given location marked by index.
*/
status = xge_hal_device_macaddr_set(hldev, index, macaddr);
if (status != XGE_HAL_OK) {
xge_debug_device(XGE_ERR, "%s",
"Not able to set the mac addr");
return status;
}
return xge_hal_device_rts_section_enable(hldev, index);
}
/*
* xge__hal_device_rts_mac_disable
* @hldev: HAL device handle.
* @index: index number where to disable the MAC addr
*
* Disable RTS Steering based on the MAC address.
* This function should be called with lock acquired.
*
*/
xge_hal_status_e
xge_hal_device_rts_mac_disable(xge_hal_device_h devh, int index)
{
xge_hal_status_e status;
u8 macaddr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
int max_addr = XGE_HAL_MAX_MAC_ADDRESSES;
xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
xge_debug_ll(XGE_TRACE, "the index value is %d ", index);
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)
max_addr = XGE_HAL_MAX_MAC_ADDRESSES_HERC;
if ( index >= max_addr )
return XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES;
/*
* Disable MAC address @ given index location
*/
status = xge_hal_device_macaddr_set(hldev, index, macaddr);
if (status != XGE_HAL_OK) {
xge_debug_device(XGE_ERR, "%s",
"Not able to set the mac addr");
return status;
}
return XGE_HAL_OK;
}
/*
* __hal_device_rth_configure - Configure RTH for the device
* @hldev: HAL device handle.
*
* Using IT (Indirection Table).
*/
xge_hal_status_e
__hal_device_rth_it_configure(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
int rings[XGE_HAL_MAX_RING_NUM]={0};
int rnum;
int rmax;
int buckets_num;
int bucket;
if (!hldev->config.rth_en) {
return XGE_HAL_OK;
}
/*
* Set the receive traffic steering mode from default(classic)
* to enhanced.
*/
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->rts_ctrl);
val64 |= XGE_HAL_RTS_CTRL_ENHANCED_MODE;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->rts_ctrl);
buckets_num = (1 << hldev->config.rth_bucket_size);
rmax=0;
for (rnum = 0; rnum < XGE_HAL_MAX_RING_NUM; rnum++) {
if (hldev->config.ring.queue[rnum].configured &&
hldev->config.ring.queue[rnum].rth_en)
rings[rmax++] = rnum;
}
rnum = 0;
/* for starters: fill in all the buckets with rings "equally" */
for (bucket = 0; bucket < buckets_num; bucket++) {
if (rnum == rmax)
rnum = 0;
/* write data */
val64 = XGE_HAL_RTS_RTH_MAP_MEM_DATA_ENTRY_EN |
XGE_HAL_RTS_RTH_MAP_MEM_DATA(rings[rnum]);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rts_rth_map_mem_data);
/* execute */
val64 = XGE_HAL_RTS_RTH_MAP_MEM_CTRL_WE |
XGE_HAL_RTS_RTH_MAP_MEM_CTRL_STROBE |
XGE_HAL_RTS_RTH_MAP_MEM_CTRL_OFFSET(bucket);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rts_rth_map_mem_ctrl);
/* poll until done */
if (__hal_device_register_poll(hldev,
&bar0->rts_rth_map_mem_ctrl, 0,
XGE_HAL_RTS_RTH_MAP_MEM_CTRL_STROBE,
XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
}
rnum++;
}
val64 = XGE_HAL_RTS_RTH_EN;
val64 |= XGE_HAL_RTS_RTH_BUCKET_SIZE(hldev->config.rth_bucket_size);
val64 |= XGE_HAL_RTS_RTH_TCP_IPV4_EN | XGE_HAL_RTS_RTH_UDP_IPV4_EN | XGE_HAL_RTS_RTH_IPV4_EN |
XGE_HAL_RTS_RTH_TCP_IPV6_EN |XGE_HAL_RTS_RTH_UDP_IPV6_EN | XGE_HAL_RTS_RTH_IPV6_EN |
XGE_HAL_RTS_RTH_TCP_IPV6_EX_EN | XGE_HAL_RTS_RTH_UDP_IPV6_EX_EN | XGE_HAL_RTS_RTH_IPV6_EX_EN;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rts_rth_cfg);
xge_debug_device(XGE_TRACE, "RTH configured, bucket_size %d",
hldev->config.rth_bucket_size);
return XGE_HAL_OK;
}
/*
* __hal_spdm_entry_add - Add a new entry to the SPDM table.
*
* Add a new entry to the SPDM table
*
* This function add a new entry to the SPDM table.
*
* Note:
* This function should be called with spdm_lock.
*
* See also: xge_hal_spdm_entry_add , xge_hal_spdm_entry_remove.
*/
static xge_hal_status_e
__hal_spdm_entry_add(xge_hal_device_t *hldev, xge_hal_ipaddr_t *src_ip,
xge_hal_ipaddr_t *dst_ip, u16 l4_sp, u16 l4_dp, u8 is_tcp,
u8 is_ipv4, u8 tgt_queue, u32 jhash_value, u16 spdm_entry)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
u64 spdm_line_arr[8];
u8 line_no;
/*
* Clear the SPDM READY bit
*/
val64 = XGE_HAL_RX_PIC_INT_REG_SPDM_READY;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rxpic_int_reg);
xge_debug_device(XGE_TRACE,
"L4 SP %x:DP %x: hash %x tgt_queue %d ",
l4_sp, l4_dp, jhash_value, tgt_queue);
xge_os_memzero(&spdm_line_arr, sizeof(spdm_line_arr));
/*
* Construct the SPDM entry.
*/
spdm_line_arr[0] = vBIT(l4_sp,0,16) |
vBIT(l4_dp,16,32) |
vBIT(tgt_queue,53,3) |
vBIT(is_tcp,59,1) |
vBIT(is_ipv4,63,1);
if (is_ipv4) {
spdm_line_arr[1] = vBIT(src_ip->ipv4.addr,0,32) |
vBIT(dst_ip->ipv4.addr,32,32);
} else {
xge_os_memcpy(&spdm_line_arr[1], &src_ip->ipv6.addr[0], 8);
xge_os_memcpy(&spdm_line_arr[2], &src_ip->ipv6.addr[1], 8);
xge_os_memcpy(&spdm_line_arr[3], &dst_ip->ipv6.addr[0], 8);
xge_os_memcpy(&spdm_line_arr[4], &dst_ip->ipv6.addr[1], 8);
}
spdm_line_arr[7] = vBIT(jhash_value,0,32) |
BIT(63); /* entry enable bit */
/*
* Add the entry to the SPDM table
*/
for(line_no = 0; line_no < 8; line_no++) {
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
spdm_line_arr[line_no],
(void *)((char *)hldev->spdm_mem_base +
(spdm_entry * 64) +
(line_no * 8)));
}
/*
* Wait for the operation to be completed.
*/
if (__hal_device_register_poll(hldev, &bar0->rxpic_int_reg, 1,
XGE_HAL_RX_PIC_INT_REG_SPDM_READY,
XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
}
/*
* Add this information to a local SPDM table. The purpose of
* maintaining a local SPDM table is to avoid a search in the
* adapter SPDM table for spdm entry lookup which is very costly
* in terms of time.
*/
hldev->spdm_table[spdm_entry]->in_use = 1;
xge_os_memcpy(&hldev->spdm_table[spdm_entry]->src_ip, src_ip,
sizeof(xge_hal_ipaddr_t));
xge_os_memcpy(&hldev->spdm_table[spdm_entry]->dst_ip, dst_ip,
sizeof(xge_hal_ipaddr_t));
hldev->spdm_table[spdm_entry]->l4_sp = l4_sp;
hldev->spdm_table[spdm_entry]->l4_dp = l4_dp;
hldev->spdm_table[spdm_entry]->is_tcp = is_tcp;
hldev->spdm_table[spdm_entry]->is_ipv4 = is_ipv4;
hldev->spdm_table[spdm_entry]->tgt_queue = tgt_queue;
hldev->spdm_table[spdm_entry]->jhash_value = jhash_value;
hldev->spdm_table[spdm_entry]->spdm_entry = spdm_entry;
return XGE_HAL_OK;
}
/*
* __hal_device_rth_spdm_configure - Configure RTH for the device
* @hldev: HAL device handle.
*
* Using SPDM (Socket-Pair Direct Match).
*/
xge_hal_status_e
__hal_device_rth_spdm_configure(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;
u64 val64;
u8 spdm_bar_num;
u32 spdm_bar_offset;
int spdm_table_size;
int i;
if (!hldev->config.rth_spdm_en) {
return XGE_HAL_OK;
}
/*
* Retrieve the base address of SPDM Table.
*/
val64 = xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->spdm_bir_offset);
spdm_bar_num = XGE_HAL_SPDM_PCI_BAR_NUM(val64);
spdm_bar_offset = XGE_HAL_SPDM_PCI_BAR_OFFSET(val64);
/*
* spdm_bar_num specifies the PCI bar num register used to
* address the memory space. spdm_bar_offset specifies the offset
* of the SPDM memory with in the bar num memory space.
*/
switch (spdm_bar_num) {
case 0:
{
hldev->spdm_mem_base = (char *)bar0 +
(spdm_bar_offset * 8);
break;
}
case 1:
{
char *bar1 = (char *)hldev->bar1;
hldev->spdm_mem_base = bar1 + (spdm_bar_offset * 8);
break;
}
default:
xge_assert(((spdm_bar_num != 0) && (spdm_bar_num != 1)));
}
/*
* Retrieve the size of SPDM table(number of entries).
*/
val64 = xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->spdm_structure);
hldev->spdm_max_entries = XGE_HAL_SPDM_MAX_ENTRIES(val64);
spdm_table_size = hldev->spdm_max_entries *
sizeof(xge_hal_spdm_entry_t);
if (hldev->spdm_table == NULL) {
void *mem;
/*
* Allocate memory to hold the copy of SPDM table.
*/
if ((hldev->spdm_table = (xge_hal_spdm_entry_t **)
xge_os_malloc(
hldev->pdev,
(sizeof(xge_hal_spdm_entry_t *) *
hldev->spdm_max_entries))) == NULL) {
return XGE_HAL_ERR_OUT_OF_MEMORY;
}
if ((mem = xge_os_malloc(hldev->pdev, spdm_table_size)) == NULL)
{
xge_os_free(hldev->pdev, hldev->spdm_table,
(sizeof(xge_hal_spdm_entry_t *) *
hldev->spdm_max_entries));
return XGE_HAL_ERR_OUT_OF_MEMORY;
}
xge_os_memzero(mem, spdm_table_size);
for (i = 0; i < hldev->spdm_max_entries; i++) {
hldev->spdm_table[i] = (xge_hal_spdm_entry_t *)
((char *)mem +
i * sizeof(xge_hal_spdm_entry_t));
}
xge_os_spin_lock_init(&hldev->spdm_lock, hldev->pdev);
} else {
/*
* We are here because the host driver tries to
* do a soft reset on the device.
* Since the device soft reset clears the SPDM table, copy
* the entries from the local SPDM table to the actual one.
*/
xge_os_spin_lock(&hldev->spdm_lock);
for (i = 0; i < hldev->spdm_max_entries; i++) {
xge_hal_spdm_entry_t *spdm_entry = hldev->spdm_table[i];
if (spdm_entry->in_use) {
if (__hal_spdm_entry_add(hldev,
&spdm_entry->src_ip,
&spdm_entry->dst_ip,
spdm_entry->l4_sp,
spdm_entry->l4_dp,
spdm_entry->is_tcp,
spdm_entry->is_ipv4,
spdm_entry->tgt_queue,
spdm_entry->jhash_value,
spdm_entry->spdm_entry)
!= XGE_HAL_OK) {
/* Log an warning */
xge_debug_device(XGE_ERR,
"SPDM table update from local"
" memory failed");
}
}
}
xge_os_spin_unlock(&hldev->spdm_lock);
}
/*
* Set the receive traffic steering mode from default(classic)
* to enhanced.
*/
val64 = xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->rts_ctrl);
val64 |= XGE_HAL_RTS_CTRL_ENHANCED_MODE;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->rts_ctrl);
/*
* We may not need to configure rts_rth_jhash_cfg register as the
* default values are good enough to calculate the hash.
*/
/*
* As of now, set all the rth mask registers to zero. TODO.
*/
for(i = 0; i < 5; i++) {
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
0, &bar0->rts_rth_hash_mask[i]);
}
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
0, &bar0->rts_rth_hash_mask_5);
if (hldev->config.rth_spdm_use_l4) {
val64 = XGE_HAL_RTH_STATUS_SPDM_USE_L4;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->rts_rth_status);
}
val64 = XGE_HAL_RTS_RTH_EN;
val64 |= XGE_HAL_RTS_RTH_IPV4_EN | XGE_HAL_RTS_RTH_TCP_IPV4_EN;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rts_rth_cfg);
return XGE_HAL_OK;
}
/*
* __hal_device_pci_init
* @hldev: HAL device handle.
*
* Initialize certain PCI/PCI-X configuration registers
* with recommended values. Save config space for future hw resets.
*/
static void
__hal_device_pci_init(xge_hal_device_t *hldev)
{
int i, pcisize = 0;
u16 cmd = 0;
u8 val;
/* Store PCI device ID and revision for future references where in we
* decide Xena revision using PCI sub system ID */
xge_os_pci_read16(hldev->pdev,hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, device_id),
&hldev->device_id);
xge_os_pci_read8(hldev->pdev,hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, revision),
&hldev->revision);
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)
pcisize = XGE_HAL_PCISIZE_HERC;
else if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA)
pcisize = XGE_HAL_PCISIZE_XENA;
/* save original PCI config space to restore it on device_terminate() */
for (i = 0; i < pcisize; i++) {
xge_os_pci_read32(hldev->pdev, hldev->cfgh, i*4,
(u32*)&hldev->pci_config_space_bios + i);
}
/* Set the PErr Repconse bit and SERR in PCI command register. */
xge_os_pci_read16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, command), &cmd);
cmd |= 0x140;
xge_os_pci_write16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, command), cmd);
/* Set user spcecified value for the PCI Latency Timer */
if (hldev->config.latency_timer &&
hldev->config.latency_timer != XGE_HAL_USE_BIOS_DEFAULT_LATENCY) {
xge_os_pci_write8(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t,
latency_timer),
(u8)hldev->config.latency_timer);
}
/* Read back latency timer to reflect it into user level */
xge_os_pci_read8(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, latency_timer), &val);
hldev->config.latency_timer = val;
/* Enable Data Parity Error Recovery in PCI-X command register. */
xge_os_pci_read16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, pcix_command), &cmd);
cmd |= 1;
xge_os_pci_write16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, pcix_command), cmd);
/* Set MMRB count in PCI-X command register. */
if (hldev->config.mmrb_count != XGE_HAL_DEFAULT_BIOS_MMRB_COUNT) {
cmd &= 0xFFF3;
cmd |= hldev->config.mmrb_count << 2;
xge_os_pci_write16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, pcix_command),
cmd);
}
/* Read back MMRB count to reflect it into user level */
xge_os_pci_read16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, pcix_command),
&cmd);
cmd &= 0x000C;
hldev->config.mmrb_count = cmd>>2;
/* Setting Maximum outstanding splits based on system type. */
if (hldev->config.max_splits_trans != XGE_HAL_USE_BIOS_DEFAULT_SPLITS) {
xge_os_pci_read16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, pcix_command),
&cmd);
cmd &= 0xFF8F;
cmd |= hldev->config.max_splits_trans << 4;
xge_os_pci_write16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, pcix_command),
cmd);
}
/* Read back max split trans to reflect it into user level */
xge_os_pci_read16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, pcix_command), &cmd);
cmd &= 0x0070;
hldev->config.max_splits_trans = cmd>>4;
/* Forcibly disabling relaxed ordering capability of the card. */
xge_os_pci_read16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, pcix_command), &cmd);
cmd &= 0xFFFD;
xge_os_pci_write16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, pcix_command), cmd);
/* save PCI config space for future resets */
for (i = 0; i < pcisize; i++) {
xge_os_pci_read32(hldev->pdev, hldev->cfgh, i*4,
(u32*)&hldev->pci_config_space + i);
}
}
/*
* __hal_device_pci_info_get - Get PCI bus informations such as width, frequency
* and mode.
* @devh: HAL device handle.
* @pci_mode: pointer to a variable of enumerated type
* xge_hal_pci_mode_e{}.
* @bus_frequency: pointer to a variable of enumerated type
* xge_hal_pci_bus_frequency_e{}.
* @bus_width: pointer to a variable of enumerated type
* xge_hal_pci_bus_width_e{}.
*
* Get pci mode, frequency, and PCI bus width.
*
* Returns: one of the xge_hal_status_e{} enumerated types.
* XGE_HAL_OK - for success.
* XGE_HAL_ERR_INVALID_PCI_INFO - for invalid PCI information from the card.
* XGE_HAL_ERR_BAD_DEVICE_ID - for invalid card.
*
* See Also: xge_hal_pci_mode_e, xge_hal_pci_mode_e, xge_hal_pci_width_e.
*/
static xge_hal_status_e
__hal_device_pci_info_get(xge_hal_device_h devh, xge_hal_pci_mode_e *pci_mode,
xge_hal_pci_bus_frequency_e *bus_frequency,
xge_hal_pci_bus_width_e *bus_width)
{
xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
xge_hal_status_e rc_status = XGE_HAL_OK;
xge_hal_card_e card_id = xge_hal_device_check_id (devh);
#ifdef XGE_HAL_HERC_EMULATION
hldev->config.pci_freq_mherz =
XGE_HAL_PCI_BUS_FREQUENCY_66MHZ;
*bus_frequency =
XGE_HAL_PCI_BUS_FREQUENCY_66MHZ;
*pci_mode = XGE_HAL_PCI_66MHZ_MODE;
#else
if (card_id == XGE_HAL_CARD_HERC) {
xge_hal_pci_bar0_t *bar0 =
(xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 pci_info = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->pci_info);
if (XGE_HAL_PCI_32_BIT & pci_info)
*bus_width = XGE_HAL_PCI_BUS_WIDTH_32BIT;
else
*bus_width = XGE_HAL_PCI_BUS_WIDTH_64BIT;
switch((pci_info & XGE_HAL_PCI_INFO)>>60)
{
case XGE_HAL_PCI_33MHZ_MODE:
*bus_frequency =
XGE_HAL_PCI_BUS_FREQUENCY_33MHZ;
*pci_mode = XGE_HAL_PCI_33MHZ_MODE;
break;
case XGE_HAL_PCI_66MHZ_MODE:
*bus_frequency =
XGE_HAL_PCI_BUS_FREQUENCY_66MHZ;
*pci_mode = XGE_HAL_PCI_66MHZ_MODE;
break;
case XGE_HAL_PCIX_M1_66MHZ_MODE:
*bus_frequency =
XGE_HAL_PCI_BUS_FREQUENCY_66MHZ;
*pci_mode = XGE_HAL_PCIX_M1_66MHZ_MODE;
break;
case XGE_HAL_PCIX_M1_100MHZ_MODE:
*bus_frequency =
XGE_HAL_PCI_BUS_FREQUENCY_100MHZ;
*pci_mode = XGE_HAL_PCIX_M1_100MHZ_MODE;
break;
case XGE_HAL_PCIX_M1_133MHZ_MODE:
*bus_frequency =
XGE_HAL_PCI_BUS_FREQUENCY_133MHZ;
*pci_mode = XGE_HAL_PCIX_M1_133MHZ_MODE;
break;
case XGE_HAL_PCIX_M2_66MHZ_MODE:
*bus_frequency =
XGE_HAL_PCI_BUS_FREQUENCY_133MHZ;
*pci_mode = XGE_HAL_PCIX_M2_66MHZ_MODE;
break;
case XGE_HAL_PCIX_M2_100MHZ_MODE:
*bus_frequency =
XGE_HAL_PCI_BUS_FREQUENCY_200MHZ;
*pci_mode = XGE_HAL_PCIX_M2_100MHZ_MODE;
break;
case XGE_HAL_PCIX_M2_133MHZ_MODE:
*bus_frequency =
XGE_HAL_PCI_BUS_FREQUENCY_266MHZ;
*pci_mode = XGE_HAL_PCIX_M2_133MHZ_MODE;
break;
case XGE_HAL_PCIX_M1_RESERVED:
case XGE_HAL_PCIX_M1_66MHZ_NS:
case XGE_HAL_PCIX_M1_100MHZ_NS:
case XGE_HAL_PCIX_M1_133MHZ_NS:
case XGE_HAL_PCIX_M2_RESERVED:
case XGE_HAL_PCIX_533_RESERVED:
default:
rc_status = XGE_HAL_ERR_INVALID_PCI_INFO;
xge_debug_device(XGE_ERR,
"invalid pci info "XGE_OS_LLXFMT,
(unsigned long long)pci_info);
break;
}
if (rc_status != XGE_HAL_ERR_INVALID_PCI_INFO)
xge_debug_device(XGE_TRACE, "PCI info: mode %d width "
"%d frequency %d", *pci_mode, *bus_width,
*bus_frequency);
if (hldev->config.pci_freq_mherz ==
XGE_HAL_DEFAULT_USE_HARDCODE) {
hldev->config.pci_freq_mherz = *bus_frequency;
}
}
/* for XENA, we report PCI mode, only. PCI bus frequency, and bus width
* are set to unknown */
else if (card_id == XGE_HAL_CARD_XENA) {
u32 pcix_status;
u8 dev_num, bus_num;
/* initialize defaults for XENA */
*bus_frequency = XGE_HAL_PCI_BUS_FREQUENCY_UNKNOWN;
*bus_width = XGE_HAL_PCI_BUS_WIDTH_UNKNOWN;
xge_os_pci_read32(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, pcix_status),
&pcix_status);
dev_num = (u8)((pcix_status & 0xF8) >> 3);
bus_num = (u8)((pcix_status & 0xFF00) >> 8);
if (dev_num == 0 && bus_num == 0)
*pci_mode = XGE_HAL_PCI_BASIC_MODE;
else
*pci_mode = XGE_HAL_PCIX_BASIC_MODE;
xge_debug_device(XGE_TRACE, "PCI info: mode %d", *pci_mode);
if (hldev->config.pci_freq_mherz ==
XGE_HAL_DEFAULT_USE_HARDCODE) {
/*
* There is no way to detect BUS frequency on Xena,
* so, in case of automatic configuration we hopelessly
* assume 133MHZ.
*/
hldev->config.pci_freq_mherz =
XGE_HAL_PCI_BUS_FREQUENCY_133MHZ;
}
} else if (card_id == XGE_HAL_CARD_TITAN) {
*bus_width = XGE_HAL_PCI_BUS_WIDTH_64BIT;
*bus_frequency = XGE_HAL_PCI_BUS_FREQUENCY_250MHZ;
if (hldev->config.pci_freq_mherz ==
XGE_HAL_DEFAULT_USE_HARDCODE) {
hldev->config.pci_freq_mherz = *bus_frequency;
}
} else{
rc_status = XGE_HAL_ERR_BAD_DEVICE_ID;
xge_debug_device(XGE_ERR, "invalid device id %d", card_id);
}
#endif
return rc_status;
}
/*
* __hal_device_handle_link_up_ind
* @hldev: HAL device handle.
*
* Link up indication handler. The function is invoked by HAL when
* Xframe indicates that the link is up for programmable amount of time.
*/
static int
__hal_device_handle_link_up_ind(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
/*
* If the previous link state is not down, return.
*/
if (hldev->link_state == XGE_HAL_LINK_UP) {
#ifdef XGE_HAL_PROCESS_LINK_INT_IN_ISR
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC){
val64 = xge_os_pio_mem_read64(
hldev->pdev, hldev->regh0,
&bar0->misc_int_mask);
val64 |= XGE_HAL_MISC_INT_REG_LINK_UP_INT;
val64 &= ~XGE_HAL_MISC_INT_REG_LINK_DOWN_INT;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->misc_int_mask);
}
#endif
xge_debug_device(XGE_TRACE,
"link up indication while link is up, ignoring..");
return 0;
}
/* Now re-enable it as due to noise, hardware turned it off */
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_control);
val64 |= XGE_HAL_ADAPTER_CNTL_EN;
val64 = val64 & (~XGE_HAL_ADAPTER_ECC_EN); /* ECC enable */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->adapter_control);
/* Turn on the Laser */
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_control);
val64 = val64|(XGE_HAL_ADAPTER_EOI_TX_ON |
XGE_HAL_ADAPTER_LED_ON);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->adapter_control);
#ifdef XGE_HAL_PROCESS_LINK_INT_IN_ISR
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_status);
if (val64 & (XGE_HAL_ADAPTER_STATUS_RMAC_REMOTE_FAULT |
XGE_HAL_ADAPTER_STATUS_RMAC_LOCAL_FAULT)) {
xge_debug_device(XGE_TRACE, "%s",
"fail to transition link to up...");
return 0;
}
else {
/*
* Mask the Link Up interrupt and unmask the Link Down
* interrupt.
*/
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->misc_int_mask);
val64 |= XGE_HAL_MISC_INT_REG_LINK_UP_INT;
val64 &= ~XGE_HAL_MISC_INT_REG_LINK_DOWN_INT;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->misc_int_mask);
xge_debug_device(XGE_TRACE, "calling link up..");
hldev->link_state = XGE_HAL_LINK_UP;
/* notify ULD */
if (g_xge_hal_driver->uld_callbacks.link_up) {
g_xge_hal_driver->uld_callbacks.link_up(
hldev->upper_layer_info);
}
return 1;
}
}
#endif
xge_os_mdelay(1);
if (__hal_device_register_poll(hldev, &bar0->adapter_status, 0,
(XGE_HAL_ADAPTER_STATUS_RMAC_REMOTE_FAULT |
XGE_HAL_ADAPTER_STATUS_RMAC_LOCAL_FAULT),
XGE_HAL_DEVICE_FAULT_WAIT_MAX_MILLIS) == XGE_HAL_OK) {
/* notify ULD */
(void) xge_queue_produce_context(hldev->queueh,
XGE_HAL_EVENT_LINK_IS_UP,
hldev);
/* link is up after been enabled */
return 1;
} else {
xge_debug_device(XGE_TRACE, "%s",
"fail to transition link to up...");
return 0;
}
}
/*
* __hal_device_handle_link_down_ind
* @hldev: HAL device handle.
*
* Link down indication handler. The function is invoked by HAL when
* Xframe indicates that the link is down.
*/
static int
__hal_device_handle_link_down_ind(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
/*
* If the previous link state is not up, return.
*/
if (hldev->link_state == XGE_HAL_LINK_DOWN) {
#ifdef XGE_HAL_PROCESS_LINK_INT_IN_ISR
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC){
val64 = xge_os_pio_mem_read64(
hldev->pdev, hldev->regh0,
&bar0->misc_int_mask);
val64 |= XGE_HAL_MISC_INT_REG_LINK_DOWN_INT;
val64 &= ~XGE_HAL_MISC_INT_REG_LINK_UP_INT;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->misc_int_mask);
}
#endif
xge_debug_device(XGE_TRACE,
"link down indication while link is down, ignoring..");
return 0;
}
xge_os_mdelay(1);
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_control);
/* try to debounce the link only if the adapter is enabled. */
if (val64 & XGE_HAL_ADAPTER_CNTL_EN) {
if (__hal_device_register_poll(hldev, &bar0->adapter_status, 0,
(XGE_HAL_ADAPTER_STATUS_RMAC_REMOTE_FAULT |
XGE_HAL_ADAPTER_STATUS_RMAC_LOCAL_FAULT),
XGE_HAL_DEVICE_FAULT_WAIT_MAX_MILLIS) == XGE_HAL_OK) {
xge_debug_device(XGE_TRACE,
"link is actually up (possible noisy link?), ignoring.");
return(0);
}
}
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_control);
/* turn off LED */
val64 = val64 & (~XGE_HAL_ADAPTER_LED_ON);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->adapter_control);
#ifdef XGE_HAL_PROCESS_LINK_INT_IN_ISR
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
/*
* Mask the Link Down interrupt and unmask the Link up
* interrupt
*/
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->misc_int_mask);
val64 |= XGE_HAL_MISC_INT_REG_LINK_DOWN_INT;
val64 &= ~XGE_HAL_MISC_INT_REG_LINK_UP_INT;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->misc_int_mask);
/* link is down */
xge_debug_device(XGE_TRACE, "calling link down..");
hldev->link_state = XGE_HAL_LINK_DOWN;
/* notify ULD */
if (g_xge_hal_driver->uld_callbacks.link_down) {
g_xge_hal_driver->uld_callbacks.link_down(
hldev->upper_layer_info);
}
return 1;
}
#endif
/* notify ULD */
(void) xge_queue_produce_context(hldev->queueh,
XGE_HAL_EVENT_LINK_IS_DOWN,
hldev);
/* link is down */
return 1;
}
/*
* __hal_device_handle_link_state_change
* @hldev: HAL device handle.
*
* Link state change handler. The function is invoked by HAL when
* Xframe indicates link state change condition. The code here makes sure to
* 1) ignore redundant state change indications;
* 2) execute link-up sequence, and handle the failure to bring the link up;
* 3) generate XGE_HAL_LINK_UP/DOWN event for the subsequent handling by
* upper-layer driver (ULD).
*/
static int
__hal_device_handle_link_state_change(xge_hal_device_t *hldev)
{
u64 hw_status;
int hw_link_state;
int retcode;
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
int i = 0;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_control);
/* If the adapter is not enabled but the hal thinks we are in the up
* state then transition to the down state.
*/
if ( !(val64 & XGE_HAL_ADAPTER_CNTL_EN) &&
(hldev->link_state == XGE_HAL_LINK_UP) ) {
return(__hal_device_handle_link_down_ind(hldev));
}
do {
xge_os_mdelay(1);
(void) xge_hal_device_status(hldev, &hw_status);
hw_link_state = (hw_status &
(XGE_HAL_ADAPTER_STATUS_RMAC_REMOTE_FAULT |
XGE_HAL_ADAPTER_STATUS_RMAC_LOCAL_FAULT)) ?
XGE_HAL_LINK_DOWN : XGE_HAL_LINK_UP;
/* check if the current link state is still considered
* to be changed. This way we will make sure that this is
* not a noise which needs to be filtered out */
if (hldev->link_state == hw_link_state)
break;
} while (i++ < hldev->config.link_valid_cnt);
/* If the current link state is same as previous, just return */
if (hldev->link_state == hw_link_state)
retcode = 0;
/* detected state change */
else if (hw_link_state == XGE_HAL_LINK_UP)
retcode = __hal_device_handle_link_up_ind(hldev);
else
retcode = __hal_device_handle_link_down_ind(hldev);
return retcode;
}
/*
*
*/
static void
__hal_device_handle_serr(xge_hal_device_t *hldev, char *reg, u64 value)
{
hldev->stats.sw_dev_err_stats.serr_cnt++;
if (hldev->config.dump_on_serr) {
#ifdef XGE_HAL_USE_MGMT_AUX
(void) xge_hal_aux_device_dump(hldev);
#endif
}
(void) xge_queue_produce(hldev->queueh, XGE_HAL_EVENT_SERR, hldev,
1, sizeof(u64), (void *)&value);
xge_debug_device(XGE_ERR, "%s: read "XGE_OS_LLXFMT, reg,
(unsigned long long) value);
}
/*
*
*/
static void
__hal_device_handle_eccerr(xge_hal_device_t *hldev, char *reg, u64 value)
{
if (hldev->config.dump_on_eccerr) {
#ifdef XGE_HAL_USE_MGMT_AUX
(void) xge_hal_aux_device_dump(hldev);
#endif
}
/* Herc smart enough to recover on its own! */
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA) {
(void) xge_queue_produce(hldev->queueh,
XGE_HAL_EVENT_ECCERR, hldev,
1, sizeof(u64), (void *)&value);
}
xge_debug_device(XGE_ERR, "%s: read "XGE_OS_LLXFMT, reg,
(unsigned long long) value);
}
/*
*
*/
static void
__hal_device_handle_parityerr(xge_hal_device_t *hldev, char *reg, u64 value)
{
if (hldev->config.dump_on_parityerr) {
#ifdef XGE_HAL_USE_MGMT_AUX
(void) xge_hal_aux_device_dump(hldev);
#endif
}
(void) xge_queue_produce_context(hldev->queueh,
XGE_HAL_EVENT_PARITYERR, hldev);
xge_debug_device(XGE_ERR, "%s: read "XGE_OS_LLXFMT, reg,
(unsigned long long) value);
}
/*
*
*/
static void
__hal_device_handle_targetabort(xge_hal_device_t *hldev)
{
(void) xge_queue_produce_context(hldev->queueh,
XGE_HAL_EVENT_TARGETABORT, hldev);
}
/*
* __hal_device_hw_initialize
* @hldev: HAL device handle.
*
* Initialize Xframe hardware.
*/
static xge_hal_status_e
__hal_device_hw_initialize(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
xge_hal_status_e status;
u64 val64;
/* Set proper endian settings and verify the same by reading the PIF
* Feed-back register. */
status = __hal_device_set_swapper(hldev);
if (status != XGE_HAL_OK) {
return status;
}
/* update the pci mode, frequency, and width */
if (__hal_device_pci_info_get(hldev, &hldev->pci_mode,
&hldev->bus_frequency, &hldev->bus_width) != XGE_HAL_OK){
hldev->pci_mode = XGE_HAL_PCI_INVALID_MODE;
hldev->bus_frequency = XGE_HAL_PCI_BUS_FREQUENCY_UNKNOWN;
hldev->bus_width = XGE_HAL_PCI_BUS_WIDTH_UNKNOWN;
/*
* FIXME: this cannot happen.
* But if it happens we cannot continue just like that
*/
xge_debug_device(XGE_ERR, "unable to get pci info");
}
if ((hldev->pci_mode == XGE_HAL_PCI_33MHZ_MODE) ||
(hldev->pci_mode == XGE_HAL_PCI_66MHZ_MODE) ||
(hldev->pci_mode == XGE_HAL_PCI_BASIC_MODE)) {
/* PCI optimization: set TxReqTimeOut
* register (0x800+0x120) to 0x1ff or
* something close to this.
* Note: not to be used for PCI-X! */
val64 = XGE_HAL_TXREQTO_VAL(0x1FF);
val64 |= XGE_HAL_TXREQTO_EN;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->txreqtimeout);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, 0ULL,
&bar0->read_retry_delay);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, 0ULL,
&bar0->write_retry_delay);
xge_debug_device(XGE_TRACE, "%s", "optimizing for PCI mode");
}
if (hldev->bus_frequency == XGE_HAL_PCI_BUS_FREQUENCY_266MHZ ||
hldev->bus_frequency == XGE_HAL_PCI_BUS_FREQUENCY_250MHZ) {
/* Optimizing for PCI-X 266/250 */
val64 = XGE_HAL_TXREQTO_VAL(0x7F);
val64 |= XGE_HAL_TXREQTO_EN;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->txreqtimeout);
xge_debug_device(XGE_TRACE, "%s", "optimizing for PCI-X 266/250 modes");
}
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, 0x4000000000000ULL,
&bar0->read_retry_delay);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, 0x4000000000000ULL,
&bar0->write_retry_delay);
}
/* added this to set the no of bytes used to update lso_bytes_sent
returned TxD0 */
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->pic_control_2);
val64 &= ~XGE_HAL_TXD_WRITE_BC(0x2);
val64 |= XGE_HAL_TXD_WRITE_BC(0x4);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->pic_control_2);
/* added this to clear the EOI_RESET field while leaving XGXS_RESET
* in reset, then a 1-second delay */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_SW_RESET_XGXS, &bar0->sw_reset);
xge_os_mdelay(1000);
/* Clear the XGXS_RESET field of the SW_RESET register in order to
* release the XGXS from reset. Its reset value is 0xA5; write 0x00
* to activate the XGXS. The core requires a minimum 500 us reset.*/
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, 0, &bar0->sw_reset);
(void) xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->sw_reset);
xge_os_mdelay(1);
/* read registers in all blocks */
(void) xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->mac_int_mask);
(void) xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->mc_int_mask);
(void) xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->xgxs_int_mask);
/* set default MTU and steer based on length*/
__hal_ring_mtu_set(hldev, hldev->config.mtu+22); // Alway set 22 bytes extra for steering to work
if (hldev->config.mac.rmac_bcast_en) {
xge_hal_device_bcast_enable(hldev);
} else {
xge_hal_device_bcast_disable(hldev);
}
#ifndef XGE_HAL_HERC_EMULATION
__hal_device_xaui_configure(hldev);
#endif
__hal_device_mac_link_util_set(hldev);
__hal_device_mac_link_util_set(hldev);
/*
* Keep its PCI REQ# line asserted during a write
* transaction up to the end of the transaction
*/
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->misc_control);
val64 |= XGE_HAL_MISC_CONTROL_EXT_REQ_EN;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->misc_control);
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->misc_control);
val64 |= XGE_HAL_MISC_CONTROL_LINK_FAULT;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->misc_control);
}
/*
* bimodal interrupts is when all Rx traffic interrupts
* will go to TTI, so we need to adjust RTI settings and
* use adaptive TTI timer. We need to make sure RTI is
* properly configured to sane value which will not
* distrupt bimodal behavior.
*/
if (hldev->config.bimodal_interrupts) {
int i;
/* force polling_cnt to be "0", otherwise
* IRQ workload statistics will be screwed. This could
* be worked out in TXPIC handler later. */
hldev->config.isr_polling_cnt = 0;
hldev->config.sched_timer_us = 10000;
/* disable all TTI < 56 */
for (i=0; i<XGE_HAL_MAX_FIFO_NUM; i++) {
int j;
if (!hldev->config.fifo.queue[i].configured)
continue;
for (j=0; j<XGE_HAL_MAX_FIFO_TTI_NUM; j++) {
if (hldev->config.fifo.queue[i].tti[j].enabled)
hldev->config.fifo.queue[i].tti[j].enabled = 0;
}
}
/* now configure bimodal interrupts */
__hal_device_bimodal_configure(hldev);
}
status = __hal_device_tti_configure(hldev, 0);
if (status != XGE_HAL_OK)
return status;
status = __hal_device_rti_configure(hldev, 0);
if (status != XGE_HAL_OK)
return status;
status = __hal_device_rth_it_configure(hldev);
if (status != XGE_HAL_OK)
return status;
status = __hal_device_rth_spdm_configure(hldev);
if (status != XGE_HAL_OK)
return status;
status = __hal_device_rts_mac_configure(hldev);
if (status != XGE_HAL_OK) {
xge_debug_device(XGE_ERR, "__hal_device_rts_mac_configure Failed ");
return status;
}
status = __hal_device_rts_port_configure(hldev);
if (status != XGE_HAL_OK) {
xge_debug_device(XGE_ERR, "__hal_device_rts_port_configure Failed ");
return status;
}
status = __hal_device_rts_qos_configure(hldev);
if (status != XGE_HAL_OK) {
xge_debug_device(XGE_ERR, "__hal_device_rts_qos_configure Failed ");
return status;
}
__hal_device_pause_frames_configure(hldev);
__hal_device_rmac_padding_configure(hldev);
__hal_device_shared_splits_configure(hldev);
/* make sure all interrupts going to be disabled at the moment */
__hal_device_intr_mgmt(hldev, XGE_HAL_ALL_INTRS, 0);
/* SXE-008 Transmit DMA arbitration issue */
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA &&
hldev->revision < 4) {
xge_os_pio_mem_write64(hldev->pdev,hldev->regh0,
XGE_HAL_ADAPTER_PCC_ENABLE_FOUR,
&bar0->pcc_enable);
}
#if 0 // Removing temporarily as FreeBSD is seeing lower performance
// attributable to this fix.
/* SXE-2-010 */
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
/* Turn off the ECC error reporting for RLDRAM interface */
if ((status = xge_hal_fix_rldram_ecc_error(hldev)) != XGE_HAL_OK)
return status;
}
#endif
__hal_fifo_hw_initialize(hldev);
__hal_ring_hw_initialize(hldev);
if (__hal_device_wait_quiescent(hldev, &val64)) {
return XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
}
if (__hal_device_register_poll(hldev, &bar0->adapter_status, 1,
XGE_HAL_ADAPTER_STATUS_RC_PRC_QUIESCENT,
XGE_HAL_DEVICE_QUIESCENT_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
xge_debug_device(XGE_TRACE, "%s", "PRC is not QUIESCENT!");
return XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
}
xge_debug_device(XGE_TRACE, "device 0x"XGE_OS_LLXFMT" is quiescent",
(unsigned long long)(ulong_t)hldev);
if (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX ||
hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSI) {
/*
* If MSI is enabled, ensure that One Shot for MSI in PCI_CTRL
* is disabled.
*/
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->pic_control);
val64 &= ~(XGE_HAL_PIC_CNTL_ONE_SHOT_TINT);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->pic_control);
}
hldev->hw_is_initialized = 1;
hldev->terminating = 0;
return XGE_HAL_OK;
}
/*
* __hal_device_reset - Reset device only.
* @hldev: HAL device handle.
*
* Reset the device, and subsequently restore
* the previously saved PCI configuration space.
*/
#define XGE_HAL_MAX_PCI_CONFIG_SPACE_REINIT 50
static xge_hal_status_e
__hal_device_reset(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
int i, j, swap_done, pcisize = 0;
u64 val64, rawval = 0ULL;
if (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX) {
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
if ( hldev->bar2 ) {
u64 *msix_vetor_table = (u64 *)hldev->bar2;
// 2 64bit words for each entry
for (i = 0; i < XGE_HAL_MAX_MSIX_MESSAGES * 2;
i++) {
hldev->msix_vector_table[i] =
xge_os_pio_mem_read64(hldev->pdev,
hldev->regh2, &msix_vetor_table[i]);
}
}
}
}
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->pif_rd_swapper_fb);
swap_done = (val64 == XGE_HAL_IF_RD_SWAPPER_FB);
if (swap_done) {
__hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0,
(u32)(XGE_HAL_SW_RESET_ALL>>32), (char *)&bar0->sw_reset);
} else {
u32 val = (u32)(XGE_HAL_SW_RESET_ALL >> 32);
#if defined(XGE_OS_HOST_LITTLE_ENDIAN) || defined(XGE_OS_PIO_LITTLE_ENDIAN)
/* swap it */
val = (((val & (u32)0x000000ffUL) << 24) |
((val & (u32)0x0000ff00UL) << 8) |
((val & (u32)0x00ff0000UL) >> 8) |
((val & (u32)0xff000000UL) >> 24));
#endif
xge_os_pio_mem_write32(hldev->pdev, hldev->regh0, val,
&bar0->sw_reset);
}
pcisize = (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)?
XGE_HAL_PCISIZE_HERC : XGE_HAL_PCISIZE_XENA;
xge_os_mdelay(20); /* Wait for 20 ms after reset */
{
/* Poll for no more than 1 second */
for (i = 0; i < XGE_HAL_MAX_PCI_CONFIG_SPACE_REINIT; i++)
{
for (j = 0; j < pcisize; j++) {
xge_os_pci_write32(hldev->pdev, hldev->cfgh, j * 4,
*((u32*)&hldev->pci_config_space + j));
}
xge_os_pci_read16(hldev->pdev,hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, device_id),
&hldev->device_id);
if (xge_hal_device_check_id(hldev) != XGE_HAL_CARD_UNKNOWN)
break;
xge_os_mdelay(20);
}
}
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_UNKNOWN)
{
xge_debug_device(XGE_ERR, "device reset failed");
return XGE_HAL_ERR_RESET_FAILED;
}
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
int cnt = 0;
rawval = XGE_HAL_SW_RESET_RAW_VAL_HERC;
pcisize = XGE_HAL_PCISIZE_HERC;
xge_os_mdelay(1);
do {
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->sw_reset);
if (val64 != rawval) {
break;
}
cnt++;
xge_os_mdelay(1); /* Wait for 1ms before retry */
} while(cnt < 20);
} else if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA) {
rawval = XGE_HAL_SW_RESET_RAW_VAL_XENA;
pcisize = XGE_HAL_PCISIZE_XENA;
xge_os_mdelay(XGE_HAL_DEVICE_RESET_WAIT_MAX_MILLIS);
}
/* Restore MSI-X vector table */
if (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX) {
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
if ( hldev->bar2 ) {
/*
* 94: MSIXTable 00000004 ( BIR:4 Offset:0x0 )
* 98: PBATable 00000404 ( BIR:4 Offset:0x400 )
*/
u64 *msix_vetor_table = (u64 *)hldev->bar2;
/* 2 64bit words for each entry */
for (i = 0; i < XGE_HAL_MAX_MSIX_MESSAGES * 2;
i++) {
xge_os_pio_mem_write64(hldev->pdev,
hldev->regh2,
hldev->msix_vector_table[i],
&msix_vetor_table[i]);
}
}
}
}
hldev->link_state = XGE_HAL_LINK_DOWN;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->sw_reset);
if (val64 != rawval) {
xge_debug_device(XGE_ERR, "device has not been reset "
"got 0x"XGE_OS_LLXFMT", expected 0x"XGE_OS_LLXFMT,
(unsigned long long)val64, (unsigned long long)rawval);
return XGE_HAL_ERR_RESET_FAILED;
}
hldev->hw_is_initialized = 0;
return XGE_HAL_OK;
}
/*
* __hal_device_poll - General private routine to poll the device.
* @hldev: HAL device handle.
*
* Returns: one of the xge_hal_status_e{} enumerated types.
* XGE_HAL_OK - for success.
* XGE_HAL_ERR_CRITICAL - when encounters critical error.
*/
static xge_hal_status_e
__hal_device_poll(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0;
u64 err_reg;
bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
/* Handling SERR errors by forcing a H/W reset. */
err_reg = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->serr_source);
if (err_reg & XGE_HAL_SERR_SOURCE_ANY) {
__hal_device_handle_serr(hldev, "serr_source", err_reg);
return XGE_HAL_ERR_CRITICAL;
}
err_reg = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->misc_int_reg);
if (err_reg & XGE_HAL_MISC_INT_REG_DP_ERR_INT) {
hldev->stats.sw_dev_err_stats.parity_err_cnt++;
__hal_device_handle_parityerr(hldev, "misc_int_reg", err_reg);
return XGE_HAL_ERR_CRITICAL;
}
#ifdef XGE_HAL_PROCESS_LINK_INT_IN_ISR
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA)
#endif
{
/* Handling link status change error Intr */
err_reg = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->mac_rmac_err_reg);
if (__hal_device_handle_link_state_change(hldev))
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
err_reg, &bar0->mac_rmac_err_reg);
}
if (hldev->inject_serr != 0) {
err_reg = hldev->inject_serr;
hldev->inject_serr = 0;
__hal_device_handle_serr(hldev, "inject_serr", err_reg);
return XGE_HAL_ERR_CRITICAL;
}
if (hldev->inject_ecc != 0) {
err_reg = hldev->inject_ecc;
hldev->inject_ecc = 0;
hldev->stats.sw_dev_err_stats.ecc_err_cnt++;
__hal_device_handle_eccerr(hldev, "inject_ecc", err_reg);
return XGE_HAL_ERR_CRITICAL;
}
if (hldev->inject_bad_tcode != 0) {
u8 t_code = hldev->inject_bad_tcode;
xge_hal_channel_t channel;
xge_hal_fifo_txd_t txd;
xge_hal_ring_rxd_1_t rxd;
channel.devh = hldev;
if (hldev->inject_bad_tcode_for_chan_type ==
XGE_HAL_CHANNEL_TYPE_FIFO) {
channel.type = XGE_HAL_CHANNEL_TYPE_FIFO;
} else {
channel.type = XGE_HAL_CHANNEL_TYPE_RING;
}
hldev->inject_bad_tcode = 0;
if (channel.type == XGE_HAL_CHANNEL_TYPE_FIFO)
return xge_hal_device_handle_tcode(&channel, &txd,
t_code);
else
return xge_hal_device_handle_tcode(&channel, &rxd,
t_code);
}
return XGE_HAL_OK;
}
/*
* __hal_verify_pcc_idle - Verify All Enbled PCC are IDLE or not
* @hldev: HAL device handle.
* @adp_status: Adapter Status value
* Usage: See xge_hal_device_enable{}.
*/
xge_hal_status_e
__hal_verify_pcc_idle(xge_hal_device_t *hldev, u64 adp_status)
{
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA &&
hldev->revision < 4) {
/*
* For Xena 1,2,3 we enable only 4 PCCs Due to
* SXE-008 (Transmit DMA arbitration issue)
*/
if ((adp_status & XGE_HAL_ADAPTER_STATUS_RMAC_PCC_4_IDLE)
!= XGE_HAL_ADAPTER_STATUS_RMAC_PCC_4_IDLE) {
xge_debug_device(XGE_TRACE, "%s",
"PCC is not IDLE after adapter enabled!");
return XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
}
} else {
if ((adp_status & XGE_HAL_ADAPTER_STATUS_RMAC_PCC_IDLE) !=
XGE_HAL_ADAPTER_STATUS_RMAC_PCC_IDLE) {
xge_debug_device(XGE_TRACE, "%s",
"PCC is not IDLE after adapter enabled!");
return XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
}
}
return XGE_HAL_OK;
}
static void
__hal_update_bimodal(xge_hal_device_t *hldev, int ring_no)
{
int tval, d, iwl_avg, len_avg, bytes_avg, bytes_hist, d_hist;
int iwl_rxcnt, iwl_txcnt, iwl_txavg, len_rxavg, iwl_rxavg, len_txavg;
int iwl_cnt, i;
#define _HIST_SIZE 50 /* 0.5 sec history */
#define _HIST_ADJ_TIMER 1
#define _STEP 2
static int bytes_avg_history[_HIST_SIZE] = {0};
static int d_avg_history[_HIST_SIZE] = {0};
static int history_idx = 0;
static int pstep = 1;
static int hist_adj_timer = 0;
/*
* tval - current value of this bimodal timer
*/
tval = hldev->bimodal_tti[ring_no].timer_val_us;
/*
* d - how many interrupts we were getting since last
* bimodal timer tick.
*/
d = hldev->stats.sw_dev_info_stats.tx_traffic_intr_cnt -
hldev->bimodal_intr_cnt;
/* advance bimodal interrupt counter */
hldev->bimodal_intr_cnt =
hldev->stats.sw_dev_info_stats.tx_traffic_intr_cnt;
/*
* iwl_cnt - how many interrupts we've got since last
* bimodal timer tick.
*/
iwl_rxcnt = (hldev->irq_workload_rxcnt[ring_no] ?
hldev->irq_workload_rxcnt[ring_no] : 1);
iwl_txcnt = (hldev->irq_workload_txcnt[ring_no] ?
hldev->irq_workload_txcnt[ring_no] : 1);
iwl_cnt = iwl_rxcnt + iwl_txcnt;
/*
* we need to take hldev->config.isr_polling_cnt into account
* but for some reason this line causing GCC to produce wrong
* code on Solaris. As of now, if bimodal_interrupts is configured
* hldev->config.isr_polling_cnt is forced to be "0".
*
* iwl_cnt = iwl_cnt / (hldev->config.isr_polling_cnt + 1); */
/*
* iwl_avg - how many RXDs on avarage been processed since
* last bimodal timer tick. This indirectly includes
* CPU utilizations.
*/
iwl_rxavg = hldev->irq_workload_rxd[ring_no] / iwl_rxcnt;
iwl_txavg = hldev->irq_workload_txd[ring_no] / iwl_txcnt;
iwl_avg = iwl_rxavg + iwl_txavg;
iwl_avg = iwl_avg == 0 ? 1 : iwl_avg;
/*
* len_avg - how many bytes on avarage been processed since
* last bimodal timer tick. i.e. avarage frame size.
*/
len_rxavg = 1 + hldev->irq_workload_rxlen[ring_no] /
(hldev->irq_workload_rxd[ring_no] ?
hldev->irq_workload_rxd[ring_no] : 1);
len_txavg = 1 + hldev->irq_workload_txlen[ring_no] /
(hldev->irq_workload_txd[ring_no] ?
hldev->irq_workload_txd[ring_no] : 1);
len_avg = len_rxavg + len_txavg;
if (len_avg < 60)
len_avg = 60;
/* align on low boundary */
if ((tval -_STEP) < hldev->config.bimodal_timer_lo_us)
tval = hldev->config.bimodal_timer_lo_us;
/* reset faster */
if (iwl_avg == 1) {
tval = hldev->config.bimodal_timer_lo_us;
/* reset history */
for (i = 0; i < _HIST_SIZE; i++)
bytes_avg_history[i] = d_avg_history[i] = 0;
history_idx = 0;
pstep = 1;
hist_adj_timer = 0;
}
/* always try to ajust timer to the best throughput value */
bytes_avg = iwl_avg * len_avg;
history_idx %= _HIST_SIZE;
bytes_avg_history[history_idx] = bytes_avg;
d_avg_history[history_idx] = d;
history_idx++;
d_hist = bytes_hist = 0;
for (i = 0; i < _HIST_SIZE; i++) {
/* do not re-configure until history is gathered */
if (!bytes_avg_history[i]) {
tval = hldev->config.bimodal_timer_lo_us;
goto _end;
}
bytes_hist += bytes_avg_history[i];
d_hist += d_avg_history[i];
}
bytes_hist /= _HIST_SIZE;
d_hist /= _HIST_SIZE;
// xge_os_printf("d %d iwl_avg %d len_avg %d:%d:%d tval %d avg %d hist %d pstep %d",
// d, iwl_avg, len_txavg, len_rxavg, len_avg, tval, d*bytes_avg,
// d_hist*bytes_hist, pstep);
/* make an adaptive step */
if (d * bytes_avg < d_hist * bytes_hist && hist_adj_timer++ > _HIST_ADJ_TIMER) {
pstep = !pstep;
hist_adj_timer = 0;
}
if (pstep &&
(tval + _STEP) <= hldev->config.bimodal_timer_hi_us) {
tval += _STEP;
hldev->stats.sw_dev_info_stats.bimodal_hi_adjust_cnt++;
} else if ((tval - _STEP) >= hldev->config.bimodal_timer_lo_us) {
tval -= _STEP;
hldev->stats.sw_dev_info_stats.bimodal_lo_adjust_cnt++;
}
/* enable TTI range A for better latencies */
hldev->bimodal_urange_a_en = 0;
if (tval <= hldev->config.bimodal_timer_lo_us && iwl_avg > 2)
hldev->bimodal_urange_a_en = 1;
_end:
/* reset workload statistics counters */
hldev->irq_workload_rxcnt[ring_no] = 0;
hldev->irq_workload_rxd[ring_no] = 0;
hldev->irq_workload_rxlen[ring_no] = 0;
hldev->irq_workload_txcnt[ring_no] = 0;
hldev->irq_workload_txd[ring_no] = 0;
hldev->irq_workload_txlen[ring_no] = 0;
/* reconfigure TTI56 + ring_no with new timer value */
hldev->bimodal_timer_val_us = tval;
(void) __hal_device_rti_configure(hldev, 1);
}
static void
__hal_update_rxufca(xge_hal_device_t *hldev, int ring_no)
{
int ufc, ic, i;
ufc = hldev->config.ring.queue[ring_no].rti.ufc_a;
ic = hldev->stats.sw_dev_info_stats.rx_traffic_intr_cnt;
/* urange_a adaptive coalescing */
if (hldev->rxufca_lbolt > hldev->rxufca_lbolt_time) {
if (ic > hldev->rxufca_intr_thres) {
if (ufc < hldev->config.rxufca_hi_lim) {
ufc += 1;
for (i=0; i<XGE_HAL_MAX_RING_NUM; i++)
hldev->config.ring.queue[i].rti.ufc_a = ufc;
(void) __hal_device_rti_configure(hldev, 1);
hldev->stats.sw_dev_info_stats.
rxufca_hi_adjust_cnt++;
}
hldev->rxufca_intr_thres = ic +
hldev->config.rxufca_intr_thres; /* def: 30 */
} else {
if (ufc > hldev->config.rxufca_lo_lim) {
ufc -= 1;
for (i=0; i<XGE_HAL_MAX_RING_NUM; i++)
hldev->config.ring.queue[i].rti.ufc_a = ufc;
(void) __hal_device_rti_configure(hldev, 1);
hldev->stats.sw_dev_info_stats.
rxufca_lo_adjust_cnt++;
}
}
hldev->rxufca_lbolt_time = hldev->rxufca_lbolt +
hldev->config.rxufca_lbolt_period;
}
hldev->rxufca_lbolt++;
}
/*
* __hal_device_handle_mc - Handle MC interrupt reason
* @hldev: HAL device handle.
* @reason: interrupt reason
*/
xge_hal_status_e
__hal_device_handle_mc(xge_hal_device_t *hldev, u64 reason)
{
xge_hal_pci_bar0_t *isrbar0 =
(xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
u64 val64;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->mc_int_status);
if (!(val64 & XGE_HAL_MC_INT_STATUS_MC_INT))
return XGE_HAL_OK;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->mc_err_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &isrbar0->mc_err_reg);
if (val64 & XGE_HAL_MC_ERR_REG_ETQ_ECC_SG_ERR_L ||
val64 & XGE_HAL_MC_ERR_REG_ETQ_ECC_SG_ERR_U ||
val64 & XGE_HAL_MC_ERR_REG_MIRI_ECC_SG_ERR_0 ||
val64 & XGE_HAL_MC_ERR_REG_MIRI_ECC_SG_ERR_1 ||
(xge_hal_device_check_id(hldev) != XGE_HAL_CARD_XENA &&
(val64 & XGE_HAL_MC_ERR_REG_ITQ_ECC_SG_ERR_L ||
val64 & XGE_HAL_MC_ERR_REG_ITQ_ECC_SG_ERR_U ||
val64 & XGE_HAL_MC_ERR_REG_RLD_ECC_SG_ERR_L ||
val64 & XGE_HAL_MC_ERR_REG_RLD_ECC_SG_ERR_U))) {
hldev->stats.sw_dev_err_stats.single_ecc_err_cnt++;
hldev->stats.sw_dev_err_stats.ecc_err_cnt++;
}
if (val64 & XGE_HAL_MC_ERR_REG_ETQ_ECC_DB_ERR_L ||
val64 & XGE_HAL_MC_ERR_REG_ETQ_ECC_DB_ERR_U ||
val64 & XGE_HAL_MC_ERR_REG_MIRI_ECC_DB_ERR_0 ||
val64 & XGE_HAL_MC_ERR_REG_MIRI_ECC_DB_ERR_1 ||
(xge_hal_device_check_id(hldev) != XGE_HAL_CARD_XENA &&
(val64 & XGE_HAL_MC_ERR_REG_ITQ_ECC_DB_ERR_L ||
val64 & XGE_HAL_MC_ERR_REG_ITQ_ECC_DB_ERR_U ||
val64 & XGE_HAL_MC_ERR_REG_RLD_ECC_DB_ERR_L ||
val64 & XGE_HAL_MC_ERR_REG_RLD_ECC_DB_ERR_U))) {
hldev->stats.sw_dev_err_stats.double_ecc_err_cnt++;
hldev->stats.sw_dev_err_stats.ecc_err_cnt++;
}
if (val64 & XGE_HAL_MC_ERR_REG_SM_ERR) {
hldev->stats.sw_dev_err_stats.sm_err_cnt++;
}
/* those two should result in device reset */
if (val64 & XGE_HAL_MC_ERR_REG_MIRI_ECC_DB_ERR_0 ||
val64 & XGE_HAL_MC_ERR_REG_MIRI_ECC_DB_ERR_1) {
__hal_device_handle_eccerr(hldev, "mc_err_reg", val64);
return XGE_HAL_ERR_CRITICAL;
}
return XGE_HAL_OK;
}
/*
* __hal_device_handle_pic - Handle non-traffic PIC interrupt reason
* @hldev: HAL device handle.
* @reason: interrupt reason
*/
xge_hal_status_e
__hal_device_handle_pic(xge_hal_device_t *hldev, u64 reason)
{
xge_hal_pci_bar0_t *isrbar0 =
(xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
u64 val64;
if (reason & XGE_HAL_PIC_INT_FLSH) {
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->flsh_int_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &isrbar0->flsh_int_reg);
/* FIXME: handle register */
}
if (reason & XGE_HAL_PIC_INT_MDIO) {
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->mdio_int_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &isrbar0->mdio_int_reg);
/* FIXME: handle register */
}
if (reason & XGE_HAL_PIC_INT_IIC) {
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->iic_int_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &isrbar0->iic_int_reg);
/* FIXME: handle register */
}
if (reason & XGE_HAL_PIC_INT_MISC) {
val64 = xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &isrbar0->misc_int_reg);
#ifdef XGE_HAL_PROCESS_LINK_INT_IN_ISR
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
/* Check for Link interrupts. If both Link Up/Down
* bits are set, clear both and check adapter status
*/
if ((val64 & XGE_HAL_MISC_INT_REG_LINK_UP_INT) &&
(val64 & XGE_HAL_MISC_INT_REG_LINK_DOWN_INT)) {
u64 temp64;
xge_debug_device(XGE_TRACE,
"both link up and link down detected "XGE_OS_LLXFMT,
(unsigned long long)val64);
temp64 = (XGE_HAL_MISC_INT_REG_LINK_DOWN_INT |
XGE_HAL_MISC_INT_REG_LINK_UP_INT);
xge_os_pio_mem_write64(hldev->pdev,
hldev->regh0, temp64,
&isrbar0->misc_int_reg);
}
else if (val64 & XGE_HAL_MISC_INT_REG_LINK_UP_INT) {
xge_debug_device(XGE_TRACE,
"link up call request, misc_int "XGE_OS_LLXFMT,
(unsigned long long)val64);
__hal_device_handle_link_up_ind(hldev);
}
else if (val64 & XGE_HAL_MISC_INT_REG_LINK_DOWN_INT){
xge_debug_device(XGE_TRACE,
"link down request, misc_int "XGE_OS_LLXFMT,
(unsigned long long)val64);
__hal_device_handle_link_down_ind(hldev);
}
} else
#endif
{
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &isrbar0->misc_int_reg);
}
}
return XGE_HAL_OK;
}
/*
* __hal_device_handle_txpic - Handle TxPIC interrupt reason
* @hldev: HAL device handle.
* @reason: interrupt reason
*/
xge_hal_status_e
__hal_device_handle_txpic(xge_hal_device_t *hldev, u64 reason)
{
xge_hal_status_e status = XGE_HAL_OK;
xge_hal_pci_bar0_t *isrbar0 =
(xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
volatile u64 val64;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->pic_int_status);
if ( val64 & (XGE_HAL_PIC_INT_FLSH |
XGE_HAL_PIC_INT_MDIO |
XGE_HAL_PIC_INT_IIC |
XGE_HAL_PIC_INT_MISC) ) {
status = __hal_device_handle_pic(hldev, val64);
xge_os_wmb();
}
if (!(val64 & XGE_HAL_PIC_INT_TX))
return status;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->txpic_int_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &isrbar0->txpic_int_reg);
xge_os_wmb();
if (val64 & XGE_HAL_TXPIC_INT_SCHED_INTR) {
int i;
if (g_xge_hal_driver->uld_callbacks.sched_timer != NULL)
g_xge_hal_driver->uld_callbacks.sched_timer(
hldev, hldev->upper_layer_info);
/*
* This feature implements adaptive receive interrupt
* coalecing. It is disabled by default. To enable it
* set hldev->config.rxufca_lo_lim to be not equal to
* hldev->config.rxufca_hi_lim.
*
* We are using HW timer for this feature, so
* use needs to configure hldev->config.rxufca_lbolt_period
* which is essentially a time slice of timer.
*
* For those who familiar with Linux, lbolt means jiffies
* of this timer. I.e. timer tick.
*/
if (hldev->config.rxufca_lo_lim !=
hldev->config.rxufca_hi_lim &&
hldev->config.rxufca_lo_lim != 0) {
for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++) {
if (!hldev->config.ring.queue[i].configured)
continue;
if (hldev->config.ring.queue[i].rti.urange_a)
__hal_update_rxufca(hldev, i);
}
}
/*
* This feature implements adaptive TTI timer re-calculation
* based on host utilization, number of interrupt processed,
* number of RXD per tick and avarage length of packets per
* tick.
*/
if (hldev->config.bimodal_interrupts) {
for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++) {
if (!hldev->config.ring.queue[i].configured)
continue;
if (hldev->bimodal_tti[i].enabled)
__hal_update_bimodal(hldev, i);
}
}
}
return XGE_HAL_OK;
}
/*
* __hal_device_handle_txdma - Handle TxDMA interrupt reason
* @hldev: HAL device handle.
* @reason: interrupt reason
*/
xge_hal_status_e
__hal_device_handle_txdma(xge_hal_device_t *hldev, u64 reason)
{
xge_hal_pci_bar0_t *isrbar0 =
(xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
u64 val64, temp64, err;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->txdma_int_status);
if (val64 & XGE_HAL_TXDMA_PFC_INT) {
err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->pfc_err_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
err, &isrbar0->pfc_err_reg);
hldev->stats.sw_dev_info_stats.pfc_err_cnt++;
temp64 = XGE_HAL_PFC_ECC_DB_ERR|XGE_HAL_PFC_SM_ERR_ALARM
|XGE_HAL_PFC_MISC_0_ERR|XGE_HAL_PFC_MISC_1_ERR
|XGE_HAL_PFC_PCIX_ERR;
if (val64 & temp64)
goto reset;
}
if (val64 & XGE_HAL_TXDMA_TDA_INT) {
err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->tda_err_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
err, &isrbar0->tda_err_reg);
hldev->stats.sw_dev_info_stats.tda_err_cnt++;
temp64 = XGE_HAL_TDA_Fn_ECC_DB_ERR|XGE_HAL_TDA_SM0_ERR_ALARM
|XGE_HAL_TDA_SM1_ERR_ALARM;
if (val64 & temp64)
goto reset;
}
if (val64 & XGE_HAL_TXDMA_PCC_INT) {
err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->pcc_err_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
err, &isrbar0->pcc_err_reg);
hldev->stats.sw_dev_info_stats.pcc_err_cnt++;
temp64 = XGE_HAL_PCC_FB_ECC_DB_ERR|XGE_HAL_PCC_TXB_ECC_DB_ERR
|XGE_HAL_PCC_SM_ERR_ALARM|XGE_HAL_PCC_WR_ERR_ALARM
|XGE_HAL_PCC_N_SERR|XGE_HAL_PCC_6_COF_OV_ERR
|XGE_HAL_PCC_7_COF_OV_ERR|XGE_HAL_PCC_6_LSO_OV_ERR
|XGE_HAL_PCC_7_LSO_OV_ERR;
if (val64 & temp64)
goto reset;
}
if (val64 & XGE_HAL_TXDMA_TTI_INT) {
err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->tti_err_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
err, &isrbar0->tti_err_reg);
hldev->stats.sw_dev_info_stats.tti_err_cnt++;
temp64 = XGE_HAL_TTI_SM_ERR_ALARM;
if (val64 & temp64)
goto reset;
}
if (val64 & XGE_HAL_TXDMA_LSO_INT) {
err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->lso_err_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
err, &isrbar0->lso_err_reg);
hldev->stats.sw_dev_info_stats.lso_err_cnt++;
temp64 = XGE_HAL_LSO6_ABORT|XGE_HAL_LSO7_ABORT
|XGE_HAL_LSO6_SM_ERR_ALARM|XGE_HAL_LSO7_SM_ERR_ALARM;
if (val64 & temp64)
goto reset;
}
if (val64 & XGE_HAL_TXDMA_TPA_INT) {
err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->tpa_err_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
err, &isrbar0->tpa_err_reg);
hldev->stats.sw_dev_info_stats.tpa_err_cnt++;
temp64 = XGE_HAL_TPA_SM_ERR_ALARM;
if (val64 & temp64)
goto reset;
}
if (val64 & XGE_HAL_TXDMA_SM_INT) {
err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->sm_err_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
err, &isrbar0->sm_err_reg);
hldev->stats.sw_dev_info_stats.sm_err_cnt++;
temp64 = XGE_HAL_SM_SM_ERR_ALARM;
if (val64 & temp64)
goto reset;
}
return XGE_HAL_OK;
reset : xge_hal_device_reset(hldev);
xge_hal_device_enable(hldev);
xge_hal_device_intr_enable(hldev);
return XGE_HAL_OK;
}
/*
* __hal_device_handle_txmac - Handle TxMAC interrupt reason
* @hldev: HAL device handle.
* @reason: interrupt reason
*/
xge_hal_status_e
__hal_device_handle_txmac(xge_hal_device_t *hldev, u64 reason)
{
xge_hal_pci_bar0_t *isrbar0 =
(xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
u64 val64, temp64;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->mac_int_status);
if (!(val64 & XGE_HAL_MAC_INT_STATUS_TMAC_INT))
return XGE_HAL_OK;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->mac_tmac_err_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &isrbar0->mac_tmac_err_reg);
hldev->stats.sw_dev_info_stats.mac_tmac_err_cnt++;
temp64 = XGE_HAL_TMAC_TX_BUF_OVRN|XGE_HAL_TMAC_TX_SM_ERR;
if (val64 & temp64) {
xge_hal_device_reset(hldev);
xge_hal_device_enable(hldev);
xge_hal_device_intr_enable(hldev);
}
return XGE_HAL_OK;
}
/*
* __hal_device_handle_txxgxs - Handle TxXGXS interrupt reason
* @hldev: HAL device handle.
* @reason: interrupt reason
*/
xge_hal_status_e
__hal_device_handle_txxgxs(xge_hal_device_t *hldev, u64 reason)
{
xge_hal_pci_bar0_t *isrbar0 =
(xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
u64 val64, temp64;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->xgxs_int_status);
if (!(val64 & XGE_HAL_XGXS_INT_STATUS_TXGXS))
return XGE_HAL_OK;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->xgxs_txgxs_err_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &isrbar0->xgxs_txgxs_err_reg);
hldev->stats.sw_dev_info_stats.xgxs_txgxs_err_cnt++;
temp64 = XGE_HAL_TXGXS_ESTORE_UFLOW|XGE_HAL_TXGXS_TX_SM_ERR;
if (val64 & temp64) {
xge_hal_device_reset(hldev);
xge_hal_device_enable(hldev);
xge_hal_device_intr_enable(hldev);
}
return XGE_HAL_OK;
}
/*
* __hal_device_handle_rxpic - Handle RxPIC interrupt reason
* @hldev: HAL device handle.
* @reason: interrupt reason
*/
xge_hal_status_e
__hal_device_handle_rxpic(xge_hal_device_t *hldev, u64 reason)
{
/* FIXME: handle register */
return XGE_HAL_OK;
}
/*
* __hal_device_handle_rxdma - Handle RxDMA interrupt reason
* @hldev: HAL device handle.
* @reason: interrupt reason
*/
xge_hal_status_e
__hal_device_handle_rxdma(xge_hal_device_t *hldev, u64 reason)
{
xge_hal_pci_bar0_t *isrbar0 =
(xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
u64 val64, err, temp64;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->rxdma_int_status);
if (val64 & XGE_HAL_RXDMA_RC_INT) {
err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->rc_err_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
err, &isrbar0->rc_err_reg);
hldev->stats.sw_dev_info_stats.rc_err_cnt++;
temp64 = XGE_HAL_RC_PRCn_ECC_DB_ERR|XGE_HAL_RC_FTC_ECC_DB_ERR
|XGE_HAL_RC_PRCn_SM_ERR_ALARM
|XGE_HAL_RC_FTC_SM_ERR_ALARM;
if (val64 & temp64)
goto reset;
}
if (val64 & XGE_HAL_RXDMA_RPA_INT) {
err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->rpa_err_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
err, &isrbar0->rpa_err_reg);
hldev->stats.sw_dev_info_stats.rpa_err_cnt++;
temp64 = XGE_HAL_RPA_SM_ERR_ALARM|XGE_HAL_RPA_CREDIT_ERR;
if (val64 & temp64)
goto reset;
}
if (val64 & XGE_HAL_RXDMA_RDA_INT) {
err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->rda_err_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
err, &isrbar0->rda_err_reg);
hldev->stats.sw_dev_info_stats.rda_err_cnt++;
temp64 = XGE_HAL_RDA_RXDn_ECC_DB_ERR
|XGE_HAL_RDA_FRM_ECC_DB_N_AERR
|XGE_HAL_RDA_SM1_ERR_ALARM|XGE_HAL_RDA_SM0_ERR_ALARM
|XGE_HAL_RDA_RXD_ECC_DB_SERR;
if (val64 & temp64)
goto reset;
}
if (val64 & XGE_HAL_RXDMA_RTI_INT) {
err = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->rti_err_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
err, &isrbar0->rti_err_reg);
hldev->stats.sw_dev_info_stats.rti_err_cnt++;
temp64 = XGE_HAL_RTI_SM_ERR_ALARM;
if (val64 & temp64)
goto reset;
}
return XGE_HAL_OK;
reset : xge_hal_device_reset(hldev);
xge_hal_device_enable(hldev);
xge_hal_device_intr_enable(hldev);
return XGE_HAL_OK;
}
/*
* __hal_device_handle_rxmac - Handle RxMAC interrupt reason
* @hldev: HAL device handle.
* @reason: interrupt reason
*/
xge_hal_status_e
__hal_device_handle_rxmac(xge_hal_device_t *hldev, u64 reason)
{
xge_hal_pci_bar0_t *isrbar0 =
(xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
u64 val64, temp64;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->mac_int_status);
if (!(val64 & XGE_HAL_MAC_INT_STATUS_RMAC_INT))
return XGE_HAL_OK;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->mac_rmac_err_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &isrbar0->mac_rmac_err_reg);
hldev->stats.sw_dev_info_stats.mac_rmac_err_cnt++;
temp64 = XGE_HAL_RMAC_RX_BUFF_OVRN|XGE_HAL_RMAC_RX_SM_ERR;
if (val64 & temp64) {
xge_hal_device_reset(hldev);
xge_hal_device_enable(hldev);
xge_hal_device_intr_enable(hldev);
}
return XGE_HAL_OK;
}
/*
* __hal_device_handle_rxxgxs - Handle RxXGXS interrupt reason
* @hldev: HAL device handle.
* @reason: interrupt reason
*/
xge_hal_status_e
__hal_device_handle_rxxgxs(xge_hal_device_t *hldev, u64 reason)
{
xge_hal_pci_bar0_t *isrbar0 =
(xge_hal_pci_bar0_t *)(void *)hldev->isrbar0;
u64 val64, temp64;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->xgxs_int_status);
if (!(val64 & XGE_HAL_XGXS_INT_STATUS_RXGXS))
return XGE_HAL_OK;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&isrbar0->xgxs_rxgxs_err_reg);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &isrbar0->xgxs_rxgxs_err_reg);
hldev->stats.sw_dev_info_stats.xgxs_rxgxs_err_cnt++;
temp64 = XGE_HAL_RXGXS_ESTORE_OFLOW|XGE_HAL_RXGXS_RX_SM_ERR;
if (val64 & temp64) {
xge_hal_device_reset(hldev);
xge_hal_device_enable(hldev);
xge_hal_device_intr_enable(hldev);
}
return XGE_HAL_OK;
}
/**
* xge_hal_device_enable - Enable device.
* @hldev: HAL device handle.
*
* Enable the specified device: bring up the link/interface.
* Returns: XGE_HAL_OK - success.
* XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT - Failed to restore the device
* to a "quiescent" state.
*
* See also: xge_hal_status_e{}.
*
* Usage: See ex_open{}.
*/
xge_hal_status_e
xge_hal_device_enable(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
u64 adp_status;
int i, j;
if (!hldev->hw_is_initialized) {
xge_hal_status_e status;
status = __hal_device_hw_initialize(hldev);
if (status != XGE_HAL_OK) {
return status;
}
}
/*
* Not needed in most cases, i.e.
* when device_disable() is followed by reset -
* the latter copies back PCI config space, along with
* the bus mastership - see __hal_device_reset().
* However, there are/may-in-future be other cases, and
* does not hurt.
*/
__hal_device_bus_master_enable(hldev);
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
/*
* Configure the link stability period.
*/
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->misc_control);
if (hldev->config.link_stability_period !=
XGE_HAL_DEFAULT_USE_HARDCODE) {
val64 |= XGE_HAL_MISC_CONTROL_LINK_STABILITY_PERIOD(
hldev->config.link_stability_period);
} else {
/*
* Use the link stability period 1 ms as default
*/
val64 |= XGE_HAL_MISC_CONTROL_LINK_STABILITY_PERIOD(
XGE_HAL_DEFAULT_LINK_STABILITY_PERIOD);
}
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->misc_control);
/*
* Clearing any possible Link up/down interrupts that
* could have popped up just before Enabling the card.
*/
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->misc_int_reg);
if (val64) {
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->misc_int_reg);
xge_debug_device(XGE_TRACE, "%s","link state cleared");
}
} else if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA) {
/*
* Clearing any possible Link state change interrupts that
* could have popped up just before Enabling the card.
*/
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->mac_rmac_err_reg);
if (val64) {
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->mac_rmac_err_reg);
xge_debug_device(XGE_TRACE, "%s", "link state cleared");
}
}
if (__hal_device_wait_quiescent(hldev, &val64)) {
return XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
}
/* Enabling Laser. */
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_control);
val64 |= XGE_HAL_ADAPTER_EOI_TX_ON;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->adapter_control);
/* let link establish */
xge_os_mdelay(1);
/* set link down untill poll() routine will set it up (maybe) */
hldev->link_state = XGE_HAL_LINK_DOWN;
/* If link is UP (adpter is connected) then enable the adapter */
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_status);
if( val64 & (XGE_HAL_ADAPTER_STATUS_RMAC_REMOTE_FAULT |
XGE_HAL_ADAPTER_STATUS_RMAC_LOCAL_FAULT) ) {
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_control);
val64 = val64 & (~XGE_HAL_ADAPTER_LED_ON);
} else {
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_control);
val64 = val64 | ( XGE_HAL_ADAPTER_EOI_TX_ON |
XGE_HAL_ADAPTER_LED_ON );
}
val64 = val64 | XGE_HAL_ADAPTER_CNTL_EN; /* adapter enable */
val64 = val64 & (~XGE_HAL_ADAPTER_ECC_EN); /* ECC enable */
xge_os_pio_mem_write64 (hldev->pdev, hldev->regh0, val64,
&bar0->adapter_control);
/* We spin here waiting for the Link to come up.
* This is the fix for the Link being unstable after the reset. */
i = 0;
j = 0;
do
{
adp_status = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_status);
/* Read the adapter control register for Adapter_enable bit */
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_control);
if (!(adp_status & (XGE_HAL_ADAPTER_STATUS_RMAC_REMOTE_FAULT |
XGE_HAL_ADAPTER_STATUS_RMAC_LOCAL_FAULT)) &&
(val64 & XGE_HAL_ADAPTER_CNTL_EN)) {
j++;
if (j >= hldev->config.link_valid_cnt) {
if (xge_hal_device_status(hldev, &adp_status) ==
XGE_HAL_OK) {
if (__hal_verify_pcc_idle(hldev,
adp_status) != XGE_HAL_OK) {
return
XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
}
xge_debug_device(XGE_TRACE,
"adp_status: "XGE_OS_LLXFMT
", link is up on "
"adapter enable!",
(unsigned long long)adp_status);
val64 = xge_os_pio_mem_read64(
hldev->pdev,
hldev->regh0,
&bar0->adapter_control);
val64 = val64|
(XGE_HAL_ADAPTER_EOI_TX_ON |
XGE_HAL_ADAPTER_LED_ON );
xge_os_pio_mem_write64(hldev->pdev,
hldev->regh0, val64,
&bar0->adapter_control);
xge_os_mdelay(1);
val64 = xge_os_pio_mem_read64(
hldev->pdev,
hldev->regh0,
&bar0->adapter_control);
break; /* out of for loop */
} else {
return
XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
}
}
} else {
j = 0; /* Reset the count */
/* Turn on the Laser */
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_control);
val64 = val64 | XGE_HAL_ADAPTER_EOI_TX_ON;
xge_os_pio_mem_write64 (hldev->pdev, hldev->regh0,
val64, &bar0->adapter_control);
xge_os_mdelay(1);
/* Now re-enable it as due to noise, hardware
* turned it off */
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_control);
val64 |= XGE_HAL_ADAPTER_CNTL_EN;
val64 = val64 & (~XGE_HAL_ADAPTER_ECC_EN);/*ECC enable*/
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->adapter_control);
}
xge_os_mdelay(1); /* Sleep for 1 msec */
i++;
} while (i < hldev->config.link_retry_cnt);
__hal_device_led_actifity_fix(hldev);
#ifndef XGE_HAL_PROCESS_LINK_INT_IN_ISR
/* Here we are performing soft reset on XGXS to force link down.
* Since link is already up, we will get link state change
* poll notificatoin after adapter is enabled */
__hal_serial_mem_write64(hldev, 0x80010515001E0000ULL,
&bar0->dtx_control);
(void) __hal_serial_mem_read64(hldev, &bar0->dtx_control);
__hal_serial_mem_write64(hldev, 0x80010515001E00E0ULL,
&bar0->dtx_control);
(void) __hal_serial_mem_read64(hldev, &bar0->dtx_control);
__hal_serial_mem_write64(hldev, 0x80070515001F00E4ULL,
&bar0->dtx_control);
(void) __hal_serial_mem_read64(hldev, &bar0->dtx_control);
xge_os_mdelay(100); /* Sleep for 500 msec */
#else
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA)
#endif
{
/*
* With some switches the link state change interrupt does not
* occur even though the xgxs reset is done as per SPN-006. So,
* poll the adapter status register and check if the link state
* is ok.
*/
adp_status = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_status);
if (!(adp_status & (XGE_HAL_ADAPTER_STATUS_RMAC_REMOTE_FAULT |
XGE_HAL_ADAPTER_STATUS_RMAC_LOCAL_FAULT)))
{
xge_debug_device(XGE_TRACE, "%s",
"enable device causing link state change ind..");
(void) __hal_device_handle_link_state_change(hldev);
}
}
if (hldev->config.stats_refresh_time_sec !=
XGE_HAL_STATS_REFRESH_DISABLE)
__hal_stats_enable(&hldev->stats);
return XGE_HAL_OK;
}
/**
* xge_hal_device_disable - Disable Xframe adapter.
* @hldev: Device handle.
*
* Disable this device. To gracefully reset the adapter, the host should:
*
* - call xge_hal_device_disable();
*
* - call xge_hal_device_intr_disable();
*
* - close all opened channels and clean up outstanding resources;
*
* - do some work (error recovery, change mtu, reset, etc);
*
* - call xge_hal_device_enable();
*
* - open channels, replenish RxDs, etc.
*
* - call xge_hal_device_intr_enable().
*
* Note: Disabling the device does _not_ include disabling of interrupts.
* After disabling the device stops receiving new frames but those frames
* that were already in the pipe will keep coming for some few milliseconds.
*
* Returns: XGE_HAL_OK - success.
* XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT - Failed to restore the device to
* a "quiescent" state.
*
* See also: xge_hal_status_e{}.
*/
xge_hal_status_e
xge_hal_device_disable(xge_hal_device_t *hldev)
{
xge_hal_status_e status = XGE_HAL_OK;
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
xge_debug_device(XGE_TRACE, "%s", "turn off laser, cleanup hardware");
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_control);
val64 = val64 & (~XGE_HAL_ADAPTER_CNTL_EN);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->adapter_control);
if (__hal_device_wait_quiescent(hldev, &val64) != XGE_HAL_OK) {
status = XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
}
if (__hal_device_register_poll(hldev, &bar0->adapter_status, 1,
XGE_HAL_ADAPTER_STATUS_RC_PRC_QUIESCENT,
XGE_HAL_DEVICE_QUIESCENT_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
xge_debug_device(XGE_TRACE, "%s", "PRC is not QUIESCENT!");
status = XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT;
}
if (hldev->config.stats_refresh_time_sec !=
XGE_HAL_STATS_REFRESH_DISABLE)
__hal_stats_disable(&hldev->stats);
#ifdef XGE_DEBUG_ASSERT
else
xge_assert(!hldev->stats.is_enabled);
#endif
#ifndef XGE_HAL_DONT_DISABLE_BUS_MASTER_ON_STOP
__hal_device_bus_master_disable(hldev);
#endif
return status;
}
/**
* xge_hal_device_reset - Reset device.
* @hldev: HAL device handle.
*
* Soft-reset the device, reset the device stats except reset_cnt.
*
* After reset is done, will try to re-initialize HW.
*
* Returns: XGE_HAL_OK - success.
* XGE_HAL_ERR_DEVICE_NOT_INITIALIZED - Device is not initialized.
* XGE_HAL_ERR_RESET_FAILED - Reset failed.
*
* See also: xge_hal_status_e{}.
*/
xge_hal_status_e
xge_hal_device_reset(xge_hal_device_t *hldev)
{
xge_hal_status_e status;
/* increment the soft reset counter */
u32 reset_cnt = hldev->stats.sw_dev_info_stats.soft_reset_cnt;
xge_debug_device(XGE_TRACE, "%s (%d)", "resetting the device", reset_cnt);
if (!hldev->is_initialized)
return XGE_HAL_ERR_DEVICE_NOT_INITIALIZED;
/* actual "soft" reset of the adapter */
status = __hal_device_reset(hldev);
/* reset all stats including saved */
__hal_stats_soft_reset(hldev, 1);
/* increment reset counter */
hldev->stats.sw_dev_info_stats.soft_reset_cnt = reset_cnt + 1;
/* re-initialize rxufca_intr_thres */
hldev->rxufca_intr_thres = hldev->config.rxufca_intr_thres;
hldev->reset_needed_after_close = 0;
return status;
}
/**
* xge_hal_device_status - Check whether Xframe hardware is ready for
* operation.
* @hldev: HAL device handle.
* @hw_status: Xframe status register. Returned by HAL.
*
* Check whether Xframe hardware is ready for operation.
* The checking includes TDMA, RDMA, PFC, PIC, MC_DRAM, and the rest
* hardware functional blocks.
*
* Returns: XGE_HAL_OK if the device is ready for operation. Otherwise
* returns XGE_HAL_FAIL. Also, fills in adapter status (in @hw_status).
*
* See also: xge_hal_status_e{}.
* Usage: See ex_open{}.
*/
xge_hal_status_e
xge_hal_device_status(xge_hal_device_t *hldev, u64 *hw_status)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 tmp64;
tmp64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->adapter_status);
*hw_status = tmp64;
if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_TDMA_READY)) {
xge_debug_device(XGE_TRACE, "%s", "TDMA is not ready!");
return XGE_HAL_FAIL;
}
if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_RDMA_READY)) {
xge_debug_device(XGE_TRACE, "%s", "RDMA is not ready!");
return XGE_HAL_FAIL;
}
if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_PFC_READY)) {
xge_debug_device(XGE_TRACE, "%s", "PFC is not ready!");
return XGE_HAL_FAIL;
}
if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_TMAC_BUF_EMPTY)) {
xge_debug_device(XGE_TRACE, "%s", "TMAC BUF is not empty!");
return XGE_HAL_FAIL;
}
if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_PIC_QUIESCENT)) {
xge_debug_device(XGE_TRACE, "%s", "PIC is not QUIESCENT!");
return XGE_HAL_FAIL;
}
if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_MC_DRAM_READY)) {
xge_debug_device(XGE_TRACE, "%s", "MC_DRAM is not ready!");
return XGE_HAL_FAIL;
}
if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_MC_QUEUES_READY)) {
xge_debug_device(XGE_TRACE, "%s", "MC_QUEUES is not ready!");
return XGE_HAL_FAIL;
}
if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_M_PLL_LOCK)) {
xge_debug_device(XGE_TRACE, "%s", "M_PLL is not locked!");
return XGE_HAL_FAIL;
}
#ifndef XGE_HAL_HERC_EMULATION
/*
* Andrew: in PCI 33 mode, the P_PLL is not used, and therefore,
* the P_PLL_LOCK bit in the adapter_status register will
* not be asserted.
*/
if (!(tmp64 & XGE_HAL_ADAPTER_STATUS_P_PLL_LOCK) &&
xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC &&
hldev->pci_mode != XGE_HAL_PCI_33MHZ_MODE) {
xge_debug_device(XGE_TRACE, "%s", "P_PLL is not locked!");
return XGE_HAL_FAIL;
}
#endif
return XGE_HAL_OK;
}
void
__hal_device_msi_intr_endis(xge_hal_device_t *hldev, int flag)
{
u16 msi_control_reg;
xge_os_pci_read16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t,
msi_control), &msi_control_reg);
if (flag)
msi_control_reg |= 0x1;
else
msi_control_reg &= ~0x1;
xge_os_pci_write16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t,
msi_control), msi_control_reg);
}
void
__hal_device_msix_intr_endis(xge_hal_device_t *hldev,
xge_hal_channel_t *channel, int flag)
{
u64 val64;
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->xmsi_mask_reg);
if (flag)
val64 &= ~(1LL << ( 63 - channel->msix_idx ));
else
val64 |= (1LL << ( 63 - channel->msix_idx ));
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->xmsi_mask_reg);
}
/**
* xge_hal_device_intr_enable - Enable Xframe interrupts.
* @hldev: HAL device handle.
* @op: One of the xge_hal_device_intr_e enumerated values specifying
* the type(s) of interrupts to enable.
*
* Enable Xframe interrupts. The function is to be executed the last in
* Xframe initialization sequence.
*
* See also: xge_hal_device_intr_disable()
*/
void
xge_hal_device_intr_enable(xge_hal_device_t *hldev)
{
xge_list_t *item;
u64 val64;
/* PRC initialization and configuration */
xge_list_for_each(item, &hldev->ring_channels) {
xge_hal_channel_h channel;
channel = xge_container_of(item, xge_hal_channel_t, item);
__hal_ring_prc_enable(channel);
}
/* enable traffic only interrupts */
if (hldev->config.intr_mode != XGE_HAL_INTR_MODE_IRQLINE) {
/*
* make sure all interrupts going to be disabled if MSI
* is enabled.
*/
__hal_device_intr_mgmt(hldev, XGE_HAL_ALL_INTRS, 0);
} else {
/*
* Enable the Tx traffic interrupts only if the TTI feature is
* enabled.
*/
val64 = 0;
if (hldev->tti_enabled)
val64 = XGE_HAL_TX_TRAFFIC_INTR;
if (!hldev->config.bimodal_interrupts)
val64 |= XGE_HAL_RX_TRAFFIC_INTR;
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA)
val64 |= XGE_HAL_RX_TRAFFIC_INTR;
val64 |=XGE_HAL_TX_PIC_INTR |
XGE_HAL_MC_INTR |
XGE_HAL_TX_DMA_INTR |
(hldev->config.sched_timer_us !=
XGE_HAL_SCHED_TIMER_DISABLED ? XGE_HAL_SCHED_INTR : 0);
__hal_device_intr_mgmt(hldev, val64, 1);
}
/*
* Enable MSI-X interrupts
*/
if (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX) {
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
/*
* To enable MSI-X, MSI also needs to be enabled,
* due to a bug in the herc NIC.
*/
__hal_device_msi_intr_endis(hldev, 1);
}
/* Enable the MSI-X interrupt for each configured channel */
xge_list_for_each(item, &hldev->fifo_channels) {
xge_hal_channel_t *channel;
channel = xge_container_of(item,
xge_hal_channel_t, item);
/* 0 vector is reserved for alarms */
if (!channel->msix_idx)
continue;
__hal_device_msix_intr_endis(hldev, channel, 1);
}
xge_list_for_each(item, &hldev->ring_channels) {
xge_hal_channel_t *channel;
channel = xge_container_of(item,
xge_hal_channel_t, item);
/* 0 vector is reserved for alarms */
if (!channel->msix_idx)
continue;
__hal_device_msix_intr_endis(hldev, channel, 1);
}
}
xge_debug_device(XGE_TRACE, "%s", "interrupts are enabled");
}
/**
* xge_hal_device_intr_disable - Disable Xframe interrupts.
* @hldev: HAL device handle.
* @op: One of the xge_hal_device_intr_e enumerated values specifying
* the type(s) of interrupts to disable.
*
* Disable Xframe interrupts.
*
* See also: xge_hal_device_intr_enable()
*/
void
xge_hal_device_intr_disable(xge_hal_device_t *hldev)
{
xge_list_t *item;
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
if (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX) {
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
/*
* To disable MSI-X, MSI also needs to be disabled,
* due to a bug in the herc NIC.
*/
__hal_device_msi_intr_endis(hldev, 0);
}
/* Disable the MSI-X interrupt for each configured channel */
xge_list_for_each(item, &hldev->fifo_channels) {
xge_hal_channel_t *channel;
channel = xge_container_of(item,
xge_hal_channel_t, item);
/* 0 vector is reserved for alarms */
if (!channel->msix_idx)
continue;
__hal_device_msix_intr_endis(hldev, channel, 0);
}
xge_os_pio_mem_write64(hldev->pdev,
hldev->regh0, 0xFFFFFFFFFFFFFFFFULL,
&bar0->tx_traffic_mask);
xge_list_for_each(item, &hldev->ring_channels) {
xge_hal_channel_t *channel;
channel = xge_container_of(item,
xge_hal_channel_t, item);
/* 0 vector is reserved for alarms */
if (!channel->msix_idx)
continue;
__hal_device_msix_intr_endis(hldev, channel, 0);
}
xge_os_pio_mem_write64(hldev->pdev,
hldev->regh0, 0xFFFFFFFFFFFFFFFFULL,
&bar0->rx_traffic_mask);
}
/*
* Disable traffic only interrupts.
* Tx traffic interrupts are used only if the TTI feature is
* enabled.
*/
val64 = 0;
if (hldev->tti_enabled)
val64 = XGE_HAL_TX_TRAFFIC_INTR;
val64 |= XGE_HAL_RX_TRAFFIC_INTR |
XGE_HAL_TX_PIC_INTR |
XGE_HAL_MC_INTR |
(hldev->config.sched_timer_us != XGE_HAL_SCHED_TIMER_DISABLED ?
XGE_HAL_SCHED_INTR : 0);
__hal_device_intr_mgmt(hldev, val64, 0);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
0xFFFFFFFFFFFFFFFFULL,
&bar0->general_int_mask);
/* disable all configured PRCs */
xge_list_for_each(item, &hldev->ring_channels) {
xge_hal_channel_h channel;
channel = xge_container_of(item, xge_hal_channel_t, item);
__hal_ring_prc_disable(channel);
}
xge_debug_device(XGE_TRACE, "%s", "interrupts are disabled");
}
/**
* xge_hal_device_mcast_enable - Enable Xframe multicast addresses.
* @hldev: HAL device handle.
*
* Enable Xframe multicast addresses.
* Returns: XGE_HAL_OK on success.
* XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to enable mcast
* feature within the time(timeout).
*
* See also: xge_hal_device_mcast_disable(), xge_hal_status_e{}.
*/
xge_hal_status_e
xge_hal_device_mcast_enable(xge_hal_device_t *hldev)
{
u64 val64;
xge_hal_pci_bar0_t *bar0;
int mc_offset = XGE_HAL_MAC_MC_ALL_MC_ADDR_OFFSET;
if (hldev == NULL)
return XGE_HAL_ERR_INVALID_DEVICE;
if (hldev->mcast_refcnt)
return XGE_HAL_OK;
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)
mc_offset = XGE_HAL_MAC_MC_ALL_MC_ADDR_OFFSET_HERC;
hldev->mcast_refcnt = 1;
bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
/* Enable all Multicast addresses */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_RMAC_ADDR_DATA0_MEM_ADDR(0x010203040506ULL),
&bar0->rmac_addr_data0_mem);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_RMAC_ADDR_DATA1_MEM_MASK(0xfeffffffffffULL),
&bar0->rmac_addr_data1_mem);
val64 = XGE_HAL_RMAC_ADDR_CMD_MEM_WE |
XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
XGE_HAL_RMAC_ADDR_CMD_MEM_OFFSET(mc_offset);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rmac_addr_cmd_mem);
if (__hal_device_register_poll(hldev,
&bar0->rmac_addr_cmd_mem, 0,
XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
/* upper layer may require to repeat */
return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
}
return XGE_HAL_OK;
}
/**
* xge_hal_device_mcast_disable - Disable Xframe multicast addresses.
* @hldev: HAL device handle.
*
* Disable Xframe multicast addresses.
* Returns: XGE_HAL_OK - success.
* XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to disable mcast
* feature within the time(timeout).
*
* See also: xge_hal_device_mcast_enable(), xge_hal_status_e{}.
*/
xge_hal_status_e
xge_hal_device_mcast_disable(xge_hal_device_t *hldev)
{
u64 val64;
xge_hal_pci_bar0_t *bar0;
int mc_offset = XGE_HAL_MAC_MC_ALL_MC_ADDR_OFFSET;
if (hldev == NULL)
return XGE_HAL_ERR_INVALID_DEVICE;
if (hldev->mcast_refcnt == 0)
return XGE_HAL_OK;
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)
mc_offset = XGE_HAL_MAC_MC_ALL_MC_ADDR_OFFSET_HERC;
hldev->mcast_refcnt = 0;
bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
/* Disable all Multicast addresses */
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_RMAC_ADDR_DATA0_MEM_ADDR(0xffffffffffffULL),
&bar0->rmac_addr_data0_mem);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_RMAC_ADDR_DATA1_MEM_MASK(0),
&bar0->rmac_addr_data1_mem);
val64 = XGE_HAL_RMAC_ADDR_CMD_MEM_WE |
XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
XGE_HAL_RMAC_ADDR_CMD_MEM_OFFSET(mc_offset);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rmac_addr_cmd_mem);
if (__hal_device_register_poll(hldev,
&bar0->rmac_addr_cmd_mem, 0,
XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
/* upper layer may require to repeat */
return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
}
return XGE_HAL_OK;
}
/**
* xge_hal_device_promisc_enable - Enable promiscuous mode.
* @hldev: HAL device handle.
*
* Enable promiscuous mode of Xframe operation.
*
* See also: xge_hal_device_promisc_disable().
*/
void
xge_hal_device_promisc_enable(xge_hal_device_t *hldev)
{
u64 val64;
xge_hal_pci_bar0_t *bar0;
xge_assert(hldev);
bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
if (!hldev->is_promisc) {
/* Put the NIC into promiscuous mode */
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->mac_cfg);
val64 |= XGE_HAL_MAC_CFG_RMAC_PROM_ENABLE;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_RMAC_CFG_KEY(0x4C0D),
&bar0->rmac_cfg_key);
__hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0,
(u32)(val64 >> 32),
&bar0->mac_cfg);
hldev->is_promisc = 1;
xge_debug_device(XGE_TRACE,
"mac_cfg 0x"XGE_OS_LLXFMT": promisc enabled",
(unsigned long long)val64);
}
}
/**
* xge_hal_device_promisc_disable - Disable promiscuous mode.
* @hldev: HAL device handle.
*
* Disable promiscuous mode of Xframe operation.
*
* See also: xge_hal_device_promisc_enable().
*/
void
xge_hal_device_promisc_disable(xge_hal_device_t *hldev)
{
u64 val64;
xge_hal_pci_bar0_t *bar0;
xge_assert(hldev);
bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
if (hldev->is_promisc) {
/* Remove the NIC from promiscuous mode */
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->mac_cfg);
val64 &= ~XGE_HAL_MAC_CFG_RMAC_PROM_ENABLE;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_RMAC_CFG_KEY(0x4C0D),
&bar0->rmac_cfg_key);
__hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0,
(u32)(val64 >> 32),
&bar0->mac_cfg);
hldev->is_promisc = 0;
xge_debug_device(XGE_TRACE,
"mac_cfg 0x"XGE_OS_LLXFMT": promisc disabled",
(unsigned long long)val64);
}
}
/**
* xge_hal_device_macaddr_get - Get MAC addresses.
* @hldev: HAL device handle.
* @index: MAC address index, in the range from 0 to
* XGE_HAL_MAX_MAC_ADDRESSES.
* @macaddr: MAC address. Returned by HAL.
*
* Retrieve one of the stored MAC addresses by reading non-volatile
* memory on the chip.
*
* Up to %XGE_HAL_MAX_MAC_ADDRESSES addresses is supported.
*
* Returns: XGE_HAL_OK - success.
* XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to retrieve the mac
* address within the time(timeout).
* XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES - Invalid MAC address index.
*
* See also: xge_hal_device_macaddr_set(), xge_hal_status_e{}.
*/
xge_hal_status_e
xge_hal_device_macaddr_get(xge_hal_device_t *hldev, int index,
macaddr_t *macaddr)
{
xge_hal_pci_bar0_t *bar0;
u64 val64;
int i;
if (hldev == NULL) {
return XGE_HAL_ERR_INVALID_DEVICE;
}
bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
if ( index >= XGE_HAL_MAX_MAC_ADDRESSES ) {
return XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES;
}
#ifdef XGE_HAL_HERC_EMULATION
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,0x0000010000000000,
&bar0->rmac_addr_data0_mem);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,0x0000000000000000,
&bar0->rmac_addr_data1_mem);
val64 = XGE_HAL_RMAC_ADDR_CMD_MEM_RD |
XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
XGE_HAL_RMAC_ADDR_CMD_MEM_OFFSET((index));
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rmac_addr_cmd_mem);
/* poll until done */
__hal_device_register_poll(hldev,
&bar0->rmac_addr_cmd_mem, 0,
XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD,
XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS);
#endif
val64 = ( XGE_HAL_RMAC_ADDR_CMD_MEM_RD |
XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
XGE_HAL_RMAC_ADDR_CMD_MEM_OFFSET((index)) );
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rmac_addr_cmd_mem);
if (__hal_device_register_poll(hldev, &bar0->rmac_addr_cmd_mem, 0,
XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
/* upper layer may require to repeat */
return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
}
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->rmac_addr_data0_mem);
for (i=0; i < XGE_HAL_ETH_ALEN; i++) {
(*macaddr)[i] = (u8)(val64 >> ((64 - 8) - (i * 8)));
}
#ifdef XGE_HAL_HERC_EMULATION
for (i=0; i < XGE_HAL_ETH_ALEN; i++) {
(*macaddr)[i] = (u8)0;
}
(*macaddr)[1] = (u8)1;
#endif
return XGE_HAL_OK;
}
/**
* xge_hal_device_macaddr_set - Set MAC address.
* @hldev: HAL device handle.
* @index: MAC address index, in the range from 0 to
* XGE_HAL_MAX_MAC_ADDRESSES.
* @macaddr: New MAC address to configure.
*
* Configure one of the available MAC address "slots".
*
* Up to %XGE_HAL_MAX_MAC_ADDRESSES addresses is supported.
*
* Returns: XGE_HAL_OK - success.
* XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to set the new mac
* address within the time(timeout).
* XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES - Invalid MAC address index.
*
* See also: xge_hal_device_macaddr_get(), xge_hal_status_e{}.
*/
xge_hal_status_e
xge_hal_device_macaddr_set(xge_hal_device_t *hldev, int index,
macaddr_t macaddr)
{
xge_hal_pci_bar0_t *bar0 =
(xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64, temp64;
int i;
if ( index >= XGE_HAL_MAX_MAC_ADDRESSES )
return XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES;
temp64 = 0;
for (i=0; i < XGE_HAL_ETH_ALEN; i++) {
temp64 |= macaddr[i];
temp64 <<= 8;
}
temp64 >>= 8;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_RMAC_ADDR_DATA0_MEM_ADDR(temp64),
&bar0->rmac_addr_data0_mem);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
XGE_HAL_RMAC_ADDR_DATA1_MEM_MASK(0ULL),
&bar0->rmac_addr_data1_mem);
val64 = ( XGE_HAL_RMAC_ADDR_CMD_MEM_WE |
XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
XGE_HAL_RMAC_ADDR_CMD_MEM_OFFSET((index)) );
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rmac_addr_cmd_mem);
if (__hal_device_register_poll(hldev, &bar0->rmac_addr_cmd_mem, 0,
XGE_HAL_RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
/* upper layer may require to repeat */
return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
}
return XGE_HAL_OK;
}
/**
* xge_hal_device_macaddr_clear - Set MAC address.
* @hldev: HAL device handle.
* @index: MAC address index, in the range from 0 to
* XGE_HAL_MAX_MAC_ADDRESSES.
*
* Clear one of the available MAC address "slots".
*
* Returns: XGE_HAL_OK - success.
* XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to set the new mac
* address within the time(timeout).
* XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES - Invalid MAC address index.
*
* See also: xge_hal_device_macaddr_set(), xge_hal_status_e{}.
*/
xge_hal_status_e
xge_hal_device_macaddr_clear(xge_hal_device_t *hldev, int index)
{
xge_hal_status_e status;
u8 macaddr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
status = xge_hal_device_macaddr_set(hldev, index, macaddr);
if (status != XGE_HAL_OK) {
xge_debug_device(XGE_ERR, "%s",
"Not able to set the mac addr");
return status;
}
return XGE_HAL_OK;
}
/**
* xge_hal_device_macaddr_find - Finds index in the rmac table.
* @hldev: HAL device handle.
* @wanted: Wanted MAC address.
*
* See also: xge_hal_device_macaddr_set().
*/
int
xge_hal_device_macaddr_find(xge_hal_device_t *hldev, macaddr_t wanted)
{
int i;
if (hldev == NULL) {
return XGE_HAL_ERR_INVALID_DEVICE;
}
for (i=1; i<XGE_HAL_MAX_MAC_ADDRESSES; i++) {
macaddr_t macaddr;
(void) xge_hal_device_macaddr_get(hldev, i, &macaddr);
if (!xge_os_memcmp(macaddr, wanted, sizeof(macaddr_t))) {
return i;
}
}
return -1;
}
/**
* xge_hal_device_mtu_set - Set MTU.
* @hldev: HAL device handle.
* @new_mtu: New MTU size to configure.
*
* Set new MTU value. Example, to use jumbo frames:
* xge_hal_device_mtu_set(my_device, my_channel, 9600);
*
* Returns: XGE_HAL_OK on success.
* XGE_HAL_ERR_SWAPPER_CTRL - Failed to configure swapper control
* register.
* XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to initialize TTI/RTI
* schemes.
* XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT - Failed to restore the device to
* a "quiescent" state.
*/
xge_hal_status_e
xge_hal_device_mtu_set(xge_hal_device_t *hldev, int new_mtu)
{
xge_hal_status_e status;
/*
* reset needed if 1) new MTU differs, and
* 2a) device was closed or
* 2b) device is being upped for first time.
*/
if (hldev->config.mtu != new_mtu) {
if (hldev->reset_needed_after_close ||
!hldev->mtu_first_time_set) {
status = xge_hal_device_reset(hldev);
if (status != XGE_HAL_OK) {
xge_debug_device(XGE_TRACE, "%s",
"fatal: can not reset the device");
return status;
}
}
/* store the new MTU in device, reset will use it */
hldev->config.mtu = new_mtu;
xge_debug_device(XGE_TRACE, "new MTU %d applied",
new_mtu);
}
if (!hldev->mtu_first_time_set)
hldev->mtu_first_time_set = 1;
return XGE_HAL_OK;
}
/**
* xge_hal_device_initialize - Initialize Xframe device.
* @hldev: HAL device handle.
* @attr: pointer to xge_hal_device_attr_t structure
* @device_config: Configuration to be _applied_ to the device,
* For the Xframe configuration "knobs" please
* refer to xge_hal_device_config_t and Xframe
* User Guide.
*
* Initialize Xframe device. Note that all the arguments of this public API
* are 'IN', including @hldev. Upper-layer driver (ULD) cooperates with
* OS to find new Xframe device, locate its PCI and memory spaces.
*
* When done, the ULD allocates sizeof(xge_hal_device_t) bytes for HAL
* to enable the latter to perform Xframe hardware initialization.
*
* Returns: XGE_HAL_OK - success.
* XGE_HAL_ERR_DRIVER_NOT_INITIALIZED - Driver is not initialized.
* XGE_HAL_ERR_BAD_DEVICE_CONFIG - Device configuration params are not
* valid.
* XGE_HAL_ERR_OUT_OF_MEMORY - Memory allocation failed.
* XGE_HAL_ERR_BAD_SUBSYSTEM_ID - Device subsystem id is invalid.
* XGE_HAL_ERR_INVALID_MAC_ADDRESS - Device mac address in not valid.
* XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to retrieve the mac
* address within the time(timeout) or TTI/RTI initialization failed.
* XGE_HAL_ERR_SWAPPER_CTRL - Failed to configure swapper control.
* XGE_HAL_ERR_DEVICE_IS_NOT_QUIESCENT -Device is not queiscent.
*
* See also: xge_hal_device_terminate(), xge_hal_status_e{}
* xge_hal_device_attr_t{}.
*/
xge_hal_status_e
xge_hal_device_initialize(xge_hal_device_t *hldev, xge_hal_device_attr_t *attr,
xge_hal_device_config_t *device_config)
{
int i;
xge_hal_status_e status;
xge_hal_channel_t *channel;
u16 subsys_device;
u16 subsys_vendor;
int total_dram_size, ring_auto_dram_cfg, left_dram_size;
int total_dram_size_max = 0;
xge_debug_device(XGE_TRACE, "device 0x"XGE_OS_LLXFMT" is initializing",
(unsigned long long)(ulong_t)hldev);
/* sanity check */
if (g_xge_hal_driver == NULL ||
!g_xge_hal_driver->is_initialized) {
return XGE_HAL_ERR_DRIVER_NOT_INITIALIZED;
}
xge_os_memzero(hldev, sizeof(xge_hal_device_t));
/*
* validate a common part of Xframe-I/II configuration
* (and run check_card() later, once PCI inited - see below)
*/
status = __hal_device_config_check_common(device_config);
if (status != XGE_HAL_OK)
return status;
/* apply config */
xge_os_memcpy(&hldev->config, device_config,
sizeof(xge_hal_device_config_t));
/* save original attr */
xge_os_memcpy(&hldev->orig_attr, attr,
sizeof(xge_hal_device_attr_t));
/* initialize rxufca_intr_thres */
hldev->rxufca_intr_thres = hldev->config.rxufca_intr_thres;
hldev->regh0 = attr->regh0;
hldev->regh1 = attr->regh1;
hldev->regh2 = attr->regh2;
hldev->isrbar0 = hldev->bar0 = attr->bar0;
hldev->bar1 = attr->bar1;
hldev->bar2 = attr->bar2;
hldev->pdev = attr->pdev;
hldev->irqh = attr->irqh;
hldev->cfgh = attr->cfgh;
/* set initial bimodal timer for bimodal adaptive schema */
hldev->bimodal_timer_val_us = hldev->config.bimodal_timer_lo_us;
hldev->queueh = xge_queue_create(hldev->pdev, hldev->irqh,
g_xge_hal_driver->config.queue_size_initial,
g_xge_hal_driver->config.queue_size_max,
__hal_device_event_queued, hldev);
if (hldev->queueh == NULL)
return XGE_HAL_ERR_OUT_OF_MEMORY;
hldev->magic = XGE_HAL_MAGIC;
xge_assert(hldev->regh0);
xge_assert(hldev->regh1);
xge_assert(hldev->bar0);
xge_assert(hldev->bar1);
xge_assert(hldev->pdev);
xge_assert(hldev->irqh);
xge_assert(hldev->cfgh);
/* initialize some PCI/PCI-X fields of this PCI device. */
__hal_device_pci_init(hldev);
/*
* initlialize lists to properly handling a potential
* terminate request
*/
xge_list_init(&hldev->free_channels);
xge_list_init(&hldev->fifo_channels);
xge_list_init(&hldev->ring_channels);
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA) {
/* fixups for xena */
hldev->config.rth_en = 0;
hldev->config.rth_spdm_en = 0;
hldev->config.rts_mac_en = 0;
total_dram_size_max = XGE_HAL_MAX_RING_QUEUE_SIZE_XENA;
status = __hal_device_config_check_xena(device_config);
if (status != XGE_HAL_OK) {
xge_hal_device_terminate(hldev);
return status;
}
if (hldev->config.bimodal_interrupts == 1) {
xge_hal_device_terminate(hldev);
return XGE_HAL_BADCFG_BIMODAL_XENA_NOT_ALLOWED;
} else if (hldev->config.bimodal_interrupts ==
XGE_HAL_DEFAULT_USE_HARDCODE)
hldev->config.bimodal_interrupts = 0;
} else if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC) {
/* fixups for herc */
total_dram_size_max = XGE_HAL_MAX_RING_QUEUE_SIZE_HERC;
status = __hal_device_config_check_herc(device_config);
if (status != XGE_HAL_OK) {
xge_hal_device_terminate(hldev);
return status;
}
if (hldev->config.bimodal_interrupts ==
XGE_HAL_DEFAULT_USE_HARDCODE)
hldev->config.bimodal_interrupts = 1;
} else {
xge_debug_device(XGE_ERR,
"detected unknown device_id 0x%x", hldev->device_id);
xge_hal_device_terminate(hldev);
return XGE_HAL_ERR_BAD_DEVICE_ID;
}
/* allocate and initialize FIFO types of channels according to
* configuration */
for (i = 0; i < XGE_HAL_MAX_FIFO_NUM; i++) {
if (!device_config->fifo.queue[i].configured)
continue;
channel = __hal_channel_allocate(hldev, i,
XGE_HAL_CHANNEL_TYPE_FIFO);
if (channel == NULL) {
xge_debug_device(XGE_ERR,
"fifo: __hal_channel_allocate failed");
xge_hal_device_terminate(hldev);
return XGE_HAL_ERR_OUT_OF_MEMORY;
}
/* add new channel to the device */
xge_list_insert(&channel->item, &hldev->free_channels);
}
/*
* automatic DRAM adjustment
*/
total_dram_size = 0;
ring_auto_dram_cfg = 0;
for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++) {
if (!device_config->ring.queue[i].configured)
continue;
if (device_config->ring.queue[i].dram_size_mb ==
XGE_HAL_DEFAULT_USE_HARDCODE) {
ring_auto_dram_cfg++;
continue;
}
total_dram_size += device_config->ring.queue[i].dram_size_mb;
}
left_dram_size = total_dram_size_max - total_dram_size;
if (left_dram_size < 0 ||
(ring_auto_dram_cfg && left_dram_size / ring_auto_dram_cfg == 0)) {
xge_debug_device(XGE_ERR,
"ring config: exceeded DRAM size %d MB",
total_dram_size_max);
xge_hal_device_terminate(hldev);
return XGE_HAL_BADCFG_RING_QUEUE_SIZE;
}
/*
* allocate and initialize RING types of channels according to
* configuration
*/
for (i = 0; i < XGE_HAL_MAX_RING_NUM; i++) {
if (!device_config->ring.queue[i].configured)
continue;
if (device_config->ring.queue[i].dram_size_mb ==
XGE_HAL_DEFAULT_USE_HARDCODE) {
hldev->config.ring.queue[i].dram_size_mb =
device_config->ring.queue[i].dram_size_mb =
left_dram_size / ring_auto_dram_cfg;
}
channel = __hal_channel_allocate(hldev, i,
XGE_HAL_CHANNEL_TYPE_RING);
if (channel == NULL) {
xge_debug_device(XGE_ERR,
"ring: __hal_channel_allocate failed");
xge_hal_device_terminate(hldev);
return XGE_HAL_ERR_OUT_OF_MEMORY;
}
/* add new channel to the device */
xge_list_insert(&channel->item, &hldev->free_channels);
}
/* get subsystem IDs */
xge_os_pci_read16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, subsystem_id),
&subsys_device);
xge_os_pci_read16(hldev->pdev, hldev->cfgh,
xge_offsetof(xge_hal_pci_config_le_t, subsystem_vendor_id),
&subsys_vendor);
xge_debug_device(XGE_TRACE,
"subsystem_id %04x:%04x",
subsys_vendor, subsys_device);
/* reset device initially */
(void) __hal_device_reset(hldev);
/* set host endian before, to assure proper action */
status = __hal_device_set_swapper(hldev);
if (status != XGE_HAL_OK) {
xge_debug_device(XGE_ERR,
"__hal_device_set_swapper failed");
xge_hal_device_terminate(hldev);
(void) __hal_device_reset(hldev);
return status;
}
#ifndef XGE_HAL_HERC_EMULATION
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_XENA)
__hal_device_xena_fix_mac(hldev);
#endif
/* MAC address initialization.
* For now only one mac address will be read and used. */
status = xge_hal_device_macaddr_get(hldev, 0, &hldev->macaddr[0]);
if (status != XGE_HAL_OK) {
xge_debug_device(XGE_ERR,
"xge_hal_device_macaddr_get failed");
xge_hal_device_terminate(hldev);
return status;
}
if (hldev->macaddr[0][0] == 0xFF &&
hldev->macaddr[0][1] == 0xFF &&
hldev->macaddr[0][2] == 0xFF &&
hldev->macaddr[0][3] == 0xFF &&
hldev->macaddr[0][4] == 0xFF &&
hldev->macaddr[0][5] == 0xFF) {
xge_debug_device(XGE_ERR,
"xge_hal_device_macaddr_get returns all FFs");
xge_hal_device_terminate(hldev);
return XGE_HAL_ERR_INVALID_MAC_ADDRESS;
}
xge_debug_device(XGE_TRACE,
"default macaddr: 0x%02x-%02x-%02x-%02x-%02x-%02x",
hldev->macaddr[0][0], hldev->macaddr[0][1],
hldev->macaddr[0][2], hldev->macaddr[0][3],
hldev->macaddr[0][4], hldev->macaddr[0][5]);
status = __hal_stats_initialize(&hldev->stats, hldev);
if (status != XGE_HAL_OK) {
xge_debug_device(XGE_ERR,
"__hal_stats_initialize failed");
xge_hal_device_terminate(hldev);
return status;
}
status = __hal_device_hw_initialize(hldev);
if (status != XGE_HAL_OK) {
xge_debug_device(XGE_ERR,
"__hal_device_hw_initialize failed");
xge_hal_device_terminate(hldev);
return status;
}
hldev->dump_buf=(char*)xge_os_malloc(hldev->pdev, XGE_HAL_DUMP_BUF_SIZE);
if (hldev->dump_buf == NULL) {
xge_debug_device(XGE_ERR,
"__hal_device_hw_initialize failed");
xge_hal_device_terminate(hldev);
return XGE_HAL_ERR_OUT_OF_MEMORY;
}
/* Xena-only: need to serialize fifo posts across all device fifos */
#if defined(XGE_HAL_TX_MULTI_POST)
xge_os_spin_lock_init(&hldev->xena_post_lock, hldev->pdev);
#elif defined(XGE_HAL_TX_MULTI_POST_IRQ)
xge_os_spin_lock_init_irq(&hldev->xena_post_lock, hldev->irqh);
#endif
/* Getting VPD data */
__hal_device_get_vpd_data(hldev);
hldev->is_initialized = 1;
return XGE_HAL_OK;
}
/**
* xge_hal_device_terminating - Mark the device as 'terminating'.
* @devh: HAL device handle.
*
* Mark the device as 'terminating', going to terminate. Can be used
* to serialize termination with other running processes/contexts.
*
* See also: xge_hal_device_terminate().
*/
void
xge_hal_device_terminating(xge_hal_device_h devh)
{
xge_hal_device_t *hldev = (xge_hal_device_t*)devh;
xge_list_t *item;
xge_hal_channel_t *channel;
#if defined(XGE_HAL_TX_MULTI_RESERVE_IRQ)
unsigned long flags=0;
#endif
/*
* go through each opened tx channel and aquire
* lock, so it will serialize with HAL termination flag
*/
xge_list_for_each(item, &hldev->fifo_channels) {
channel = xge_container_of(item, xge_hal_channel_t, item);
#if defined(XGE_HAL_TX_MULTI_RESERVE)
xge_os_spin_lock(&channel->reserve_lock);
#elif defined(XGE_HAL_TX_MULTI_RESERVE_IRQ)
xge_os_spin_lock_irq(&channel->reserve_lock, flags);
#endif
channel->terminating = 1;
#if defined(XGE_HAL_TX_MULTI_RESERVE)
xge_os_spin_unlock(&channel->reserve_lock);
#elif defined(XGE_HAL_TX_MULTI_RESERVE_IRQ)
xge_os_spin_unlock_irq(&channel->reserve_lock, flags);
#endif
}
hldev->terminating = 1;
}
/**
* xge_hal_device_terminate - Terminate Xframe device.
* @hldev: HAL device handle.
*
* Terminate HAL device.
*
* See also: xge_hal_device_initialize().
*/
void
xge_hal_device_terminate(xge_hal_device_t *hldev)
{
xge_assert(g_xge_hal_driver != NULL);
xge_assert(hldev != NULL);
xge_assert(hldev->magic == XGE_HAL_MAGIC);
xge_queue_flush(hldev->queueh);
hldev->terminating = 1;
hldev->is_initialized = 0;
hldev->in_poll = 0;
hldev->magic = XGE_HAL_DEAD;
#if defined(XGE_HAL_TX_MULTI_POST)
xge_os_spin_lock_destroy(&hldev->xena_post_lock, hldev->pdev);
#elif defined(XGE_HAL_TX_MULTI_POST_IRQ)
xge_os_spin_lock_destroy_irq(&hldev->xena_post_lock, hldev->pdev);
#endif
xge_debug_device(XGE_TRACE, "device "XGE_OS_LLXFMT" is terminating",
(unsigned long long)(ulong_t)hldev);
xge_assert(xge_list_is_empty(&hldev->fifo_channels));
xge_assert(xge_list_is_empty(&hldev->ring_channels));
if (hldev->stats.is_initialized) {
__hal_stats_terminate(&hldev->stats);
}
/* close if open and free all channels */
while (!xge_list_is_empty(&hldev->free_channels)) {
xge_hal_channel_t *channel = (xge_hal_channel_t*)
hldev->free_channels.next;
xge_assert(!channel->is_open);
xge_list_remove(&channel->item);
__hal_channel_free(channel);
}
if (hldev->queueh) {
xge_queue_destroy(hldev->queueh);
}
if (hldev->spdm_table) {
xge_os_free(hldev->pdev,
hldev->spdm_table[0],
(sizeof(xge_hal_spdm_entry_t) *
hldev->spdm_max_entries));
xge_os_free(hldev->pdev,
hldev->spdm_table,
(sizeof(xge_hal_spdm_entry_t *) *
hldev->spdm_max_entries));
xge_os_spin_lock_destroy(&hldev->spdm_lock, hldev->pdev);
hldev->spdm_table = NULL;
}
if (hldev->dump_buf) {
xge_os_free(hldev->pdev, hldev->dump_buf,
XGE_HAL_DUMP_BUF_SIZE);
hldev->dump_buf = NULL;
}
if (hldev->device_id != 0) {
int j, pcisize;
pcisize = (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)?
XGE_HAL_PCISIZE_HERC : XGE_HAL_PCISIZE_XENA;
for (j = 0; j < pcisize; j++) {
xge_os_pci_write32(hldev->pdev, hldev->cfgh, j * 4,
*((u32*)&hldev->pci_config_space_bios + j));
}
}
}
/**
* __hal_device_get_vpd_data - Getting vpd_data.
*
* @hldev: HAL device handle.
*
* Getting product name and serial number from vpd capabilites structure
*
*/
void
__hal_device_get_vpd_data(xge_hal_device_t *hldev)
{
u8 * vpd_data;
u8 data;
int index = 0, count, fail = 0;
u8 vpd_addr = XGE_HAL_CARD_XENA_VPD_ADDR;
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)
vpd_addr = XGE_HAL_CARD_HERC_VPD_ADDR;
xge_os_strcpy((char *) hldev->vpd_data.product_name,
"10 Gigabit Ethernet Adapter");
xge_os_strcpy((char *) hldev->vpd_data.serial_num, "not available");
vpd_data = ( u8*) xge_os_malloc(hldev->pdev, XGE_HAL_VPD_BUFFER_SIZE + 16);
if ( vpd_data == NULL )
return;
for (index = 0; index < XGE_HAL_VPD_BUFFER_SIZE; index +=4 ) {
xge_os_pci_write8(hldev->pdev, hldev->cfgh, (vpd_addr + 2), (u8)index);
xge_os_pci_read8(hldev->pdev, hldev->cfgh,(vpd_addr + 2), &data);
xge_os_pci_write8(hldev->pdev, hldev->cfgh, (vpd_addr + 3), 0);
for (count = 0; count < 5; count++ ) {
xge_os_mdelay(2);
xge_os_pci_read8(hldev->pdev, hldev->cfgh,(vpd_addr + 3), &data);
if (data == XGE_HAL_VPD_READ_COMPLETE)
break;
}
if (count >= 5) {
xge_os_printf("ERR, Reading VPD data failed");
fail = 1;
break;
}
xge_os_pci_read32(hldev->pdev, hldev->cfgh,(vpd_addr + 4),
(u32 *)&vpd_data[index]);
}
if(!fail) {
/* read serial number of adapter */
for (count = 0; count < XGE_HAL_VPD_BUFFER_SIZE; count++) {
if ((vpd_data[count] == 'S') &&
(vpd_data[count + 1] == 'N') &&
(vpd_data[count + 2] < XGE_HAL_VPD_LENGTH)) {
memset(hldev->vpd_data.serial_num, 0, XGE_HAL_VPD_LENGTH);
memcpy(hldev->vpd_data.serial_num, &vpd_data[count + 3],
vpd_data[count + 2]);
break;
}
}
if (vpd_data[1] < XGE_HAL_VPD_LENGTH) {
memset(hldev->vpd_data.product_name, 0, vpd_data[1]);
memcpy(hldev->vpd_data.product_name, &vpd_data[3], vpd_data[1]);
}
}
xge_os_free(hldev->pdev, vpd_data, XGE_HAL_VPD_BUFFER_SIZE + 16);
}
/**
* xge_hal_device_handle_tcode - Handle transfer code.
* @channelh: Channel handle.
* @dtrh: Descriptor handle.
* @t_code: One of the enumerated (and documented in the Xframe user guide)
* "transfer codes".
*
* Handle descriptor's transfer code. The latter comes with each completed
* descriptor, see xge_hal_fifo_dtr_next_completed() and
* xge_hal_ring_dtr_next_completed().
* Transfer codes are enumerated in xgehal-fifo.h and xgehal-ring.h.
*
* Returns: one of the xge_hal_status_e{} enumerated types.
* XGE_HAL_OK - for success.
* XGE_HAL_ERR_CRITICAL - when encounters critical error.
*/
xge_hal_status_e
xge_hal_device_handle_tcode (xge_hal_channel_h channelh,
xge_hal_dtr_h dtrh, u8 t_code)
{
xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
xge_hal_device_t *hldev = (xge_hal_device_t *)channel->devh;
if (t_code > 15) {
xge_os_printf("invalid t_code %d", t_code);
return XGE_HAL_OK;
}
if (channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) {
hldev->stats.sw_dev_err_stats.txd_t_code_err_cnt[t_code]++;
#if defined(XGE_HAL_DEBUG_BAD_TCODE)
xge_hal_fifo_txd_t *txdp = (xge_hal_fifo_txd_t *)dtrh;
xge_os_printf(""XGE_OS_LLXFMT":"XGE_OS_LLXFMT":"
XGE_OS_LLXFMT":"XGE_OS_LLXFMT,
txdp->control_1, txdp->control_2, txdp->buffer_pointer,
txdp->host_control);
#endif
/* handle link "down" immediately without going through
* xge_hal_device_poll() routine. */
if (t_code == XGE_HAL_TXD_T_CODE_LOSS_OF_LINK) {
/* link is down */
if (hldev->link_state != XGE_HAL_LINK_DOWN) {
xge_hal_pci_bar0_t *bar0 =
(xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
hldev->link_state = XGE_HAL_LINK_DOWN;
val64 = xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->adapter_control);
/* turn off LED */
val64 = val64 & (~XGE_HAL_ADAPTER_LED_ON);
xge_os_pio_mem_write64(hldev->pdev,
hldev->regh0, val64,
&bar0->adapter_control);
g_xge_hal_driver->uld_callbacks.link_down(
hldev->upper_layer_info);
}
} else if (t_code == XGE_HAL_TXD_T_CODE_ABORT_BUFFER ||
t_code == XGE_HAL_TXD_T_CODE_ABORT_DTOR) {
__hal_device_handle_targetabort(hldev);
return XGE_HAL_ERR_CRITICAL;
}
return XGE_HAL_ERR_PKT_DROP;
} else if (channel->type == XGE_HAL_CHANNEL_TYPE_RING) {
hldev->stats.sw_dev_err_stats.rxd_t_code_err_cnt[t_code]++;
#if defined(XGE_HAL_DEBUG_BAD_TCODE)
xge_hal_ring_rxd_1_t *rxdp = (xge_hal_ring_rxd_1_t *)dtrh;
xge_os_printf(""XGE_OS_LLXFMT":"XGE_OS_LLXFMT":"XGE_OS_LLXFMT
":"XGE_OS_LLXFMT, rxdp->control_1,
rxdp->control_2, rxdp->buffer0_ptr,
rxdp->host_control);
#endif
if (t_code == XGE_HAL_RXD_T_CODE_BAD_ECC) {
hldev->stats.sw_dev_err_stats.ecc_err_cnt++;
__hal_device_handle_eccerr(hldev, "rxd_t_code",
(u64)t_code);
return XGE_HAL_ERR_CRITICAL;
} else if (t_code == XGE_HAL_RXD_T_CODE_PARITY ||
t_code == XGE_HAL_RXD_T_CODE_PARITY_ABORT) {
hldev->stats.sw_dev_err_stats.parity_err_cnt++;
__hal_device_handle_parityerr(hldev, "rxd_t_code",
(u64)t_code);
return XGE_HAL_ERR_CRITICAL;
/* do not drop if detected unknown IPv6 extension */
} else if (t_code != XGE_HAL_RXD_T_CODE_UNKNOWN_PROTO) {
return XGE_HAL_ERR_PKT_DROP;
}
}
return XGE_HAL_OK;
}
/**
* xge_hal_device_link_state - Get link state.
* @devh: HAL device handle.
* @ls: Link state, see xge_hal_device_link_state_e{}.
*
* Get link state.
* Returns: XGE_HAL_OK.
* See also: xge_hal_device_link_state_e{}.
*/
xge_hal_status_e xge_hal_device_link_state(xge_hal_device_h devh,
xge_hal_device_link_state_e *ls)
{
xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
xge_assert(ls != NULL);
*ls = hldev->link_state;
return XGE_HAL_OK;
}
/**
* xge_hal_device_sched_timer - Configure scheduled device interrupt.
* @devh: HAL device handle.
* @interval_us: Time interval, in miscoseconds.
* Unlike transmit and receive interrupts,
* the scheduled interrupt is generated independently of
* traffic, but purely based on time.
* @one_shot: 1 - generate scheduled interrupt only once.
* 0 - generate scheduled interrupt periodically at the specified
* @interval_us interval.
*
* (Re-)configure scheduled interrupt. Can be called at runtime to change
* the setting, generate one-shot interrupts based on the resource and/or
* traffic conditions, other purposes.
* See also: xge_hal_device_config_t{}.
*/
void xge_hal_device_sched_timer(xge_hal_device_h devh, int interval_us,
int one_shot)
{
u64 val64;
xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
xge_hal_pci_bar0_t *bar0 =
(xge_hal_pci_bar0_t *)(void *)hldev->bar0;
unsigned int interval = hldev->config.pci_freq_mherz * interval_us;
interval = __hal_fix_time_ival_herc(hldev, interval);
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->scheduled_int_ctrl);
if (interval) {
val64 &= XGE_HAL_SCHED_INT_PERIOD_MASK;
val64 |= XGE_HAL_SCHED_INT_PERIOD(interval);
if (one_shot) {
val64 |= XGE_HAL_SCHED_INT_CTRL_ONE_SHOT;
}
val64 |= XGE_HAL_SCHED_INT_CTRL_TIMER_EN;
} else {
val64 &= ~XGE_HAL_SCHED_INT_CTRL_TIMER_EN;
}
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->scheduled_int_ctrl);
xge_debug_device(XGE_TRACE, "sched_timer 0x"XGE_OS_LLXFMT": %s",
(unsigned long long)val64,
interval ? "enabled" : "disabled");
}
/**
* xge_hal_device_check_id - Verify device ID.
* @devh: HAL device handle.
*
* Verify device ID.
* Returns: one of the xge_hal_card_e{} enumerated types.
* See also: xge_hal_card_e{}.
*/
xge_hal_card_e
xge_hal_device_check_id(xge_hal_device_h devh)
{
xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
switch (hldev->device_id) {
case XGE_PCI_DEVICE_ID_XENA_1:
case XGE_PCI_DEVICE_ID_XENA_2:
return XGE_HAL_CARD_XENA;
case XGE_PCI_DEVICE_ID_HERC_1:
case XGE_PCI_DEVICE_ID_HERC_2:
return XGE_HAL_CARD_HERC;
case XGE_PCI_DEVICE_ID_TITAN_1:
case XGE_PCI_DEVICE_ID_TITAN_2:
return XGE_HAL_CARD_TITAN;
default:
return XGE_HAL_CARD_UNKNOWN;
}
}
/**
* xge_hal_device_pci_info_get - Get PCI bus informations such as width,
* frequency, and mode from previously stored values.
* @devh: HAL device handle.
* @pci_mode: pointer to a variable of enumerated type
* xge_hal_pci_mode_e{}.
* @bus_frequency: pointer to a variable of enumerated type
* xge_hal_pci_bus_frequency_e{}.
* @bus_width: pointer to a variable of enumerated type
* xge_hal_pci_bus_width_e{}.
*
* Get pci mode, frequency, and PCI bus width.
* Returns: one of the xge_hal_status_e{} enumerated types.
* XGE_HAL_OK - for success.
* XGE_HAL_ERR_INVALID_DEVICE - for invalid device handle.
* See Also: xge_hal_pci_mode_e, xge_hal_pci_mode_e, xge_hal_pci_width_e.
*/
xge_hal_status_e
xge_hal_device_pci_info_get(xge_hal_device_h devh, xge_hal_pci_mode_e *pci_mode,
xge_hal_pci_bus_frequency_e *bus_frequency,
xge_hal_pci_bus_width_e *bus_width)
{
xge_hal_status_e rc_status;
xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
if (!hldev || !hldev->is_initialized || hldev->magic != XGE_HAL_MAGIC) {
rc_status = XGE_HAL_ERR_INVALID_DEVICE;
xge_debug_device(XGE_ERR,
"xge_hal_device_pci_info_get error, rc %d for device %p",
rc_status, hldev);
return rc_status;
}
*pci_mode = hldev->pci_mode;
*bus_frequency = hldev->bus_frequency;
*bus_width = hldev->bus_width;
rc_status = XGE_HAL_OK;
return rc_status;
}
/**
* xge_hal_reinitialize_hw
* @hldev: private member of the device structure.
*
* This function will soft reset the NIC and re-initalize all the
* I/O registers to the values they had after it's inital initialization
* through the probe function.
*/
int xge_hal_reinitialize_hw(xge_hal_device_t * hldev)
{
(void) xge_hal_device_reset(hldev);
if (__hal_device_hw_initialize(hldev) != XGE_HAL_OK) {
xge_hal_device_terminate(hldev);
(void) __hal_device_reset(hldev);
return 1;
}
return 0;
}
/*
* __hal_read_spdm_entry_line
* @hldev: pointer to xge_hal_device_t structure
* @spdm_line: spdm line in the spdm entry to be read.
* @spdm_entry: spdm entry of the spdm_line in the SPDM table.
* @spdm_line_val: Contains the value stored in the spdm line.
*
* SPDM table contains upto a maximum of 256 spdm entries.
* Each spdm entry contains 8 lines and each line stores 8 bytes.
* This function reads the spdm line(addressed by @spdm_line)
* of the spdm entry(addressed by @spdm_entry) in
* the SPDM table.
*/
xge_hal_status_e
__hal_read_spdm_entry_line(xge_hal_device_t *hldev, u8 spdm_line,
u16 spdm_entry, u64 *spdm_line_val)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
val64 = XGE_HAL_RTS_RTH_SPDM_MEM_CTRL_STROBE |
XGE_HAL_RTS_RTH_SPDM_MEM_CTRL_LINE_SEL(spdm_line) |
XGE_HAL_RTS_RTH_SPDM_MEM_CTRL_OFFSET(spdm_entry);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rts_rth_spdm_mem_ctrl);
/* poll until done */
if (__hal_device_register_poll(hldev,
&bar0->rts_rth_spdm_mem_ctrl, 0,
XGE_HAL_RTS_RTH_SPDM_MEM_CTRL_STROBE,
XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
}
*spdm_line_val = xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0, &bar0->rts_rth_spdm_mem_data);
return XGE_HAL_OK;
}
/*
* __hal_get_free_spdm_entry
* @hldev: pointer to xge_hal_device_t structure
* @spdm_entry: Contains an index to the unused spdm entry in the SPDM table.
*
* This function returns an index of unused spdm entry in the SPDM
* table.
*/
static xge_hal_status_e
__hal_get_free_spdm_entry(xge_hal_device_t *hldev, u16 *spdm_entry)
{
xge_hal_status_e status;
u64 spdm_line_val=0;
/*
* Search in the local SPDM table for a free slot.
*/
*spdm_entry = 0;
for(; *spdm_entry < hldev->spdm_max_entries; (*spdm_entry)++) {
if (hldev->spdm_table[*spdm_entry]->in_use) {
break;
}
}
if (*spdm_entry >= hldev->spdm_max_entries) {
return XGE_HAL_ERR_SPDM_TABLE_FULL;
}
/*
* Make sure that the corresponding spdm entry in the SPDM
* table is free.
* Seventh line of the spdm entry contains information about
* whether the entry is free or not.
*/
if ((status = __hal_read_spdm_entry_line(hldev, 7, *spdm_entry,
&spdm_line_val)) != XGE_HAL_OK) {
return status;
}
/* BIT(63) in spdm_line 7 corresponds to entry_enable bit */
if ((spdm_line_val & BIT(63))) {
/*
* Log a warning
*/
xge_debug_device(XGE_ERR, "Local SPDM table is not "
"consistent with the actual one for the spdm "
"entry %d", *spdm_entry);
return XGE_HAL_ERR_SPDM_TABLE_DATA_INCONSISTENT;
}
return XGE_HAL_OK;
}
/*
* __hal_calc_jhash - Calculate Jenkins hash.
* @msg: Jenkins hash algorithm key.
* @length: Length of the key.
* @golden_ratio: Jenkins hash golden ratio.
* @init_value: Jenkins hash initial value.
*
* This function implements the Jenkins based algorithm used for the
* calculation of the RTH hash.
* Returns: Jenkins hash value.
*
*/
static u32
__hal_calc_jhash(u8 *msg, u32 length, u32 golden_ratio, u32 init_value)
{
register u32 a,b,c,len;
/*
* Set up the internal state
*/
len = length;
a = b = golden_ratio; /* the golden ratio; an arbitrary value */
c = init_value; /* the previous hash value */
/* handle most of the key */
while (len >= 12)
{
a += (msg[0] + ((u32)msg[1]<<8) + ((u32)msg[2]<<16)
+ ((u32)msg[3]<<24));
b += (msg[4] + ((u32)msg[5]<<8) + ((u32)msg[6]<<16)
+ ((u32)msg[7]<<24));
c += (msg[8] + ((u32)msg[9]<<8) + ((u32)msg[10]<<16)
+ ((u32)msg[11]<<24));
mix(a,b,c);
msg += 12; len -= 12;
}
/* handle the last 11 bytes */
c += length;
switch(len) /* all the case statements fall through */
{
case 11: c+= ((u32)msg[10]<<24);
break;
case 10: c+= ((u32)msg[9]<<16);
break;
case 9 : c+= ((u32)msg[8]<<8);
break;
/* the first byte of c is reserved for the length */
case 8 : b+= ((u32)msg[7]<<24);
break;
case 7 : b+= ((u32)msg[6]<<16);
break;
case 6 : b+= ((u32)msg[5]<<8);
break;
case 5 : b+= msg[4];
break;
case 4 : a+= ((u32)msg[3]<<24);
break;
case 3 : a+= ((u32)msg[2]<<16);
break;
case 2 : a+= ((u32)msg[1]<<8);
break;
case 1 : a+= msg[0];
break;
/* case 0: nothing left to add */
}
mix(a,b,c);
/* report the result */
return c;
}
/**
* xge_hal_spdm_entry_add - Add a new entry to the SPDM table.
* @devh: HAL device handle.
* @src_ip: Source ip address(IPv4/IPv6).
* @dst_ip: Destination ip address(IPv4/IPv6).
* @l4_sp: L4 source port.
* @l4_dp: L4 destination port.
* @is_tcp: Set to 1, if the protocol is TCP.
* 0, if the protocol is UDP.
* @is_ipv4: Set to 1, if the protocol is IPv4.
* 0, if the protocol is IPv6.
* @tgt_queue: Target queue to route the receive packet.
*
* This function add a new entry to the SPDM table.
*
* Returns: XGE_HAL_OK - success.
* XGE_HAL_ERR_SPDM_NOT_ENABLED - SPDM support is not enabled.
* XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to add a new entry with in
* the time(timeout).
* XGE_HAL_ERR_SPDM_TABLE_FULL - SPDM table is full.
* XGE_HAL_ERR_SPDM_INVALID_ENTRY - Invalid SPDM entry.
*
* See also: xge_hal_spdm_entry_remove{}.
*/
xge_hal_status_e
xge_hal_spdm_entry_add(xge_hal_device_h devh, xge_hal_ipaddr_t *src_ip,
xge_hal_ipaddr_t *dst_ip, u16 l4_sp, u16 l4_dp,
u8 is_tcp, u8 is_ipv4, u8 tgt_queue)
{
xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u32 jhash_value;
u32 jhash_init_val;
u32 jhash_golden_ratio;
u64 val64;
int off;
u16 spdm_entry;
u8 msg[XGE_HAL_JHASH_MSG_LEN];
int ipaddr_len;
xge_hal_status_e status;
if (!hldev->config.rth_spdm_en) {
return XGE_HAL_ERR_SPDM_NOT_ENABLED;
}
if ((tgt_queue < XGE_HAL_MIN_RING_NUM) ||
(tgt_queue > XGE_HAL_MAX_RING_NUM)) {
return XGE_HAL_ERR_SPDM_INVALID_ENTRY;
}
/*
* Calculate the jenkins hash.
*/
/*
* Create the Jenkins hash algorithm key.
* key = {L3SA, L3DA, L4SP, L4DP}, if SPDM is configured to
* use L4 information. Otherwize key = {L3SA, L3DA}.
*/
if (is_ipv4) {
ipaddr_len = 4; // In bytes
} else {
ipaddr_len = 16;
}
/*
* Jenkins hash algorithm expects the key in the big endian
* format. Since key is the byte array, memcpy won't work in the
* case of little endian. So, the current code extracts each
* byte starting from MSB and store it in the key.
*/
if (is_ipv4) {
for (off = 0; off < ipaddr_len; off++) {
u32 mask = vBIT32(0xff,(off*8),8);
int shift = 32-(off+1)*8;
msg[off] = (u8)((src_ip->ipv4.addr & mask) >> shift);
msg[off+ipaddr_len] =
(u8)((dst_ip->ipv4.addr & mask) >> shift);
}
} else {
for (off = 0; off < ipaddr_len; off++) {
int loc = off % 8;
u64 mask = vBIT(0xff,(loc*8),8);
int shift = 64-(loc+1)*8;
msg[off] = (u8)((src_ip->ipv6.addr[off/8] & mask)
>> shift);
msg[off+ipaddr_len] = (u8)((dst_ip->ipv6.addr[off/8]
& mask) >> shift);
}
}
off = (2*ipaddr_len);
if (hldev->config.rth_spdm_use_l4) {
msg[off] = (u8)((l4_sp & 0xff00) >> 8);
msg[off + 1] = (u8)(l4_sp & 0xff);
msg[off + 2] = (u8)((l4_dp & 0xff00) >> 8);
msg[off + 3] = (u8)(l4_dp & 0xff);
off += 4;
}
/*
* Calculate jenkins hash for this configuration
*/
val64 = xge_os_pio_mem_read64(hldev->pdev,
hldev->regh0,
&bar0->rts_rth_jhash_cfg);
jhash_golden_ratio = (u32)(val64 >> 32);
jhash_init_val = (u32)(val64 & 0xffffffff);
jhash_value = __hal_calc_jhash(msg, off,
jhash_golden_ratio,
jhash_init_val);
xge_os_spin_lock(&hldev->spdm_lock);
/*
* Locate a free slot in the SPDM table. To avoid a seach in the
* actual SPDM table, which is very expensive in terms of time,
* we are maintaining a local copy of the table and the search for
* the free entry is performed in the local table.
*/
if ((status = __hal_get_free_spdm_entry(hldev,&spdm_entry))
!= XGE_HAL_OK) {
xge_os_spin_unlock(&hldev->spdm_lock);
return status;
}
/*
* Add this entry to the SPDM table
*/
status = __hal_spdm_entry_add(hldev, src_ip, dst_ip, l4_sp, l4_dp,
is_tcp, is_ipv4, tgt_queue,
jhash_value, /* calculated jhash */
spdm_entry);
xge_os_spin_unlock(&hldev->spdm_lock);
return status;
}
/**
* xge_hal_spdm_entry_remove - Remove an entry from the SPDM table.
* @devh: HAL device handle.
* @src_ip: Source ip address(IPv4/IPv6).
* @dst_ip: Destination ip address(IPv4/IPv6).
* @l4_sp: L4 source port.
* @l4_dp: L4 destination port.
* @is_tcp: Set to 1, if the protocol is TCP.
* 0, if the protocol os UDP.
* @is_ipv4: Set to 1, if the protocol is IPv4.
* 0, if the protocol is IPv6.
*
* This function remove an entry from the SPDM table.
*
* Returns: XGE_HAL_OK - success.
* XGE_HAL_ERR_SPDM_NOT_ENABLED - SPDM support is not enabled.
* XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING - Failed to remove an entry with in
* the time(timeout).
* XGE_HAL_ERR_SPDM_ENTRY_NOT_FOUND - Unable to locate the entry in the SPDM
* table.
*
* See also: xge_hal_spdm_entry_add{}.
*/
xge_hal_status_e
xge_hal_spdm_entry_remove(xge_hal_device_h devh, xge_hal_ipaddr_t *src_ip,
xge_hal_ipaddr_t *dst_ip, u16 l4_sp, u16 l4_dp,
u8 is_tcp, u8 is_ipv4)
{
xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
u16 spdm_entry;
xge_hal_status_e status;
u64 spdm_line_arr[8];
u8 line_no;
u8 spdm_is_tcp;
u8 spdm_is_ipv4;
u16 spdm_l4_sp;
u16 spdm_l4_dp;
if (!hldev->config.rth_spdm_en) {
return XGE_HAL_ERR_SPDM_NOT_ENABLED;
}
xge_os_spin_lock(&hldev->spdm_lock);
/*
* Poll the rxpic_int_reg register until spdm ready bit is set or
* timeout happens.
*/
if (__hal_device_register_poll(hldev, &bar0->rxpic_int_reg, 1,
XGE_HAL_RX_PIC_INT_REG_SPDM_READY,
XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
/* upper layer may require to repeat */
xge_os_spin_unlock(&hldev->spdm_lock);
return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
}
/*
* Clear the SPDM READY bit.
*/
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->rxpic_int_reg);
val64 &= ~XGE_HAL_RX_PIC_INT_REG_SPDM_READY;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rxpic_int_reg);
/*
* Search in the local SPDM table to get the index of the
* corresponding entry in the SPDM table.
*/
spdm_entry = 0;
for (;spdm_entry < hldev->spdm_max_entries; spdm_entry++) {
if ((!hldev->spdm_table[spdm_entry]->in_use) ||
(hldev->spdm_table[spdm_entry]->is_tcp != is_tcp) ||
(hldev->spdm_table[spdm_entry]->l4_sp != l4_sp) ||
(hldev->spdm_table[spdm_entry]->l4_dp != l4_dp) ||
(hldev->spdm_table[spdm_entry]->is_ipv4 != is_ipv4)) {
continue;
}
/*
* Compare the src/dst IP addresses of source and target
*/
if (is_ipv4) {
if ((hldev->spdm_table[spdm_entry]->src_ip.ipv4.addr
!= src_ip->ipv4.addr) ||
(hldev->spdm_table[spdm_entry]->dst_ip.ipv4.addr
!= dst_ip->ipv4.addr)) {
continue;
}
} else {
if ((hldev->spdm_table[spdm_entry]->src_ip.ipv6.addr[0]
!= src_ip->ipv6.addr[0]) ||
(hldev->spdm_table[spdm_entry]->src_ip.ipv6.addr[1]
!= src_ip->ipv6.addr[1]) ||
(hldev->spdm_table[spdm_entry]->dst_ip.ipv6.addr[0]
!= dst_ip->ipv6.addr[0]) ||
(hldev->spdm_table[spdm_entry]->dst_ip.ipv6.addr[1]
!= dst_ip->ipv6.addr[1])) {
continue;
}
}
break;
}
if (spdm_entry >= hldev->spdm_max_entries) {
xge_os_spin_unlock(&hldev->spdm_lock);
return XGE_HAL_ERR_SPDM_ENTRY_NOT_FOUND;
}
/*
* Retrieve the corresponding entry from the SPDM table and
* make sure that the data is consistent.
*/
for(line_no = 0; line_no < 8; line_no++) {
/*
* SPDM line 2,3,4 are valid only for IPv6 entry.
* SPDM line 5 & 6 are reserved. We don't have to
* read these entries in the above cases.
*/
if (((is_ipv4) &&
((line_no == 2)||(line_no == 3)||(line_no == 4))) ||
(line_no == 5) ||
(line_no == 6)) {
continue;
}
if ((status = __hal_read_spdm_entry_line(
hldev,
line_no,
spdm_entry,
&spdm_line_arr[line_no]))
!= XGE_HAL_OK) {
xge_os_spin_unlock(&hldev->spdm_lock);
return status;
}
}
/*
* Seventh line of the spdm entry contains the entry_enable
* bit. Make sure that the entry_enable bit of this spdm entry
* is set.
* To remove an entry from the SPDM table, reset this
* bit.
*/
if (!(spdm_line_arr[7] & BIT(63))) {
/*
* Log a warning
*/
xge_debug_device(XGE_ERR, "Local SPDM table is not "
"consistent with the actual one for the spdm "
"entry %d ", spdm_entry);
goto err_exit;
}
/*
* Retreive the L4 SP/DP, src/dst ip addresses from the SPDM
* table and do a comparision.
*/
spdm_is_tcp = (u8)((spdm_line_arr[0] & BIT(59)) >> 4);
spdm_is_ipv4 = (u8)(spdm_line_arr[0] & BIT(63));
spdm_l4_sp = (u16)(spdm_line_arr[0] >> 48);
spdm_l4_dp = (u16)((spdm_line_arr[0] >> 32) & 0xffff);
if ((spdm_is_tcp != is_tcp) ||
(spdm_is_ipv4 != is_ipv4) ||
(spdm_l4_sp != l4_sp) ||
(spdm_l4_dp != l4_dp)) {
/*
* Log a warning
*/
xge_debug_device(XGE_ERR, "Local SPDM table is not "
"consistent with the actual one for the spdm "
"entry %d ", spdm_entry);
goto err_exit;
}
if (is_ipv4) {
/* Upper 32 bits of spdm_line(64 bit) contains the
* src IPv4 address. Lower 32 bits of spdm_line
* contains the destination IPv4 address.
*/
u32 temp_src_ip = (u32)(spdm_line_arr[1] >> 32);
u32 temp_dst_ip = (u32)(spdm_line_arr[1] & 0xffffffff);
if ((temp_src_ip != src_ip->ipv4.addr) ||
(temp_dst_ip != dst_ip->ipv4.addr)) {
xge_debug_device(XGE_ERR, "Local SPDM table is not "
"consistent with the actual one for the spdm "
"entry %d ", spdm_entry);
goto err_exit;
}
} else {
/*
* SPDM line 1 & 2 contains the src IPv6 address.
* SPDM line 3 & 4 contains the dst IPv6 address.
*/
if ((spdm_line_arr[1] != src_ip->ipv6.addr[0]) ||
(spdm_line_arr[2] != src_ip->ipv6.addr[1]) ||
(spdm_line_arr[3] != dst_ip->ipv6.addr[0]) ||
(spdm_line_arr[4] != dst_ip->ipv6.addr[1])) {
/*
* Log a warning
*/
xge_debug_device(XGE_ERR, "Local SPDM table is not "
"consistent with the actual one for the spdm "
"entry %d ", spdm_entry);
goto err_exit;
}
}
/*
* Reset the entry_enable bit to zero
*/
spdm_line_arr[7] &= ~BIT(63);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
spdm_line_arr[7],
(void *)((char *)hldev->spdm_mem_base +
(spdm_entry * 64) + (7 * 8)));
/*
* Wait for the operation to be completed.
*/
if (__hal_device_register_poll(hldev,
&bar0->rxpic_int_reg, 1,
XGE_HAL_RX_PIC_INT_REG_SPDM_READY,
XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
xge_os_spin_unlock(&hldev->spdm_lock);
return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
}
/*
* Make the corresponding spdm entry in the local SPDM table
* available for future use.
*/
hldev->spdm_table[spdm_entry]->in_use = 0;
xge_os_spin_unlock(&hldev->spdm_lock);
return XGE_HAL_OK;
err_exit:
xge_os_spin_unlock(&hldev->spdm_lock);
return XGE_HAL_ERR_SPDM_TABLE_DATA_INCONSISTENT;
}
/*
* __hal_device_rti_set
* @ring: The post_qid of the ring.
* @channel: HAL channel of the ring.
*
* This function stores the RTI value associated for the MSI and
* also unmasks this particular RTI in the rti_mask register.
*/
static void __hal_device_rti_set(int ring_qid, xge_hal_channel_t *channel)
{
xge_hal_device_t *hldev = (xge_hal_device_t*)channel->devh;
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;
u64 val64;
if (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSI ||
hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX)
channel->rti = (u8)ring_qid;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->rx_traffic_mask);
val64 &= ~BIT(ring_qid);
xge_os_pio_mem_write64(hldev->pdev,
hldev->regh0, val64,
&bar0->rx_traffic_mask);
}
/*
* __hal_device_tti_set
* @ring: The post_qid of the FIFO.
* @channel: HAL channel the FIFO.
*
* This function stores the TTI value associated for the MSI and
* also unmasks this particular TTI in the tti_mask register.
*/
static void __hal_device_tti_set(int fifo_qid, xge_hal_channel_t *channel)
{
xge_hal_device_t *hldev = (xge_hal_device_t*)channel->devh;
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;
u64 val64;
if (hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSI ||
hldev->config.intr_mode == XGE_HAL_INTR_MODE_MSIX)
channel->tti = (u8)fifo_qid;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->tx_traffic_mask);
val64 &= ~BIT(fifo_qid);
xge_os_pio_mem_write64(hldev->pdev,
hldev->regh0, val64,
&bar0->tx_traffic_mask);
}
/**
* xge_hal_channel_msi_set - Associate a RTI with a ring or TTI with a
* FIFO for a given MSI.
* @channelh: HAL channel handle.
* @msi: MSI Number associated with the channel.
* @msi_msg: The MSI message associated with the MSI number above.
*
* This API will associate a given channel (either Ring or FIFO) with the
* given MSI number. It will alo program the Tx_Mat/Rx_Mat tables in the
* hardware to indicate this association to the hardware.
*/
xge_hal_status_e
xge_hal_channel_msi_set(xge_hal_channel_h channelh, int msi, u32 msi_msg)
{
xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
xge_hal_device_t *hldev = (xge_hal_device_t*)channel->devh;
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;
u64 val64;
channel->msi_msg = msi_msg;
if (channel->type == XGE_HAL_CHANNEL_TYPE_RING) {
int ring = channel->post_qid;
xge_debug_osdep(XGE_TRACE, "MSI Data: 0x%4x, Ring: %d,"
" MSI: %d", channel->msi_msg, ring, msi);
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->rx_mat);
val64 |= XGE_HAL_SET_RX_MAT(ring, msi);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rx_mat);
__hal_device_rti_set(ring, channel);
} else {
int fifo = channel->post_qid;
xge_debug_osdep(XGE_TRACE, "MSI Data: 0x%4x, Fifo: %d,"
" MSI: %d", channel->msi_msg, fifo, msi);
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->tx_mat[0]);
val64 |= XGE_HAL_SET_TX_MAT(fifo, msi);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->tx_mat[0]);
__hal_device_tti_set(fifo, channel);
}
return XGE_HAL_OK;
}
/**
* xge_hal_mask_msix - Begin IRQ processing.
* @hldev: HAL device handle.
* @msi_id: MSI ID
*
* The function masks the msix interrupt for the given msi_id
*
* Note:
*
* Returns: 0,
* Otherwise, XGE_HAL_ERR_WRONG_IRQ if the msix index is out of range
* status.
* See also:
*/
xge_hal_status_e
xge_hal_mask_msix(xge_hal_device_h devh, int msi_id)
{
xge_hal_status_e status = XGE_HAL_OK;
xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
u32 *bar2 = (u32 *)hldev->bar2;
u32 val32;
xge_assert(msi_id < XGE_HAL_MAX_MSIX_MESSAGES);
val32 = xge_os_pio_mem_read32(hldev->pdev, hldev->regh2, &bar2[msi_id*4+3]);
val32 |= 1;
xge_os_pio_mem_write32(hldev->pdev, hldev->regh2, val32, &bar2[msi_id*4+3]);
return status;
}
/**
* xge_hal_mask_msix - Begin IRQ processing.
* @hldev: HAL device handle.
* @msi_id: MSI ID
*
* The function masks the msix interrupt for the given msi_id
*
* Note:
*
* Returns: 0,
* Otherwise, XGE_HAL_ERR_WRONG_IRQ if the msix index is out of range
* status.
* See also:
*/
xge_hal_status_e
xge_hal_unmask_msix(xge_hal_device_h devh, int msi_id)
{
xge_hal_status_e status = XGE_HAL_OK;
xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
u32 *bar2 = (u32 *)hldev->bar2;
u32 val32;
xge_assert(msi_id < XGE_HAL_MAX_MSIX_MESSAGES);
val32 = xge_os_pio_mem_read32(hldev->pdev, hldev->regh2, &bar2[msi_id*4+3]);
val32 &= ~1;
xge_os_pio_mem_write32(hldev->pdev, hldev->regh2, val32, &bar2[msi_id*4+3]);
return status;
}
/*
* __hal_set_msix_vals
* @devh: HAL device handle.
* @msix_value: 32bit MSI-X value transferred across PCI to @msix_address.
* Filled in by this function.
* @msix_address: 32bit MSI-X DMA address.
* Filled in by this function.
* @msix_idx: index that corresponds to the (@msix_value, @msix_address)
* entry in the table of MSI-X (value, address) pairs.
*
* This function will program the hardware associating the given
* address/value cobination to the specified msi number.
*/
static void __hal_set_msix_vals (xge_hal_device_h devh,
u32 *msix_value,
u64 *msix_addr,
int msix_idx)
{
int cnt = 0;
xge_hal_device_t *hldev = (xge_hal_device_t*)devh;
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;
u64 val64;
val64 = XGE_HAL_XMSI_NO(msix_idx) | XGE_HAL_XMSI_STROBE;
__hal_pio_mem_write32_upper(hldev->pdev, hldev->regh0,
(u32)(val64 >> 32), &bar0->xmsi_access);
__hal_pio_mem_write32_lower(hldev->pdev, hldev->regh0,
(u32)(val64), &bar0->xmsi_access);
do {
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->xmsi_access);
if (val64 & XGE_HAL_XMSI_STROBE)
break;
cnt++;
xge_os_mdelay(20);
} while(cnt < 5);
*msix_value = (u32)(xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->xmsi_data));
*msix_addr = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->xmsi_address);
}
/**
* xge_hal_channel_msix_set - Associate MSI-X with a channel.
* @channelh: HAL channel handle.
* @msix_idx: index that corresponds to a particular (@msix_value,
* @msix_address) entry in the MSI-X table.
*
* This API associates a given channel (either Ring or FIFO) with the
* given MSI-X number. It programs the Xframe's Tx_Mat/Rx_Mat tables
* to indicate this association.
*/
xge_hal_status_e
xge_hal_channel_msix_set(xge_hal_channel_h channelh, int msix_idx)
{
xge_hal_channel_t *channel = (xge_hal_channel_t *)channelh;
xge_hal_device_t *hldev = (xge_hal_device_t*)channel->devh;
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;
u64 val64;
if (channel->type == XGE_HAL_CHANNEL_TYPE_RING) {
/* Currently Ring and RTI is one on one. */
int ring = channel->post_qid;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->rx_mat);
val64 |= XGE_HAL_SET_RX_MAT(ring, msix_idx);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rx_mat);
__hal_device_rti_set(ring, channel);
hldev->config.fifo.queue[channel->post_qid].intr_vector =
msix_idx;
} else if (channel->type == XGE_HAL_CHANNEL_TYPE_FIFO) {
int fifo = channel->post_qid;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->tx_mat[0]);
val64 |= XGE_HAL_SET_TX_MAT(fifo, msix_idx);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->tx_mat[0]);
__hal_device_tti_set(fifo, channel);
hldev->config.ring.queue[channel->post_qid].intr_vector =
msix_idx;
}
channel->msix_idx = msix_idx;
__hal_set_msix_vals(hldev, &channel->msix_data,
&channel->msix_address,
channel->msix_idx);
return XGE_HAL_OK;
}
#if defined(XGE_HAL_CONFIG_LRO)
/**
* xge_hal_lro_terminate - Terminate lro resources.
* @lro_scale: Amount of lro memory.
* @hldev: Hal device structure.
*
*/
void
xge_hal_lro_terminate(u32 lro_scale,
xge_hal_device_t *hldev)
{
}
/**
* xge_hal_lro_init - Initiate lro resources.
* @lro_scale: Amount of lro memory.
* @hldev: Hal device structure.
* Note: For time being I am using only one LRO per device. Later on size
* will be increased.
*/
xge_hal_status_e
xge_hal_lro_init(u32 lro_scale,
xge_hal_device_t *hldev)
{
int i;
if (hldev->config.lro_sg_size == XGE_HAL_DEFAULT_USE_HARDCODE)
hldev->config.lro_sg_size = XGE_HAL_LRO_DEFAULT_SG_SIZE;
if (hldev->config.lro_frm_len == XGE_HAL_DEFAULT_USE_HARDCODE)
hldev->config.lro_frm_len = XGE_HAL_LRO_DEFAULT_FRM_LEN;
for (i=0; i < XGE_HAL_MAX_RING_NUM; i++)
{
xge_os_memzero(hldev->lro_desc[i].lro_pool,
sizeof(lro_t) * XGE_HAL_LRO_MAX_BUCKETS);
hldev->lro_desc[i].lro_next_idx = 0;
hldev->lro_desc[i].lro_recent = NULL;
}
return XGE_HAL_OK;
}
#endif
/**
* xge_hal_device_poll - HAL device "polling" entry point.
* @devh: HAL device.
*
* HAL "polling" entry point. Note that this is part of HAL public API.
* Upper-Layer driver _must_ periodically poll HAL via
* xge_hal_device_poll().
*
* HAL uses caller's execution context to serially process accumulated
* slow-path events, such as link state changes and hardware error
* indications.
*
* The rate of polling could be somewhere between 500us to 10ms,
* depending on requirements (e.g., the requirement to support fail-over
* could mean that 500us or even 100us polling interval need to be used).
*
* The need and motivation for external polling includes
*
* - remove the error-checking "burden" from the HAL interrupt handler
* (see xge_hal_device_handle_irq());
*
* - remove the potential source of portability issues by _not_
* implementing separate polling thread within HAL itself.
*
* See also: xge_hal_event_e{}, xge_hal_driver_config_t{}.
* Usage: See ex_slow_path{}.
*/
void
xge_hal_device_poll(xge_hal_device_h devh)
{
unsigned char item_buf[sizeof(xge_queue_item_t) +
XGE_DEFAULT_EVENT_MAX_DATA_SIZE];
xge_queue_item_t *item = (xge_queue_item_t *)(void *)item_buf;
xge_queue_status_e qstatus;
xge_hal_status_e hstatus;
int i = 0;
int queue_has_critical_event = 0;
xge_hal_device_t *hldev = (xge_hal_device_t*)devh;
xge_os_memzero(item_buf, (sizeof(xge_queue_item_t) +
XGE_DEFAULT_EVENT_MAX_DATA_SIZE));
_again:
if (!hldev->is_initialized ||
hldev->terminating ||
hldev->magic != XGE_HAL_MAGIC)
return;
if(hldev->stats.sw_dev_err_stats.xpak_counter.tick_period < 72000)
{
/*
* Wait for an Hour
*/
hldev->stats.sw_dev_err_stats.xpak_counter.tick_period++;
} else {
/*
* Logging Error messages in the excess temperature,
* Bias current, laser output for three cycle
*/
__hal_updt_stats_xpak(hldev);
hldev->stats.sw_dev_err_stats.xpak_counter.tick_period = 0;
}
if (!queue_has_critical_event)
queue_has_critical_event =
__queue_get_reset_critical(hldev->queueh);
hldev->in_poll = 1;
while (i++ < XGE_HAL_DRIVER_QUEUE_CONSUME_MAX || queue_has_critical_event) {
qstatus = xge_queue_consume(hldev->queueh,
XGE_DEFAULT_EVENT_MAX_DATA_SIZE,
item);
if (qstatus == XGE_QUEUE_IS_EMPTY)
break;
xge_debug_queue(XGE_TRACE,
"queueh 0x"XGE_OS_LLXFMT" consumed event: %d ctxt 0x"
XGE_OS_LLXFMT, (u64)(ulong_t)hldev->queueh, item->event_type,
(u64)(ulong_t)item->context);
if (!hldev->is_initialized ||
hldev->magic != XGE_HAL_MAGIC) {
hldev->in_poll = 0;
return;
}
switch (item->event_type) {
case XGE_HAL_EVENT_LINK_IS_UP: {
if (!queue_has_critical_event &&
g_xge_hal_driver->uld_callbacks.link_up) {
g_xge_hal_driver->uld_callbacks.link_up(
hldev->upper_layer_info);
hldev->link_state = XGE_HAL_LINK_UP;
}
} break;
case XGE_HAL_EVENT_LINK_IS_DOWN: {
if (!queue_has_critical_event &&
g_xge_hal_driver->uld_callbacks.link_down) {
g_xge_hal_driver->uld_callbacks.link_down(
hldev->upper_layer_info);
hldev->link_state = XGE_HAL_LINK_DOWN;
}
} break;
case XGE_HAL_EVENT_SERR:
case XGE_HAL_EVENT_ECCERR:
case XGE_HAL_EVENT_PARITYERR:
case XGE_HAL_EVENT_TARGETABORT:
case XGE_HAL_EVENT_SLOT_FREEZE: {
void *item_data = xge_queue_item_data(item);
xge_hal_event_e event_type = item->event_type;
u64 val64 = *((u64*)item_data);
if (event_type != XGE_HAL_EVENT_SLOT_FREEZE)
if (xge_hal_device_is_slot_freeze(hldev))
event_type = XGE_HAL_EVENT_SLOT_FREEZE;
if (g_xge_hal_driver->uld_callbacks.crit_err) {
g_xge_hal_driver->uld_callbacks.crit_err(
hldev->upper_layer_info,
event_type,
val64);
/* handle one critical event per poll cycle */
hldev->in_poll = 0;
return;
}
} break;
default: {
xge_debug_queue(XGE_TRACE,
"got non-HAL event %d",
item->event_type);
} break;
}
/* broadcast this event */
if (g_xge_hal_driver->uld_callbacks.event)
g_xge_hal_driver->uld_callbacks.event(item);
}
if (g_xge_hal_driver->uld_callbacks.before_device_poll) {
if (g_xge_hal_driver->uld_callbacks.before_device_poll(
hldev) != 0) {
hldev->in_poll = 0;
return;
}
}
hstatus = __hal_device_poll(hldev);
if (g_xge_hal_driver->uld_callbacks.after_device_poll)
g_xge_hal_driver->uld_callbacks.after_device_poll(hldev);
/*
* handle critical error right away:
* - walk the device queue again
* - drop non-critical events, if any
* - look for the 1st critical
*/
if (hstatus == XGE_HAL_ERR_CRITICAL) {
queue_has_critical_event = 1;
goto _again;
}
hldev->in_poll = 0;
}
/**
* xge_hal_rts_rth_init - Set enhanced mode for RTS hashing.
* @hldev: HAL device handle.
*
* This function is used to set the adapter to enhanced mode.
*
* See also: xge_hal_rts_rth_clr(), xge_hal_rts_rth_set().
*/
void
xge_hal_rts_rth_init(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
/*
* Set the receive traffic steering mode from default(classic)
* to enhanced.
*/
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->rts_ctrl);
val64 |= XGE_HAL_RTS_CTRL_ENHANCED_MODE;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->rts_ctrl);
}
/**
* xge_hal_rts_rth_clr - Clear RTS hashing.
* @hldev: HAL device handle.
*
* This function is used to clear all RTS hashing related stuff.
* It brings the adapter out from enhanced mode to classic mode.
* It also clears RTS_RTH_CFG register i.e clears hash type, function etc.
*
* See also: xge_hal_rts_rth_set(), xge_hal_rts_rth_itable_set().
*/
void
xge_hal_rts_rth_clr(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
/*
* Set the receive traffic steering mode from default(classic)
* to enhanced.
*/
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->rts_ctrl);
val64 &= ~XGE_HAL_RTS_CTRL_ENHANCED_MODE;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->rts_ctrl);
val64 = 0;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rts_rth_cfg);
}
/**
* xge_hal_rts_rth_set - Set/configure RTS hashing.
* @hldev: HAL device handle.
* @def_q: default queue
* @hash_type: hash type i.e TcpIpV4, TcpIpV6 etc.
* @bucket_size: no of least significant bits to be used for hashing.
*
* Used to set/configure all RTS hashing related stuff.
* - set the steering mode to enhanced.
* - set hash function i.e algo selection.
* - set the default queue.
*
* See also: xge_hal_rts_rth_clr(), xge_hal_rts_rth_itable_set().
*/
void
xge_hal_rts_rth_set(xge_hal_device_t *hldev, u8 def_q, u64 hash_type,
u16 bucket_size)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
val64 = XGE_HAL_RTS_DEFAULT_Q(def_q);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rts_default_q);
val64 = hash_type;
val64 |= XGE_HAL_RTS_RTH_EN;
val64 |= XGE_HAL_RTS_RTH_BUCKET_SIZE(bucket_size);
val64 |= XGE_HAL_RTS_RTH_ALG_SEL_MS;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rts_rth_cfg);
}
/**
* xge_hal_rts_rth_start - Start RTS hashing.
* @hldev: HAL device handle.
*
* Used to Start RTS hashing .
*
* See also: xge_hal_rts_rth_clr(), xge_hal_rts_rth_itable_set(), xge_hal_rts_rth_start.
*/
void
xge_hal_rts_rth_start(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->rts_rth_cfg);
val64 |= XGE_HAL_RTS_RTH_EN;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rts_rth_cfg);
}
/**
* xge_hal_rts_rth_stop - Stop the RTS hashing.
* @hldev: HAL device handle.
*
* Used to Staop RTS hashing .
*
* See also: xge_hal_rts_rth_clr(), xge_hal_rts_rth_itable_set(), xge_hal_rts_rth_start.
*/
void
xge_hal_rts_rth_stop(xge_hal_device_t *hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->rts_rth_cfg);
val64 &= ~XGE_HAL_RTS_RTH_EN;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rts_rth_cfg);
}
/**
* xge_hal_rts_rth_itable_set - Set/configure indirection table (IT).
* @hldev: HAL device handle.
* @itable: Pointer to the indirection table
* @itable_size: no of least significant bits to be used for hashing
*
* Used to set/configure indirection table.
* It enables the required no of entries in the IT.
* It adds entries to the IT.
*
* See also: xge_hal_rts_rth_clr(), xge_hal_rts_rth_set().
*/
xge_hal_status_e
xge_hal_rts_rth_itable_set(xge_hal_device_t *hldev, u8 *itable, u32 itable_size)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
u64 val64;
u32 idx;
for (idx = 0; idx < itable_size; idx++) {
val64 = XGE_HAL_RTS_RTH_MAP_MEM_DATA_ENTRY_EN |
XGE_HAL_RTS_RTH_MAP_MEM_DATA(itable[idx]);
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rts_rth_map_mem_data);
/* execute */
val64 = (XGE_HAL_RTS_RTH_MAP_MEM_CTRL_WE |
XGE_HAL_RTS_RTH_MAP_MEM_CTRL_STROBE |
XGE_HAL_RTS_RTH_MAP_MEM_CTRL_OFFSET(idx));
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rts_rth_map_mem_ctrl);
/* poll until done */
if (__hal_device_register_poll(hldev,
&bar0->rts_rth_map_mem_ctrl, 0,
XGE_HAL_RTS_RTH_MAP_MEM_CTRL_STROBE,
XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK) {
/* upper layer may require to repeat */
return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
}
}
return XGE_HAL_OK;
}
/**
* xge_hal_device_rts_rth_key_set - Configure 40byte secret for hash calc.
*
* @hldev: HAL device handle.
* @KeySize: Number of 64-bit words
* @Key: upto 40-byte array of 8-bit values
* This function configures the 40-byte secret which is used for hash
* calculation.
*
* See also: xge_hal_rts_rth_clr(), xge_hal_rts_rth_set().
*/
void
xge_hal_device_rts_rth_key_set(xge_hal_device_t *hldev, u8 KeySize, u8 *Key)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *) hldev->bar0;
u64 val64;
u32 entry, nreg, i;
entry = 0;
nreg = 0;
while( KeySize ) {
val64 = 0;
for ( i = 0; i < 8 ; i++) {
/* Prepare 64-bit word for 'nreg' containing 8 keys. */
if (i)
val64 <<= 8;
val64 |= Key[entry++];
}
KeySize--;
/* temp64 = XGE_HAL_RTH_HASH_MASK_n(val64, (n<<3), (n<<3)+7);*/
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rts_rth_hash_mask[nreg++]);
}
while( nreg < 5 ) {
/* Clear the rest if key is less than 40 bytes */
val64 = 0;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->rts_rth_hash_mask[nreg++]);
}
}
/**
* xge_hal_device_is_closed - Device is closed
*
* @devh: HAL device handle.
*/
int
xge_hal_device_is_closed(xge_hal_device_h devh)
{
xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
if (xge_list_is_empty(&hldev->fifo_channels) &&
xge_list_is_empty(&hldev->ring_channels))
return 1;
return 0;
}
xge_hal_status_e
xge_hal_device_rts_section_enable(xge_hal_device_h devh, int index)
{
u64 val64;
int section;
int max_addr = XGE_HAL_MAX_MAC_ADDRESSES;
xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)(void *)hldev->bar0;
if (xge_hal_device_check_id(hldev) == XGE_HAL_CARD_HERC)
max_addr = XGE_HAL_MAX_MAC_ADDRESSES_HERC;
if ( index >= max_addr )
return XGE_HAL_ERR_OUT_OF_MAC_ADDRESSES;
/*
* Calculate the section value
*/
section = index / 32;
xge_debug_device(XGE_TRACE, "the Section value is %d ", section);
val64 = xge_os_pio_mem_read64(hldev->pdev, hldev->regh0,
&bar0->rts_mac_cfg);
switch(section)
{
case 0:
val64 |= XGE_HAL_RTS_MAC_SECT0_EN;
break;
case 1:
val64 |= XGE_HAL_RTS_MAC_SECT1_EN;
break;
case 2:
val64 |= XGE_HAL_RTS_MAC_SECT2_EN;
break;
case 3:
val64 |= XGE_HAL_RTS_MAC_SECT3_EN;
break;
case 4:
val64 |= XGE_HAL_RTS_MAC_SECT4_EN;
break;
case 5:
val64 |= XGE_HAL_RTS_MAC_SECT5_EN;
break;
case 6:
val64 |= XGE_HAL_RTS_MAC_SECT6_EN;
break;
case 7:
val64 |= XGE_HAL_RTS_MAC_SECT7_EN;
break;
default:
xge_debug_device(XGE_ERR, "Invalid Section value %d "
, section);
}
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0,
val64, &bar0->rts_mac_cfg);
return XGE_HAL_OK;
}
/**
* xge_hal_fix_rldram_ecc_error
* @hldev: private member of the device structure.
*
* SXE-02-010. This function will turn OFF the ECC error reporting for the
* interface bet'n external Micron RLDRAM II device and memory controller.
* The error would have been reported in RLD_ECC_DB_ERR_L and RLD_ECC_DB_ERR_U
* fields of MC_ERR_REG register. Issue reported by HP-Unix folks during the
* qualification of Herc.
*/
xge_hal_status_e
xge_hal_fix_rldram_ecc_error(xge_hal_device_t * hldev)
{
xge_hal_pci_bar0_t *bar0 = (xge_hal_pci_bar0_t *)hldev->bar0;
u64 val64;
// Enter Test Mode.
val64 = XGE_HAL_MC_RLDRAM_TEST_MODE;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->mc_rldram_test_ctrl);
// Enable fg/bg tests.
val64 = 0x0100000000000000ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->mc_driver);
// Enable RLDRAM configuration.
val64 = 0x0000000000017B00ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->mc_rldram_mrs);
// Enable RLDRAM queues.
val64 = 0x0000000001017B00ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->mc_rldram_mrs);
// Setup test ranges
val64 = 0x00000000001E0100ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->mc_rldram_test_add);
val64 = 0x00000100001F0100ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->mc_rldram_test_add_bkg);
// Start Reads.
val64 = 0x0001000000010000ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->mc_rldram_test_ctrl);
if (__hal_device_register_poll(hldev, &bar0->mc_rldram_test_ctrl, 1,
XGE_HAL_MC_RLDRAM_TEST_DONE,
XGE_HAL_DEVICE_CMDMEM_WAIT_MAX_MILLIS) != XGE_HAL_OK){
return XGE_HAL_INF_MEM_STROBE_CMD_EXECUTING;
}
// Exit test mode
val64 = 0x0000000000000000ULL;
xge_os_pio_mem_write64(hldev->pdev, hldev->regh0, val64,
&bar0->mc_rldram_test_ctrl);
return XGE_HAL_OK;
}