/*- * 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 #include #include #include #include #include #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; iconfig.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; iconfig.fifo.queue[i].configured) continue; for (j=0; jconfig.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; ibimodal_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; iconfig.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; iconfig.fifo.queue[i].configured) continue; for (j=0; jconfig.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; iwl_cnt = iwl_cnt; /* just to remove the lint warning */ /* * 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; iconfig.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; iconfig.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; iconfig.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 == 0 ) 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 ouput 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; }