diff options
Diffstat (limited to 'drivers/net/vxge')
-rw-r--r-- | drivers/net/vxge/Makefile | 7 | ||||
-rw-r--r-- | drivers/net/vxge/vxge-config.c | 5264 | ||||
-rw-r--r-- | drivers/net/vxge/vxge-config.h | 2259 | ||||
-rw-r--r-- | drivers/net/vxge/vxge-ethtool.c | 1148 | ||||
-rw-r--r-- | drivers/net/vxge/vxge-ethtool.h | 67 | ||||
-rw-r--r-- | drivers/net/vxge/vxge-main.c | 4502 | ||||
-rw-r--r-- | drivers/net/vxge/vxge-main.h | 557 | ||||
-rw-r--r-- | drivers/net/vxge/vxge-reg.h | 4608 | ||||
-rw-r--r-- | drivers/net/vxge/vxge-traffic.c | 2528 | ||||
-rw-r--r-- | drivers/net/vxge/vxge-traffic.h | 2409 | ||||
-rw-r--r-- | drivers/net/vxge/vxge-version.h | 23 |
11 files changed, 23372 insertions, 0 deletions
diff --git a/drivers/net/vxge/Makefile b/drivers/net/vxge/Makefile new file mode 100644 index 00000000000..8992ca26b27 --- /dev/null +++ b/drivers/net/vxge/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for Neterion Inc's X3100 Series 10 GbE PCIe # I/O +# Virtualized Server Adapter linux driver + +obj-$(CONFIG_VXGE) += vxge.o + +vxge-objs := vxge-config.o vxge-traffic.o vxge-ethtool.o vxge-main.o diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c new file mode 100644 index 00000000000..6b41c884a33 --- /dev/null +++ b/drivers/net/vxge/vxge-config.c @@ -0,0 +1,5264 @@ +/****************************************************************************** + * This software may be used and distributed according to the terms of + * the GNU General Public License (GPL), incorporated herein by reference. + * Drivers based on or derived from this code fall under the GPL and must + * retain the authorship, copyright and license notice. This file is not + * a complete program and may only be used when the entire operating + * system is licensed under the GPL. + * See the file COPYING in this distribution for more information. + * + * vxge-config.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O + * Virtualized Server Adapter. + * Copyright(c) 2002-2009 Neterion Inc. + ******************************************************************************/ +#include <linux/vmalloc.h> +#include <linux/etherdevice.h> +#include <linux/pci.h> +#include <linux/pci_hotplug.h> + +#include "vxge-traffic.h" +#include "vxge-config.h" + +/* + * __vxge_hw_channel_allocate - Allocate memory for channel + * This function allocates required memory for the channel and various arrays + * in the channel + */ +struct __vxge_hw_channel* +__vxge_hw_channel_allocate(struct __vxge_hw_vpath_handle *vph, + enum __vxge_hw_channel_type type, + u32 length, u32 per_dtr_space, void *userdata) +{ + struct __vxge_hw_channel *channel; + struct __vxge_hw_device *hldev; + int size = 0; + u32 vp_id; + + hldev = vph->vpath->hldev; + vp_id = vph->vpath->vp_id; + + switch (type) { + case VXGE_HW_CHANNEL_TYPE_FIFO: + size = sizeof(struct __vxge_hw_fifo); + break; + case VXGE_HW_CHANNEL_TYPE_RING: + size = sizeof(struct __vxge_hw_ring); + break; + default: + break; + } + + channel = kzalloc(size, GFP_KERNEL); + if (channel == NULL) + goto exit0; + INIT_LIST_HEAD(&channel->item); + + channel->common_reg = hldev->common_reg; + channel->first_vp_id = hldev->first_vp_id; + channel->type = type; + channel->devh = hldev; + channel->vph = vph; + channel->userdata = userdata; + channel->per_dtr_space = per_dtr_space; + channel->length = length; + channel->vp_id = vp_id; + + channel->work_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL); + if (channel->work_arr == NULL) + goto exit1; + + channel->free_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL); + if (channel->free_arr == NULL) + goto exit1; + channel->free_ptr = length; + + channel->reserve_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL); + if (channel->reserve_arr == NULL) + goto exit1; + channel->reserve_ptr = length; + channel->reserve_top = 0; + + channel->orig_arr = kzalloc(sizeof(void *)*length, GFP_KERNEL); + if (channel->orig_arr == NULL) + goto exit1; + + return channel; +exit1: + __vxge_hw_channel_free(channel); + +exit0: + return NULL; +} + +/* + * __vxge_hw_channel_free - Free memory allocated for channel + * This function deallocates memory from the channel and various arrays + * in the channel + */ +void __vxge_hw_channel_free(struct __vxge_hw_channel *channel) +{ + kfree(channel->work_arr); + kfree(channel->free_arr); + kfree(channel->reserve_arr); + kfree(channel->orig_arr); + kfree(channel); +} + +/* + * __vxge_hw_channel_initialize - Initialize a channel + * This function initializes a channel by properly setting the + * various references + */ +enum vxge_hw_status +__vxge_hw_channel_initialize(struct __vxge_hw_channel *channel) +{ + u32 i; + struct __vxge_hw_virtualpath *vpath; + + vpath = channel->vph->vpath; + + if ((channel->reserve_arr != NULL) && (channel->orig_arr != NULL)) { + for (i = 0; i < channel->length; i++) + channel->orig_arr[i] = channel->reserve_arr[i]; + } + + switch (channel->type) { + case VXGE_HW_CHANNEL_TYPE_FIFO: + vpath->fifoh = (struct __vxge_hw_fifo *)channel; + channel->stats = &((struct __vxge_hw_fifo *) + channel)->stats->common_stats; + break; + case VXGE_HW_CHANNEL_TYPE_RING: + vpath->ringh = (struct __vxge_hw_ring *)channel; + channel->stats = &((struct __vxge_hw_ring *) + channel)->stats->common_stats; + break; + default: + break; + } + + return VXGE_HW_OK; +} + +/* + * __vxge_hw_channel_reset - Resets a channel + * This function resets a channel by properly setting the various references + */ +enum vxge_hw_status +__vxge_hw_channel_reset(struct __vxge_hw_channel *channel) +{ + u32 i; + + for (i = 0; i < channel->length; i++) { + if (channel->reserve_arr != NULL) + channel->reserve_arr[i] = channel->orig_arr[i]; + if (channel->free_arr != NULL) + channel->free_arr[i] = NULL; + if (channel->work_arr != NULL) + channel->work_arr[i] = NULL; + } + channel->free_ptr = channel->length; + channel->reserve_ptr = channel->length; + channel->reserve_top = 0; + channel->post_index = 0; + channel->compl_index = 0; + + return VXGE_HW_OK; +} + +/* + * __vxge_hw_device_pci_e_init + * Initialize certain PCI/PCI-X configuration registers + * with recommended values. Save config space for future hw resets. + */ +void +__vxge_hw_device_pci_e_init(struct __vxge_hw_device *hldev) +{ + u16 cmd = 0; + + /* Set the PErr Repconse bit and SERR in PCI command register. */ + pci_read_config_word(hldev->pdev, PCI_COMMAND, &cmd); + cmd |= 0x140; + pci_write_config_word(hldev->pdev, PCI_COMMAND, cmd); + + pci_save_state(hldev->pdev); + + return; +} + +/* + * __vxge_hw_device_register_poll + * Will poll certain register for specified amount of time. + * Will poll until masked bit is not cleared. + */ +enum vxge_hw_status +__vxge_hw_device_register_poll(void __iomem *reg, u64 mask, u32 max_millis) +{ + u64 val64; + u32 i = 0; + enum vxge_hw_status ret = VXGE_HW_FAIL; + + udelay(10); + + do { + val64 = readq(reg); + if (!(val64 & mask)) + return VXGE_HW_OK; + udelay(100); + } while (++i <= 9); + + i = 0; + do { + val64 = readq(reg); + if (!(val64 & mask)) + return VXGE_HW_OK; + mdelay(1); + } while (++i <= max_millis); + + return ret; +} + + /* __vxge_hw_device_vpath_reset_in_prog_check - Check if vpath reset + * in progress + * This routine checks the vpath reset in progress register is turned zero + */ +enum vxge_hw_status +__vxge_hw_device_vpath_reset_in_prog_check(u64 __iomem *vpath_rst_in_prog) +{ + enum vxge_hw_status status; + status = __vxge_hw_device_register_poll(vpath_rst_in_prog, + VXGE_HW_VPATH_RST_IN_PROG_VPATH_RST_IN_PROG(0x1ffff), + VXGE_HW_DEF_DEVICE_POLL_MILLIS); + return status; +} + +/* + * __vxge_hw_device_toc_get + * This routine sets the swapper and reads the toc pointer and returns the + * memory mapped address of the toc + */ +struct vxge_hw_toc_reg __iomem * +__vxge_hw_device_toc_get(void __iomem *bar0) +{ + u64 val64; + struct vxge_hw_toc_reg __iomem *toc = NULL; + enum vxge_hw_status status; + + struct vxge_hw_legacy_reg __iomem *legacy_reg = + (struct vxge_hw_legacy_reg __iomem *)bar0; + + status = __vxge_hw_legacy_swapper_set(legacy_reg); + if (status != VXGE_HW_OK) + goto exit; + + val64 = readq(&legacy_reg->toc_first_pointer); + toc = (struct vxge_hw_toc_reg __iomem *)(bar0+val64); +exit: + return toc; +} + +/* + * __vxge_hw_device_reg_addr_get + * This routine sets the swapper and reads the toc pointer and initializes the + * register location pointers in the device object. It waits until the ric is + * completed initializing registers. + */ +enum vxge_hw_status +__vxge_hw_device_reg_addr_get(struct __vxge_hw_device *hldev) +{ + u64 val64; + u32 i; + enum vxge_hw_status status = VXGE_HW_OK; + + hldev->legacy_reg = (struct vxge_hw_legacy_reg __iomem *)hldev->bar0; + + hldev->toc_reg = __vxge_hw_device_toc_get(hldev->bar0); + if (hldev->toc_reg == NULL) { + status = VXGE_HW_FAIL; + goto exit; + } + + val64 = readq(&hldev->toc_reg->toc_common_pointer); + hldev->common_reg = + (struct vxge_hw_common_reg __iomem *)(hldev->bar0 + val64); + + val64 = readq(&hldev->toc_reg->toc_mrpcim_pointer); + hldev->mrpcim_reg = + (struct vxge_hw_mrpcim_reg __iomem *)(hldev->bar0 + val64); + + for (i = 0; i < VXGE_HW_TITAN_SRPCIM_REG_SPACES; i++) { + val64 = readq(&hldev->toc_reg->toc_srpcim_pointer[i]); + hldev->srpcim_reg[i] = + (struct vxge_hw_srpcim_reg __iomem *) + (hldev->bar0 + val64); + } + + for (i = 0; i < VXGE_HW_TITAN_VPMGMT_REG_SPACES; i++) { + val64 = readq(&hldev->toc_reg->toc_vpmgmt_pointer[i]); + hldev->vpmgmt_reg[i] = + (struct vxge_hw_vpmgmt_reg __iomem *)(hldev->bar0 + val64); + } + + for (i = 0; i < VXGE_HW_TITAN_VPATH_REG_SPACES; i++) { + val64 = readq(&hldev->toc_reg->toc_vpath_pointer[i]); + hldev->vpath_reg[i] = + (struct vxge_hw_vpath_reg __iomem *) + (hldev->bar0 + val64); + } + + val64 = readq(&hldev->toc_reg->toc_kdfc); + + switch (VXGE_HW_TOC_GET_KDFC_INITIAL_BIR(val64)) { + case 0: + hldev->kdfc = (u8 __iomem *)(hldev->bar0 + + VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64)); + break; + case 2: + hldev->kdfc = (u8 __iomem *)(hldev->bar1 + + VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64)); + break; + case 4: + hldev->kdfc = (u8 __iomem *)(hldev->bar2 + + VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64)); + break; + default: + break; + } + + status = __vxge_hw_device_vpath_reset_in_prog_check( + (u64 __iomem *)&hldev->common_reg->vpath_rst_in_prog); +exit: + return status; +} + +/* + * __vxge_hw_device_id_get + * This routine returns sets the device id and revision numbers into the device + * structure + */ +void __vxge_hw_device_id_get(struct __vxge_hw_device *hldev) +{ + u64 val64; + + val64 = readq(&hldev->common_reg->titan_asic_id); + hldev->device_id = + (u16)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_DEVICE_ID(val64); + + hldev->major_revision = + (u8)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MAJOR_REVISION(val64); + + hldev->minor_revision = + (u8)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MINOR_REVISION(val64); + + return; +} + +/* + * __vxge_hw_device_access_rights_get: Get Access Rights of the driver + * This routine returns the Access Rights of the driver + */ +static u32 +__vxge_hw_device_access_rights_get(u32 host_type, u32 func_id) +{ + u32 access_rights = VXGE_HW_DEVICE_ACCESS_RIGHT_VPATH; + + switch (host_type) { + case VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION: + if (func_id == 0) { + access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM | + VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM; + } + break; + case VXGE_HW_MR_NO_SR_VH0_BASE_FUNCTION: + access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM | + VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM; + break; + case VXGE_HW_NO_MR_SR_VH0_FUNCTION0: + access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM | + VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM; + break; + case VXGE_HW_NO_MR_SR_VH0_VIRTUAL_FUNCTION: + case VXGE_HW_SR_VH_VIRTUAL_FUNCTION: + case VXGE_HW_MR_SR_VH0_INVALID_CONFIG: + break; + case VXGE_HW_SR_VH_FUNCTION0: + case VXGE_HW_VH_NORMAL_FUNCTION: + access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM; + break; + } + + return access_rights; +} +/* + * __vxge_hw_device_host_info_get + * This routine returns the host type assignments + */ +void __vxge_hw_device_host_info_get(struct __vxge_hw_device *hldev) +{ + u64 val64; + u32 i; + + val64 = readq(&hldev->common_reg->host_type_assignments); + + hldev->host_type = + (u32)VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(val64); + + hldev->vpath_assignments = readq(&hldev->common_reg->vpath_assignments); + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!(hldev->vpath_assignments & vxge_mBIT(i))) + continue; + + hldev->func_id = + __vxge_hw_vpath_func_id_get(i, hldev->vpmgmt_reg[i]); + + hldev->access_rights = __vxge_hw_device_access_rights_get( + hldev->host_type, hldev->func_id); + + hldev->first_vp_id = i; + break; + } + + return; +} + +/* + * __vxge_hw_verify_pci_e_info - Validate the pci-e link parameters such as + * link width and signalling rate. + */ +static enum vxge_hw_status +__vxge_hw_verify_pci_e_info(struct __vxge_hw_device *hldev) +{ + int exp_cap; + u16 lnk; + + /* Get the negotiated link width and speed from PCI config space */ + exp_cap = pci_find_capability(hldev->pdev, PCI_CAP_ID_EXP); + pci_read_config_word(hldev->pdev, exp_cap + PCI_EXP_LNKSTA, &lnk); + + if ((lnk & PCI_EXP_LNKSTA_CLS) != 1) + return VXGE_HW_ERR_INVALID_PCI_INFO; + + switch ((lnk & PCI_EXP_LNKSTA_NLW) >> 4) { + case PCIE_LNK_WIDTH_RESRV: + case PCIE_LNK_X1: + case PCIE_LNK_X2: + case PCIE_LNK_X4: + case PCIE_LNK_X8: + break; + default: + return VXGE_HW_ERR_INVALID_PCI_INFO; + } + + return VXGE_HW_OK; +} + +static enum vxge_hw_status +__vxge_hw_device_is_privilaged(struct __vxge_hw_device *hldev) +{ + if ((hldev->host_type == VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION || + hldev->host_type == VXGE_HW_MR_NO_SR_VH0_BASE_FUNCTION || + hldev->host_type == VXGE_HW_NO_MR_SR_VH0_FUNCTION0) && + (hldev->func_id == 0)) + return VXGE_HW_OK; + else + return VXGE_HW_ERR_PRIVILAGED_OPEARATION; +} + +/* + * vxge_hw_wrr_rebalance - Rebalance the RX_WRR and KDFC_WRR calandars. + * Rebalance the RX_WRR and KDFC_WRR calandars. + */ +static enum +vxge_hw_status vxge_hw_wrr_rebalance(struct __vxge_hw_device *hldev) +{ + u64 val64; + u32 wrr_states[VXGE_HW_WEIGHTED_RR_SERVICE_STATES]; + u32 i, j, how_often = 1; + enum vxge_hw_status status = VXGE_HW_OK; + + status = __vxge_hw_device_is_privilaged(hldev); + if (status != VXGE_HW_OK) + goto exit; + + /* Reset the priorities assigned to the WRR arbitration + phases for the receive traffic */ + for (i = 0; i < VXGE_HW_WRR_RING_COUNT; i++) + writeq(0, ((&hldev->mrpcim_reg->rx_w_round_robin_0) + i)); + + /* Reset the transmit FIFO servicing calendar for FIFOs */ + for (i = 0; i < VXGE_HW_WRR_FIFO_COUNT; i++) { + writeq(0, ((&hldev->mrpcim_reg->kdfc_w_round_robin_0) + i)); + writeq(0, ((&hldev->mrpcim_reg->kdfc_w_round_robin_20) + i)); + } + + /* Assign WRR priority 0 for all FIFOs */ + for (i = 1; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + writeq(VXGE_HW_KDFC_FIFO_0_CTRL_WRR_NUMBER(0), + ((&hldev->mrpcim_reg->kdfc_fifo_0_ctrl) + i)); + + writeq(VXGE_HW_KDFC_FIFO_17_CTRL_WRR_NUMBER(0), + ((&hldev->mrpcim_reg->kdfc_fifo_17_ctrl) + i)); + } + + /* Reset to service non-offload doorbells */ + writeq(0, &hldev->mrpcim_reg->kdfc_entry_type_sel_0); + writeq(0, &hldev->mrpcim_reg->kdfc_entry_type_sel_1); + + /* Set priority 0 to all receive queues */ + writeq(0, &hldev->mrpcim_reg->rx_queue_priority_0); + writeq(0, &hldev->mrpcim_reg->rx_queue_priority_1); + writeq(0, &hldev->mrpcim_reg->rx_queue_priority_2); + + /* Initialize all the slots as unused */ + for (i = 0; i < VXGE_HW_WEIGHTED_RR_SERVICE_STATES; i++) + wrr_states[i] = -1; + + /* Prepare the Fifo service states */ + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!hldev->config.vp_config[i].min_bandwidth) + continue; + + how_often = VXGE_HW_VPATH_BANDWIDTH_MAX / + hldev->config.vp_config[i].min_bandwidth; + if (how_often) { + + for (j = 0; j < VXGE_HW_WRR_FIFO_SERVICE_STATES;) { + if (wrr_states[j] == -1) { + wrr_states[j] = i; + /* Make sure each fifo is serviced + * atleast once */ + if (i == j) + j += VXGE_HW_MAX_VIRTUAL_PATHS; + else + j += how_often; + } else + j++; + } + } + } + + /* Fill the unused slots with 0 */ + for (j = 0; j < VXGE_HW_WEIGHTED_RR_SERVICE_STATES; j++) { + if (wrr_states[j] == -1) + wrr_states[j] = 0; + } + + /* Assign WRR priority number for FIFOs */ + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + writeq(VXGE_HW_KDFC_FIFO_0_CTRL_WRR_NUMBER(i), + ((&hldev->mrpcim_reg->kdfc_fifo_0_ctrl) + i)); + + writeq(VXGE_HW_KDFC_FIFO_17_CTRL_WRR_NUMBER(i), + ((&hldev->mrpcim_reg->kdfc_fifo_17_ctrl) + i)); + } + + /* Modify the servicing algorithm applied to the 3 types of doorbells. + i.e, none-offload, message and offload */ + writeq(VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_0(0) | + VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_1(0) | + VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_2(0) | + VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_3(0) | + VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_4(1) | + VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_5(0) | + VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_6(0) | + VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_7(0), + &hldev->mrpcim_reg->kdfc_entry_type_sel_0); + + writeq(VXGE_HW_KDFC_ENTRY_TYPE_SEL_1_NUMBER_8(1), + &hldev->mrpcim_reg->kdfc_entry_type_sel_1); + + for (i = 0, j = 0; i < VXGE_HW_WRR_FIFO_COUNT; i++) { + + val64 = VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_0(wrr_states[j++]); + val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_1(wrr_states[j++]); + val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_2(wrr_states[j++]); + val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_3(wrr_states[j++]); + val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_4(wrr_states[j++]); + val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_5(wrr_states[j++]); + val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_6(wrr_states[j++]); + val64 |= VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_7(wrr_states[j++]); + + writeq(val64, (&hldev->mrpcim_reg->kdfc_w_round_robin_0 + i)); + writeq(val64, (&hldev->mrpcim_reg->kdfc_w_round_robin_20 + i)); + } + + /* Set up the priorities assigned to receive queues */ + writeq(VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_0(0) | + VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_1(1) | + VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_2(2) | + VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_3(3) | + VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_4(4) | + VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_5(5) | + VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_6(6) | + VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_7(7), + &hldev->mrpcim_reg->rx_queue_priority_0); + + writeq(VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_8(8) | + VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_9(9) | + VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_10(10) | + VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_11(11) | + VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_12(12) | + VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_13(13) | + VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_14(14) | + VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_15(15), + &hldev->mrpcim_reg->rx_queue_priority_1); + + writeq(VXGE_HW_RX_QUEUE_PRIORITY_2_RX_Q_NUMBER_16(16), + &hldev->mrpcim_reg->rx_queue_priority_2); + + /* Initialize all the slots as unused */ + for (i = 0; i < VXGE_HW_WEIGHTED_RR_SERVICE_STATES; i++) + wrr_states[i] = -1; + + /* Prepare the Ring service states */ + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!hldev->config.vp_config[i].min_bandwidth) + continue; + + how_often = VXGE_HW_VPATH_BANDWIDTH_MAX / + hldev->config.vp_config[i].min_bandwidth; + + if (how_often) { + for (j = 0; j < VXGE_HW_WRR_RING_SERVICE_STATES;) { + if (wrr_states[j] == -1) { + wrr_states[j] = i; + /* Make sure each ring is + * serviced atleast once */ + if (i == j) + j += VXGE_HW_MAX_VIRTUAL_PATHS; + else + j += how_often; + } else + j++; + } + } + } + + /* Fill the unused slots with 0 */ + for (j = 0; j < VXGE_HW_WEIGHTED_RR_SERVICE_STATES; j++) { + if (wrr_states[j] == -1) + wrr_states[j] = 0; + } + + for (i = 0, j = 0; i < VXGE_HW_WRR_RING_COUNT; i++) { + val64 = VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_0( + wrr_states[j++]); + val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_1( + wrr_states[j++]); + val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_2( + wrr_states[j++]); + val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_3( + wrr_states[j++]); + val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_4( + wrr_states[j++]); + val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_5( + wrr_states[j++]); + val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_6( + wrr_states[j++]); + val64 |= VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_7( + wrr_states[j++]); + + writeq(val64, ((&hldev->mrpcim_reg->rx_w_round_robin_0) + i)); + } +exit: + return status; +} + +/* + * __vxge_hw_device_initialize + * Initialize Titan-V hardware. + */ +enum vxge_hw_status __vxge_hw_device_initialize(struct __vxge_hw_device *hldev) +{ + enum vxge_hw_status status = VXGE_HW_OK; + + /* Validate the pci-e link width and speed */ + status = __vxge_hw_verify_pci_e_info(hldev); + if (status != VXGE_HW_OK) + goto exit; + + vxge_hw_wrr_rebalance(hldev); +exit: + return status; +} + +/** + * vxge_hw_device_hw_info_get - Get the hw information + * Returns the vpath mask that has the bits set for each vpath allocated + * for the driver, FW version information and the first mac addresse for + * each vpath + */ +enum vxge_hw_status __devinit +vxge_hw_device_hw_info_get(void __iomem *bar0, + struct vxge_hw_device_hw_info *hw_info) +{ + u32 i; + u64 val64; + struct vxge_hw_toc_reg __iomem *toc; + struct vxge_hw_mrpcim_reg __iomem *mrpcim_reg; + struct vxge_hw_common_reg __iomem *common_reg; + struct vxge_hw_vpath_reg __iomem *vpath_reg; + struct vxge_hw_vpmgmt_reg __iomem *vpmgmt_reg; + enum vxge_hw_status status; + + memset(hw_info, 0, sizeof(struct vxge_hw_device_hw_info)); + + toc = __vxge_hw_device_toc_get(bar0); + if (toc == NULL) { + status = VXGE_HW_ERR_CRITICAL; + goto exit; + } + + val64 = readq(&toc->toc_common_pointer); + common_reg = (struct vxge_hw_common_reg __iomem *)(bar0 + val64); + + status = __vxge_hw_device_vpath_reset_in_prog_check( + (u64 __iomem *)&common_reg->vpath_rst_in_prog); + if (status != VXGE_HW_OK) + goto exit; + + hw_info->vpath_mask = readq(&common_reg->vpath_assignments); + + val64 = readq(&common_reg->host_type_assignments); + + hw_info->host_type = + (u32)VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(val64); + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!((hw_info->vpath_mask) & vxge_mBIT(i))) + continue; + + val64 = readq(&toc->toc_vpmgmt_pointer[i]); + + vpmgmt_reg = (struct vxge_hw_vpmgmt_reg __iomem *) + (bar0 + val64); + + hw_info->func_id = __vxge_hw_vpath_func_id_get(i, vpmgmt_reg); + if (__vxge_hw_device_access_rights_get(hw_info->host_type, + hw_info->func_id) & + VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM) { + + val64 = readq(&toc->toc_mrpcim_pointer); + + mrpcim_reg = (struct vxge_hw_mrpcim_reg __iomem *) + (bar0 + val64); + + writeq(0, &mrpcim_reg->xgmac_gen_fw_memo_mask); + wmb(); + } + + val64 = readq(&toc->toc_vpath_pointer[i]); + + vpath_reg = (struct vxge_hw_vpath_reg __iomem *)(bar0 + val64); + + hw_info->function_mode = + __vxge_hw_vpath_pci_func_mode_get(i, vpath_reg); + + status = __vxge_hw_vpath_fw_ver_get(i, vpath_reg, hw_info); + if (status != VXGE_HW_OK) + goto exit; + + status = __vxge_hw_vpath_card_info_get(i, vpath_reg, hw_info); + if (status != VXGE_HW_OK) + goto exit; + + break; + } + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!((hw_info->vpath_mask) & vxge_mBIT(i))) + continue; + + val64 = readq(&toc->toc_vpath_pointer[i]); + vpath_reg = (struct vxge_hw_vpath_reg __iomem *)(bar0 + val64); + + status = __vxge_hw_vpath_addr_get(i, vpath_reg, + hw_info->mac_addrs[i], + hw_info->mac_addr_masks[i]); + if (status != VXGE_HW_OK) + goto exit; + } +exit: + return status; +} + +/* + * vxge_hw_device_initialize - Initialize Titan device. + * Initialize Titan device. Note that all the arguments of this public API + * are 'IN', including @hldev. Driver cooperates with + * OS to find new Titan device, locate its PCI and memory spaces. + * + * When done, the driver allocates sizeof(struct __vxge_hw_device) bytes for HW + * to enable the latter to perform Titan hardware initialization. + */ +enum vxge_hw_status __devinit +vxge_hw_device_initialize( + struct __vxge_hw_device **devh, + struct vxge_hw_device_attr *attr, + struct vxge_hw_device_config *device_config) +{ + u32 i; + u32 nblocks = 0; + struct __vxge_hw_device *hldev = NULL; + enum vxge_hw_status status = VXGE_HW_OK; + + status = __vxge_hw_device_config_check(device_config); + if (status != VXGE_HW_OK) + goto exit; + + hldev = (struct __vxge_hw_device *) + vmalloc(sizeof(struct __vxge_hw_device)); + if (hldev == NULL) { + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto exit; + } + + memset(hldev, 0, sizeof(struct __vxge_hw_device)); + hldev->magic = VXGE_HW_DEVICE_MAGIC; + + vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_ALL); + + /* apply config */ + memcpy(&hldev->config, device_config, + sizeof(struct vxge_hw_device_config)); + + hldev->bar0 = attr->bar0; + hldev->bar1 = attr->bar1; + hldev->bar2 = attr->bar2; + hldev->pdev = attr->pdev; + + hldev->uld_callbacks.link_up = attr->uld_callbacks.link_up; + hldev->uld_callbacks.link_down = attr->uld_callbacks.link_down; + hldev->uld_callbacks.crit_err = attr->uld_callbacks.crit_err; + + __vxge_hw_device_pci_e_init(hldev); + + status = __vxge_hw_device_reg_addr_get(hldev); + if (status != VXGE_HW_OK) + goto exit; + __vxge_hw_device_id_get(hldev); + + __vxge_hw_device_host_info_get(hldev); + + /* Incrementing for stats blocks */ + nblocks++; + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!(hldev->vpath_assignments & vxge_mBIT(i))) + continue; + + if (device_config->vp_config[i].ring.enable == + VXGE_HW_RING_ENABLE) + nblocks += device_config->vp_config[i].ring.ring_blocks; + + if (device_config->vp_config[i].fifo.enable == + VXGE_HW_FIFO_ENABLE) + nblocks += device_config->vp_config[i].fifo.fifo_blocks; + nblocks++; + } + + if (__vxge_hw_blockpool_create(hldev, + &hldev->block_pool, + device_config->dma_blockpool_initial + nblocks, + device_config->dma_blockpool_max + nblocks) != VXGE_HW_OK) { + + vxge_hw_device_terminate(hldev); + status = VXGE_HW_ERR_OUT_OF_MEMORY; + goto exit; + } + + status = __vxge_hw_device_initialize(hldev); + + if (status != VXGE_HW_OK) { + vxge_hw_device_terminate(hldev); + goto exit; + } + + *devh = hldev; +exit: + return status; +} + +/* + * vxge_hw_device_terminate - Terminate Titan device. + * Terminate HW device. + */ +void +vxge_hw_device_terminate(struct __vxge_hw_device *hldev) +{ + vxge_assert(hldev->magic == VXGE_HW_DEVICE_MAGIC); + + hldev->magic = VXGE_HW_DEVICE_DEAD; + __vxge_hw_blockpool_destroy(&hldev->block_pool); + vfree(hldev); +} + +/* + * vxge_hw_device_stats_get - Get the device hw statistics. + * Returns the vpath h/w stats for the device. + */ +enum vxge_hw_status +vxge_hw_device_stats_get(struct __vxge_hw_device *hldev, + struct vxge_hw_device_stats_hw_info *hw_stats) +{ + u32 i; + enum vxge_hw_status status = VXGE_HW_OK; + + for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) { + + if (!(hldev->vpaths_deployed & vxge_mBIT(i)) || + (hldev->virtual_paths[i].vp_open == + VXGE_HW_VP_NOT_OPEN)) + continue; + + memcpy(hldev->virtual_paths[i].hw_stats_sav, + hldev->virtual_paths[i].hw_stats, + sizeof(struct vxge_hw_vpath_stats_hw_info)); + + status = __vxge_hw_vpath_stats_get( + &hldev->virtual_paths[i], + hldev->virtual_paths[i].hw_stats); + } + + memcpy(hw_stats, &hldev->stats.hw_dev_info_stats, + sizeof(struct vxge_hw_device_stats_hw_info)); + + return status; +} + +/* + * vxge_hw_driver_stats_get - Get the device sw statistics. + * Returns the vpath s/w stats for the device. + */ +enum vxge_hw_status vxge_hw_driver_stats_get( + struct __vxge_hw_device *hldev, + struct vxge_hw_device_stats_sw_info *sw_stats) +{ + enum vxge_hw_status status = VXGE_HW_OK; + + memcpy(sw_stats, &hldev->stats.sw_dev_info_stats, + sizeof(struct vxge_hw_device_stats_sw_info)); + + return status; +} + +/* + * vxge_hw_mrpcim_stats_access - Access the statistics from the given location + * and offset and perform an operation + * Get the statistics from the given location and offset. + */ +enum vxge_hw_status +vxge_hw_mrpcim_stats_access(struct __vxge_hw_device *hldev, + u32 operation, u32 location, u32 offset, u64 *stat) +{ + u64 val64; + enum vxge_hw_status status = VXGE_HW_OK; + + status = __vxge_hw_device_is_privilaged(hldev); + if (status != VXGE_HW_OK) + goto exit; + + val64 = VXGE_HW_XMAC_STATS_SYS_CMD_OP(operation) | + VXGE_HW_XMAC_STATS_SYS_CMD_STROBE | + VXGE_HW_XMAC_STATS_SYS_CMD_LOC_SEL(location) | + VXGE_HW_XMAC_STATS_SYS_CMD_OFFSET_SEL(offset); + + status = __vxge_hw_pio_mem_write64(val64, + &hldev->mrpcim_reg->xmac_stats_sys_cmd, + VXGE_HW_XMAC_STATS_SYS_CMD_STROBE, + hldev->config.device_poll_millis); + + if ((status == VXGE_HW_OK) && (operation == VXGE_HW_STATS_OP_READ)) + *stat = readq(&hldev->mrpcim_reg->xmac_stats_sys_data); + else + *stat = 0; +exit: + return status; +} + +/* + * vxge_hw_device_xmac_aggr_stats_get - Get the Statistics on aggregate port + * Get the Statistics on aggregate port + */ +enum vxge_hw_status +vxge_hw_device_xmac_aggr_stats_get(struct __vxge_hw_device *hldev, u32 port, + struct vxge_hw_xmac_aggr_stats *aggr_stats) +{ + u64 *val64; + int i; + u32 offset = VXGE_HW_STATS_AGGRn_OFFSET; + enum vxge_hw_status status = VXGE_HW_OK; + + val64 = (u64 *)aggr_stats; + + status = __vxge_hw_device_is_privilaged(hldev); + if (status != VXGE_HW_OK) + goto exit; + + for (i = 0; i < sizeof(struct vxge_hw_xmac_aggr_stats) / 8; i++) { + status = vxge_hw_mrpcim_stats_access(hldev, + VXGE_HW_STATS_OP_READ, + VXGE_HW_STATS_LOC_AGGR, + ((offset + (104 * port)) >> 3), val64); + if (status != VXGE_HW_OK) + goto exit; + + offset += 8; + val64++; + } +exit: + return status; +} + +/* + * vxge_hw_device_xmac_port_stats_get - Get the Statistics on a port + * Get the Statistics on port + */ +enum vxge_hw_status +vxge_hw_device_xmac_port_stats_get(struct __vxge_hw_device *hldev, u32 port, + struct vxge_hw_xmac_port_stats *port_stats) +{ + u64 *val64; + enum vxge_hw_status status = VXGE_HW_OK; + int i; + u32 offset = 0x0; + val64 = (u64 *) port_stats; + + status = __vxge_hw_device_is_privilaged(hldev); + if (status != VXGE_HW_OK) + goto exit; + + for (i = 0; i < sizeof(struct vxge_hw_xmac_port_stats) / 8; i++) { + status = vxge_hw_mrpcim_stats_access(hldev, + VXGE_HW_STATS_OP_READ, + VXGE_HW_STATS_LOC_AGGR, + ((offset + (608 * port)) >> 3), val64); + if (status != VXGE_HW_OK) + goto exit; + + offset += 8; + val64++; + } + +exit: + return status; +} + +/* + * vxge_hw_device_xmac_stats_get - Get the XMAC Statistics + * Get the XMAC Statistics + */ +enum vxge_hw_status +vxge_hw_device_xmac_stats_get(struct __vxge_hw_device *hldev, + struct vxge_hw_xmac_stats *xmac_stats) +{ + enum vxge_hw_status status = VXGE_HW_OK; + u32 i; + + status = vxge_hw_device_xmac_aggr_stats_get(hldev, + 0, &xmac_stats->aggr_stats[0]); + + if (status != VXGE_HW_OK) + goto exit; + + status = vxge |