Neterion: New driver: Hardware init & configuration
Subsystems (2)
PATCH 6/10 Neterion: New driver: Hardware init & configuration
This patch takes care of Initialization and configuration steps of Neterion Inc's X3100 Series 10GbE PCIe I/O Virtualized Server Adapter.
- Device Initialization.
- Verification and setting of device config parameters.
- Allocation of Tx FIFO and Rx Ring descriptors (DTR).
- APIs to get various type of hw stats
- APIs to configure RTS (Receive Traffic Steering)
---
drivers/net/vxge/vxge-config.c +7576 -0
@@ -0,0 +1,7576 @@ +/****************************************************************************** +* 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/version.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/pci.h> +#include <linux/delay.h> + +#include "vxge-traffic.h" +#include "vxge-config.h" + +/* +* __hw_channel_allocate - Allocate memory for channel +* @devh: Handle to the device object +* @vph: Handle to Virtual Path +* @type: Type of channel +* @length: Lengths of arrays +* @alloc_work_array: Flag to specify if work array is required +* @alloc_free_array: Flag to specify if free array is required +* @alloc_reserve_array: Flag to specify if reserve array is required +* @per_dtr_space: driver requested per dtr space to be allocated in priv +* @userdata: User data to be passed back in the callback +* +* This function allocates required memory for the channel and various arrays +* in the channel +*/ +struct __hw_channel * +__hw_channel_allocate ( +struct __hw_device *hldev, +struct __hw_vpath_handle *vph, +enum __hw_channel_type type, +u32 length, +u32 alloc_work_array, +u32 alloc_free_array, +u32 alloc_reserve_array, +u32 per_dtr_space, +void *userdata) +{ +struct __hw_channel *channel; +int size =0 ; +u32 vp_id; + +vxge_assert ((hldev !=NULL ) && (vph !=NULL )); + + vp_id = ((struct __hw_vpath_handle *)vph)->vpath->vp_id; + +switch (type) { +case VXGE_HW_CHANNEL_TYPE_FIFO : + size =sizeof (struct __hw_fifo ); +break ; +case VXGE_HW_CHANNEL_TYPE_RING : + size =sizeof (struct __hw_ring ); +break ; +default : +vxge_assert (size); +break ; + + } + + channel = (struct __hw_channel *)vmalloc (size); +if (channel ==NULL ) + goto exit0; +memset (channel,0 , size); +vxge_list_init (&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; + +if (alloc_work_array) { + channel->work_arr = (void **)vmalloc (sizeof (void *)*length); +if (channel->work_arr ==NULL ) + goto exit1; +memset (channel->work_arr,0 ,sizeof (void *)*length); + } + + channel->post_index =0 ; + channel->compl_index =0 ; + +if (alloc_free_array) { + channel->free_arr = (void **)vmalloc (sizeof (void *)*length); +if (channel->free_arr ==NULL ) + goto exit1; +memset (channel->free_arr,0 ,sizeof (void *)*length); + } + + channel->free_ptr = length; + +if (alloc_reserve_array) { + channel->reserve_arr = + (void **)vmalloc (sizeof (void *)*length); +if (channel->reserve_arr ==NULL ) + goto exit1; + +memset (channel->reserve_arr,0 ,sizeof (void *)*length); + } + + channel->reserve_ptr = length; + channel->reserve_top =0 ; + +if (alloc_reserve_array) { + channel->orig_arr = (void **)vmalloc (sizeof (void *) * length); +if (channel->orig_arr ==NULL ) + goto exit1; + +memset (channel->orig_arr,0 ,sizeof (void *)*length); + } + + channel->level_err =vxge_hw_device_error_level_get (hldev); + channel->level_trace =vxge_hw_device_trace_level_get (hldev); + +return channel; +exit1: +__hw_channel_free (channel); + +exit0: + +return NULL ; +} + +/* +* __hw_channel_free - Free memory allocated for channel +* @channel: channel to be freed +* +* This function deallocates memory from the channel and various arrays +* in the channel +*/ +void +__hw_channel_free ( +struct __hw_channel *channel) +{ +u32 vp_id =0 ; +struct __hw_device *hldev; + +vxge_assert (channel !=NULL ); + + hldev = (struct __hw_device *)channel->devh; + + vp_id = ((struct __hw_vpath_handle *)channel->vph)->vpath->vp_id; + +if (channel->work_arr) { +vfree (channel->work_arr); + channel->work_arr =NULL ; + } + +if (channel->free_arr) { +vfree (channel->free_arr); + channel->free_arr =NULL ; + } + +if (channel->reserve_arr) { +vfree (channel->reserve_arr); + channel->reserve_arr =NULL ; + } + +if (channel->orig_arr) { +vfree (channel->orig_arr); + channel->orig_arr =NULL ; + } + +vfree (channel); + +} + +/* +* __hw_channel_initialize - Initialize a channel +* @channel: channel to be initialized +* +* This function initializes a channel by properly setting the +* various references +*/ +enum vxge_hw_status +__hw_channel_initialize ( +struct __hw_channel *channel) +{ +u32 i; +struct __hw_virtualpath *vpath; + +vxge_assert (channel !=NULL ); + + vpath = (struct __hw_virtualpath *)((struct __hw_vpath_handle *) \ + channel->vph)->vpath; +vxge_assert (vpath !=NULL ); + +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 __hw_fifo *)channel; + channel->stats = &((struct __hw_fifo *) \ + channel)->stats->common_stats; +break ; +case VXGE_HW_CHANNEL_TYPE_RING : + vpath->ringh = (struct __hw_ring *)channel; + channel->stats = &((struct __hw_ring *) \ + channel)->stats->common_stats; +break ; +default : +break ; + } + +return VXGE_HW_OK ; +} + +/* +* __hw_channel_reset - Resets a channel +* @channel: channel to be reset +* +* This function resets a channel by properly setting the various references +*/ +enum vxge_hw_status +__hw_channel_reset ( +struct __hw_channel *channel) +{ +u32 i; +struct __hw_device *hldev; + +vxge_assert (channel !=NULL ); + + hldev = (struct __hw_device *)channel->devh; + +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 ; +} + +/* +* __hw_device_pci_caps_list_process +* @hldev: HW device handle. +* +* Process PCI capabilities and initialize the offsets +*/ +void +__hw_device_pci_caps_list_process (struct __hw_device *hldev) +{ +u8 cap_id; +u16 next_ptr; +struct vxge_hw_pci_config *pci_config = &hldev->pci_config_space_bios; + +vxge_assert (hldev !=NULL ); + + next_ptr = pci_config->capabilities_pointer; + +while (next_ptr !=0 ) { + + cap_id =VXGE_HW_PCI_CAP_ID ((((u8 *)pci_config) + next_ptr)); + +switch (cap_id) { + +case VXGE_HW_PCI_CAP_ID_PM : + hldev->pci_caps.pm_cap_offset = next_ptr; +break ; +case VXGE_HW_PCI_CAP_ID_VPD : + hldev->pci_caps.vpd_cap_offset = next_ptr; +break ; +case VXGE_HW_PCI_CAP_ID_SLOTID : + hldev->pci_caps.sid_cap_offset = next_ptr; +break ; +case VXGE_HW_PCI_CAP_ID_MSI : + hldev->pci_caps.msi_cap_offset = next_ptr; +break ; +case VXGE_HW_PCI_CAP_ID_VS : + hldev->pci_caps.vs_cap_offset = next_ptr; +break ; +case VXGE_HW_PCI_CAP_ID_SHPC : + hldev->pci_caps.shpc_cap_offset = next_ptr; +break ; +case VXGE_HW_PCI_CAP_ID_PCIE : + hldev->pci_e_caps = next_ptr; +break ; +case VXGE_HW_PCI_CAP_ID_MSIX : + hldev->pci_caps.msix_cap_offset = next_ptr; +break ; +case VXGE_HW_PCI_CAP_ID_AGP : +case VXGE_HW_PCI_CAP_ID_CHSWP : +case VXGE_HW_PCI_CAP_ID_PCIX : +case VXGE_HW_PCI_CAP_ID_HT : +case VXGE_HW_PCI_CAP_ID_DBGPORT : +case VXGE_HW_PCI_CAP_ID_CPCICSR : +case VXGE_HW_PCI_CAP_ID_PCIBSVID : +case VXGE_HW_PCI_CAP_ID_AGP8X : +case VXGE_HW_PCI_CAP_ID_SECDEV : + +break ; +default : + +break ; + } + + next_ptr = +VXGE_HW_PCI_CAP_NEXT ((((u8 *)pci_config) + next_ptr)); + + } + +if (VXGE_HW_PCI_CONFIG_SPACE_SIZE <=0x100 ) + goto exit; + + next_ptr =0x100 ; + +while (next_ptr !=0 ) { + + cap_id = (u8 )VXGE_HW_PCI_EXT_CAP_ID ( + *(u32 *)(((u8 *)pci_config) + next_ptr)); + +switch (cap_id) { + +case VXGE_HW_PCI_EXT_CAP_ID_ERR : + hldev->pci_e_ext_caps.err_cap_offset = next_ptr; +break ; +case VXGE_HW_PCI_EXT_CAP_ID_VC : + hldev->pci_e_ext_caps.vc_cap_offset = next_ptr; +break ; +case VXGE_HW_PCI_EXT_CAP_ID_DSN : + hldev->pci_e_ext_caps.dsn_cap_offset = next_ptr; +break ; +case VXGE_HW_PCI_EXT_CAP_ID_PWR : + hldev->pci_e_ext_caps.pwr_budget_cap_offset = next_ptr; +break ; + +default : + +break ; + } + + next_ptr = (u16 )VXGE_HW_PCI_EXT_CAP_NEXT ( + *(u32 *)(((u8 *)pci_config) + next_ptr)); + + } +exit: + +return ; +} + +/* +* __hw_device_pci_e_init +* @hldev: HW device handle. +* +* Initialize certain PCI/PCI-X configuration registers +* with recommended values. Save config space for future hw resets. +*/ +void +__hw_device_pci_e_init (struct __hw_device *hldev) +{ +int i; +u16 cmd =0 ; +u16 device_id; +u8 revision; + +vxge_assert (hldev !=NULL ); + +/* Store PCI device ID and revision for future references where in we +* decide Xena revision using PCI sub system ID */ +pci_read_config_word (hldev->pdev, + vxge_offsetof(struct vxge_hw_pci_config_le, device_id), + &device_id); + +pci_read_config_byte (hldev->pdev,vxge_offsetof ( + struct vxge_hw_pci_config_le, revision), + &revision); + +/* save original PCI config space to restore it on device_terminate() */ +for (i =0 ; i <VXGE_HW_PCI_CONFIG_SPACE_SIZE /4 ; i++) { +pci_read_config_dword (hldev->pdev, i *4 , + (u32 *)&hldev->pci_config_space_bios + i); + } + +__hw_device_pci_caps_list_process (hldev); + +/* Set the PErr Repconse bit and SERR in PCI command register. */ +pci_read_config_word (hldev->pdev, + vxge_offsetof(struct vxge_hw_pci_config_le, command), + &cmd); + cmd |=0x140 ; +pci_write_config_word (hldev->pdev, + vxge_offsetof(struct vxge_hw_pci_config_le, command), + cmd); + +/* save PCI config space for future resets */ +for (i =0 ; i <VXGE_HW_PCI_CONFIG_SPACE_SIZE /4 ; i++) { +pci_read_config_dword (hldev->pdev, i *4 , + (u32 *)&hldev->pci_config_space + i); + } + +return ; +} + +/* +* __hw_device_register_poll +* @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. +*/ +enum vxge_hw_status +__hw_device_register_poll (u64 *reg, +u32 op, +u64 mask, +u32 max_millis) +{ +u64 val64; +u32 i =0 ; +enum vxge_hw_status ret =VXGE_HW_FAIL ; + +vxge_os_udelay (10 ); + +do { + val64 =readq (reg); +if (op ==0 && !(val64 & mask)) +return VXGE_HW_OK ; +else if (op ==1 && (val64 & mask) == mask) +return VXGE_HW_OK ; +vxge_os_udelay (100 ); + }while (++i <=9 ); + +do { + val64 =readq (reg); +if (op ==0 && !(val64 & mask)) +return VXGE_HW_OK ; +else if (op ==1 && (val64 & mask) == mask) +return VXGE_HW_OK ; +vxge_os_udelay (1000 ); + }while (++i < max_millis); + +return ret; +} + +/* +* __hw_device_vpath_reset_in_prog_check - Check if vpath reset in progress +* +* @vpath_rst_in_prog: Address of vpath reset in progress register +* +* This routine checks the vpath reset in progress register is turned zero +*/ +enum vxge_hw_status +__hw_device_vpath_reset_in_prog_check (u64 *vpath_rst_in_prog) +{ +enum vxge_hw_status status; + + status =__hw_device_register_poll (vpath_rst_in_prog,0 , +VXGE_HW_VPATH_RST_IN_PROG_VPATH_RST_IN_PROG (0x1ffff ), +VXGE_HW_DEF_DEVICE_POLL_MILLIS ); + +return status; +} + +/* +* __hw_device_toc_get +* @bar0: Address of BAR0 in PCI config +* +* This routine sets the sapper and reads the toc pointer and returns the +* memory mapped address of the toc +*/ +struct vxge_hw_toc_reg * +__hw_device_toc_get (u8 *bar0) +{ +u64 val64; +struct vxge_hw_toc_reg *toc =NULL ; +enum vxge_hw_status status; +struct vxge_hw_legacy_reg *legacy_reg = + (struct vxge_hw_legacy_reg *)bar0; + + status =__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 *)(bar0+val64); + +exit: + +return toc; +} + +/* +* __hw_device_reg_addr_get +* @hldev: HW Device object. +* +* 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 +__hw_device_reg_addr_get (struct __hw_device *hldev) +{ +u64 val64; +u32 i; +enum vxge_hw_status status =VXGE_HW_OK ; + +vxge_assert (hldev); + + hldev->legacy_reg = (struct vxge_hw_legacy_reg *)hldev->bar0; + + hldev->toc_reg =__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 *)(hldev->bar0 + val64); + + val64 =readq (&hldev->toc_reg->toc_memrepair_pointer); + + hldev->memrepair_reg = + (struct vxge_hw_memrepair_reg *)(hldev->bar0 + val64); + +for (i =0 ; i <VXGE_HW_TITAN_PCICFGMGMT_REG_SPACES ; i++) { + + val64 =readq (&hldev->toc_reg->toc_pcicfgmgmt_pointer[i]); + + hldev->pcicfgmgmt_reg[i] = (struct vxge_hw_pcicfgmgmt_reg *) \ + (hldev->bar0 + val64); + + } + + val64 =readq (&hldev->toc_reg->toc_mrpcim_pointer); + + hldev->mrpcim_reg = + (struct vxge_hw_mrpcim_reg *)(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 *)(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 *)(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 *)(hldev->bar0 + val64); + + } + + val64 =readq (&hldev->toc_reg->toc_kdfc); + +switch (VXGE_HW_TOC_GET_KDFC_INITIAL_BIR (val64)) { +case 0 : + hldev->kdfc = hldev->bar0 + +VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET (val64); +break ; +case 2 : + hldev->kdfc = hldev->bar1 + +VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET (val64); +break ; +case 4 : + hldev->kdfc = hldev->bar2 + +VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET (val64); +break ; +default : + +break ; + } + + val64 =readq (&hldev->toc_reg->toc_usdc); + +switch (VXGE_HW_TOC_GET_USDC_INITIAL_BIR (val64)) { +case 0 : + hldev->usdc = hldev->bar0 + +VXGE_HW_TOC_GET_USDC_INITIAL_OFFSET (val64); +break ; +case 2 : + hldev->usdc = hldev->bar1 + +VXGE_HW_TOC_GET_USDC_INITIAL_OFFSET (val64); +break ; +case 4 : + hldev->usdc = hldev->bar2 + +VXGE_HW_TOC_GET_USDC_INITIAL_OFFSET (val64); +break ; +default : + +break ; + } + + status =__hw_device_vpath_reset_in_prog_check ( + (u64 *)&hldev->common_reg->vpath_rst_in_prog); + +exit: + +return status; +} + +/* +* __hw_device_id_get +* @hldev: HW Device object. +* +* This routine returns sets the device id and revision numbers into the device +* structure +*/ +void +__hw_device_id_get (struct __hw_device *hldev) +{ +u64 val64; + +vxge_assert (hldev); + + 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 ; +} + +/* +* __hw_device_access_rights_get: Get Access Rights of the driver +* @host_type: Host type. +* @func_id: Function Id +* +* This routine returns the Access Rights of the driver +*/ +u32 +__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 : +break ; +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; +} +/* +* __hw_device_host_info_get +* @hldev: HW Device object. +* +* This routine returns the host type assignments +*/ +void +__hw_device_host_info_get (struct __hw_device *hldev) +{ +u64 val64; +u32 i; + +vxge_assert (hldev); + + 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 =__hw_vpath_func_id_get (i, + hldev->vpmgmt_reg[i]); + + hldev->access_rights =__hw_device_access_rights_get ( + hldev->host_type, hldev->func_id); + + hldev->first_vp_id = i; + +break ; + + } + +return ; +} + +/* +* __hw_device_pci_e_info_get - Get PCI_E bus informations such as link_width +*and signalling rate +* @hldev: HW device. +* @signalling_rate: pointer to a variable of enumerated type +* enum vxge_hw_pci_e_signalling_rate{}. +* @link_width: pointer to a variable of enumerated type +* enum vxge_hw_pci_e_link_width{}. +* +* Get pci-e signalling rate and link width. +* +* Returns: one of the enum vxge_hw_status{} enumerated types. +* VXGE_HW_OK- for success. +* VXGE_HW_ERR_INVALID_PCI_INFO - for invalid PCI information from the card. +* VXGE_HW_ERR_BAD_DEVICE_ID - for invalid card. +* +*/ +static enum vxge_hw_status +__hw_device_pci_e_info_get ( +struct __hw_device *hldev, +enum vxge_hw_pci_e_signalling_rate *signalling_rate, +enum vxge_hw_pci_e_link_width *link_width) + +{ +enum vxge_hw_status status =VXGE_HW_OK ; +struct vxge_hw_pci_e_capability *pci_e_caps; + +vxge_assert ((hldev !=NULL ) && (signalling_rate !=NULL ) && + (link_width !=NULL )); + + pci_e_caps = (struct vxge_hw_pci_e_capability *) + (((u8 *)&hldev->pci_config_space_bios) + hldev->pci_e_caps); + +switch (pci_e_caps->pci_e_lnkcap &VXGE_HW_PCI_EXP_LNKCAP_LNK_SPEED ) { +case VXGE_HW_PCI_EXP_LNKCAP_LS_2_5 : + *signalling_rate =VXGE_HW_PCI_E_SIGNALLING_RATE_2_5GB ; +break ; +case VXGE_HW_PCI_EXP_LNKCAP_LS_5 : + *signalling_rate =VXGE_HW_PCI_E_SIGNALLING_RATE_5GB ; +break ; +default : + *signalling_rate =VXGE_HW_PCI_E_SIGNALLING_RATE_UNKNOWN ; +break ; + } + +switch ((pci_e_caps->pci_e_lnkcap & +VXGE_HW_PCI_EXP_LNKCAP_LNK_WIDTH ) >>4 ) { +case VXGE_HW_PCI_EXP_LNKCAP_LW_X1 : + *link_width =VXGE_HW_PCI_E_LINK_WIDTH_X1 ; +break ; +case VXGE_HW_PCI_EXP_LNKCAP_LW_X2 : + *link_width =VXGE_HW_PCI_E_LINK_WIDTH_X2 ; +break ; +case VXGE_HW_PCI_EXP_LNKCAP_LW_X4 : + *link_width =VXGE_HW_PCI_E_LINK_WIDTH_X4 ; +break ; +case VXGE_HW_PCI_EXP_LNKCAP_LW_X8 : + *link_width =VXGE_HW_PCI_E_LINK_WIDTH_X8 ; +break ; +case VXGE_HW_PCI_EXP_LNKCAP_LW_X12 : + *link_width =VXGE_HW_PCI_E_LINK_WIDTH_X12 ; +break ; +case VXGE_HW_PCI_EXP_LNKCAP_LW_X16 : + *link_width =VXGE_HW_PCI_E_LINK_WIDTH_X16 ; +break ; +case VXGE_HW_PCI_EXP_LNKCAP_LW_X32 : + *link_width =VXGE_HW_PCI_E_LINK_WIDTH_X32 ; +break ; +case VXGE_HW_PCI_EXP_LNKCAP_LW_RES : +default : + *link_width =VXGE_HW_PCI_E_LINK_WIDTH_UNKNOWN ; +break ; + } + +if ((*signalling_rate ==VXGE_HW_PCI_E_SIGNALLING_RATE_UNKNOWN ) || + (*link_width ==VXGE_HW_PCI_E_LINK_WIDTH_UNKNOWN )) + status =VXGE_HW_ERR_INVALID_PCI_INFO ; + +return status; +} + +/** +* __hw_device_get_vpd_data - Getting vpd_data. +* +* @hldev: HW device handle. +* +* Getting product name and serial number from vpd capabilites structure +* +*/ +void +__hw_device_get_vpd_data (struct __hw_device *hldev) +{ +u8 *vpd_data; +u16 data; +u32 data32; +u32 index =0 , i, count, fail =0 ; +u32 addr_offset; +u32 data_offset; +u32 max_count = hldev->config.device_poll_millis *10 ; + +vxge_assert (hldev); + + addr_offset = hldev->pci_caps.vpd_cap_offset + + vxge_offsetof(struct vxge_hw_vpid_capability_le, vpd_address); + + data_offset = hldev->pci_caps.vpd_cap_offset + + vxge_offsetof(struct vxge_hw_vpid_capability_le, vpd_data); +strcpy ((char *) hldev->vpd_data.product_name, +"10 Gigabit Ethernet Adapter" ); + +strcpy ((char *) hldev->vpd_data.serial_num,"not available" ); + +if ((hldev->host_type !=VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION ) || + (hldev->func_id !=0 )) { +strcpy ((char *) hldev->vpd_data.serial_num, +"not supported" ); +strcpy ((char *) hldev->vpd_data.product_name, +"not supported" ); +return ; + } + vpd_data = (u8 *)vmalloc (VXGE_HW_VPD_BUFFER_SIZE +16 ); +if (vpd_data ==0 ) +return ; +for (index =0 ; index <VXGE_HW_VPD_BUFFER_SIZE ; index +=4 ) { +pci_write_config_word (hldev->pdev, + addr_offset, (u16 )index); +for (count =0 ; count < max_count; count++) { +vxge_os_udelay (100 ); +pci_read_config_word (hldev->pdev, + addr_offset, &data); +if (data &VXGE_HW_PCI_VPID_COMPL_FALG ) +break ; + } + +if (count >= max_count) { + + fail =1 ; +break ; + } + +pci_read_config_dword (hldev->pdev, + data_offset, &data32); + +for (i =0 ; i <4 ; i++) { + vpd_data[index+i] = (u8)(data32 &0xff ); + data32 >>=8 ; + } + } + +if (!fail) { + +/* read serial number of adapter */ +for (count =0 ; count <VXGE_HW_VPD_BUFFER_SIZE ; count++) { +if ((vpd_data[count] =='S' ) && + (vpd_data[count +1 ] =='N' ) && + (vpd_data[count +2 ] <VXGE_HW_VPD_LENGTH )) { +memset (hldev->vpd_data.serial_num,0 , +VXGE_HW_VPD_LENGTH ); +memcpy (hldev->vpd_data.serial_num, + &vpd_data[count +3 ], + vpd_data[count +2 ]); +break ; + } + } + +if (vpd_data[1 ] <VXGE_HW_VPD_LENGTH ) { +memset (hldev->vpd_data.product_name,0 , vpd_data[1 ]); +memcpy (hldev->vpd_data.product_name, &vpd_data[3 ], + vpd_data[1 ]); + } + } + +vfree (vpd_data); + +return ; +} + +/* +* vxge_hw_wrr_rebalance - Rebalance the RX_WRR and KDFC_WRR calandars. +* @devh: HW device handle. +* +* Rebalance the RX_WRR and KDFC_WRR calandars. +* +*/ +enum vxge_hw_status vxge_hw_wrr_rebalance (struct __hw_device *hldev) +{ +u64 val64; +u32 calender[176 ]; +u32 i, j, how_often =1 ; +enum vxge_hw_status status =VXGE_HW_OK ; + +vxge_assert (hldev !=NULL ); + +if ((hldev->host_type !=VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION ) || + (hldev->func_id !=0 )) { + status =VXGE_HW_ERR_PRIVILAGED_OPEARATION ; + goto exit; + } + +/* Reset the priorities assigned to the WRR arbitration +phases for the receive traffic */ +for (i =0 ; i <22 ; i++) +writeq (0 , ((&hldev->mrpcim_reg->rx_w_round_robin_0) + i)); + +/* Reset the transmit FIFO servicing calendar for FIFOs */ +for (i =0 ; i <20 ; 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 <176 ; i++) + calender[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 =100 / hldev->config. + vp_config[i].min_bandwidth; +if (how_often) { + +for (j =0 ; j <153 ;) { +if (calender[j] ==-1 ) { + calender[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 <176 ; j++) { +if (calender[j] ==-1 ) + calender[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 <20 ; i++) { + + val64 =0 ; + + val64 |=VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_0 (calender[j++]); + val64 |=VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_1 (calender[j++]); + val64 |=VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_2 (calender[j++]); + val64 |=VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_3 (calender[j++]); + val64 |=VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_4 (calender[j++]); + val64 |=VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_5 (calender[j++]); + val64 |=VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_6 (calender[j++]); + val64 |=VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_7 (calender[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 <176 ; i++) + calender[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 =100 / hldev-> + config.vp_config[i].min_bandwidth; +if (how_often) { + +for (j =0 ; j <171 ;) { +if (calender[j] ==-1 ) { + calender[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 <176 ; j++) { +if (calender[j] ==-1 ) + calender[j] =0 ; + } + +for (i =0 , j =0 ; i <22 ; i++) { + val64 =0 ; + val64 |=VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_0 ( + calender[j++]); + val64 |=VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_1 ( + calender[j++]); + val64 |=VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_2 ( + calender[j++]); + val64 |=VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_3 ( + calender[j++]); + val64 |=VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_4 ( + calender[j++]); + val64 |=VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_5 ( + calender[j++]); + val64 |=VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_6 ( + calender[j++]); + val64 |=VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_7 ( + calender[j++]); + +writeq (val64, ((&hldev->mrpcim_reg->rx_w_round_robin_0) + i)); + } +exit: + +return status; +} + +/* +* __hw_device_initialize +* @hldev: HW device handle. +* +* Initialize Titan-V hardware. +*/ +enum vxge_hw_status +__hw_device_initialize (struct __hw_device *hldev) +{ +enum vxge_hw_status status =VXGE_HW_OK ; + +vxge_assert (hldev); + +/* Get the pci-e link width and speed */ + status =__hw_device_pci_e_info_get (hldev, + &hldev->signalling_rate, + &hldev->link_width); +if (status !=VXGE_HW_OK ) { + hldev->signalling_rate = +VXGE_HW_PCI_E_SIGNALLING_RATE_UNKNOWN ; + hldev->link_width =VXGE_HW_PCI_E_LINK_WIDTH_UNKNOWN ; + goto exit; + } + +if ((hldev->host_type ==VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION ) && + (hldev->func_id ==0 )) { + + hldev->mrpcim_stats_block = +__hw_blockpool_block_allocate (hldev, +VXGE_HW_BLOCK_SIZE ); + +if (hldev->mrpcim_stats_block ==NULL ) { + status =VXGE_HW_ERR_OUT_OF_MEMORY ; + goto exit; + } + + hldev->mrpcim_stats = + (struct vxge_hw_device_stats_mrpcim_info *) \ + hldev->mrpcim_stats_block->memblock; + +memset (hldev->mrpcim_stats,0 , +sizeof (struct vxge_hw_device_stats_mrpcim_info )); + + hldev->stats.hw_dev_info_stats.mrpcim_info = + hldev->mrpcim_stats; + + hldev->mrpcim_stats_sav = + &hldev->stats.hw_dev_info_stats.mrpcim_info_sav; + +memset (hldev->mrpcim_stats_sav,0 , +sizeof (struct vxge_hw_device_stats_mrpcim_info )); + +writeq (hldev->mrpcim_stats_block->dma_addr, + &hldev->mrpcim_reg->mrpcim_stats_start_host_addr); + } + +vxge_hw_wrr_rebalance (hldev); + +exit: + +return status; +} + +/** +* vxge_hw_device_hw_info_get - Get the hw information +* @bar0: Address of BAR0 in PCI config +* @hw_info: Buffer to return struct vxge_hw_device_hw_info{} structure +* +* 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 vxge_hw_device_hw_info_get (u8 *bar0, +struct vxge_hw_device_hw_info *hw_info) +{ +u32 i; +u64 val64; +struct vxge_hw_toc_reg *toc; +struct vxge_hw_mrpcim_reg *mrpcim_reg; +struct vxge_hw_common_reg *common_reg; +struct vxge_hw_vpath_reg *vpath_reg; +struct vxge_hw_vpmgmt_reg *vpmgmt_reg; +enum vxge_hw_status status; + +vxge_assert ((bar0 !=NULL ) && (hw_info !=NULL )); + +memset (hw_info,0 ,sizeof (struct vxge_hw_device_hw_info )); + + toc =__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 *)(bar0 + val64); + + status =__hw_device_vpath_reset_in_prog_check ( + (u64 *)&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 *)(bar0 + val64); + + hw_info->func_id =__hw_vpath_func_id_get (i, vpmgmt_reg); +if (__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 *)(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 *)(bar0 + val64); + + hw_info->function_mode = +__hw_vpath_pci_func_mode_get (i, vpath_reg); + +__hw_vpath_fw_flash_ver_get (i, vpath_reg, + &hw_info->fw_version, + &hw_info->fw_date, + &hw_info->flash_version, + &hw_info->flash_date); + +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 *)(bar0 + val64); + + status =__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. +* @hldev: HW device handle. +* @attr: pointer to struct vxge_hw_device_attr structure +* @device_config: Configuration to be _applied_ to the device, +* For the Titan configuration "knobs" please +* refer to struct vxge_hw_device_config and Titan +* User Guide. +* +* 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 __hw_device) bytes for HW +* to enable the latter to perform Titan hardware initialization. +* +* Returns: VXGE_HW_OK - success. +* VXGE_HW_ERR_DRIVER_NOT_INITIALIZED - Driver is not initialized. +* VXGE_HW_ERR_BAD_DEVICE_CONFIG - Device configuration params are not +* valid. +* VXGE_HW_ERR_OUT_OF_MEMORY - Memory allocation failed. +* VXGE_HW_ERR_BAD_SUBSYSTEM_ID - Device subsystem id is invalid. +* VXGE_HW_ERR_INVALID_MAC_ADDRESS - Device mac address in not valid. +* VXGE_HW_INF_MEM_STROBE_CMD_EXECUTING - Failed to retrieve the mac +* address within the time(timeout) or TTI/RTI initialization failed. +* VXGE_HW_ERR_SWAPPER_CTRL - Failed to configure swapper control. +* +* See also: __hw_device_terminate(), enum vxge_hw_status{} +* struct vxge_hw_device_attr{}. +*/ +enum vxge_hw_status +vxge_hw_device_initialize ( +struct __hw_device **devh, +struct vxge_hw_device_attr *attr, +struct vxge_hw_device_config *device_config) +{ +u32 i; +u32 nblocks =0 ; +struct __hw_device *hldev =NULL ; +enum vxge_hw_status status =VXGE_HW_OK ; +u64 value =0 ; + +vxge_assert ((devh !=NULL ) && (attr !=NULL ) && + (device_config !=NULL )); + + status =__hw_device_config_check (device_config); +if (status !=VXGE_HW_OK ) + goto exit; + + hldev = (struct __hw_device *)vmalloc (sizeof (struct __hw_device )); +if (hldev ==NULL ) { + status =VXGE_HW_ERR_OUT_OF_MEMORY ; + goto exit; + } + +memset (hldev,0 ,sizeof (struct __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; + hldev->uld_callbacks.sched_timer = + attr->uld_callbacks.sched_timer; + hldev->uld_callbacks.xpak_alarm_log = + attr->uld_callbacks.xpak_alarm_log; + +__hw_device_pci_e_init (hldev); + + status =__hw_device_reg_addr_get (hldev); +if (status !=VXGE_HW_OK ) + goto exit; +__hw_device_id_get (hldev); + +__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 (__hw_blockpool_create (hldev, + &hldev->block_pool, + device_config->dma_blockpool_initial + nblocks, + device_config->dma_blockpool_incr, + device_config->dma_blockpool_min, + device_config->dma_blockpool_max + nblocks) != +VXGE_HW_OK ) { + +vxge_hw_device_terminate (hldev); + status =VXGE_HW_ERR_OUT_OF_MEMORY ; + goto exit; + } + + status =__hw_device_initialize (hldev); + +if (status !=VXGE_HW_OK ) { + +vxge_hw_device_terminate (hldev); + goto exit; + } + +__hw_device_get_vpd_data (hldev); + +/* Redundant as it is already set in __hw_device_hw_initialzie. */ + hldev->is_initialized =1 ; + + *devh = hldev; + +if (hldev->access_rights &VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM ) { +/* debounce configuration for PORT0 */ + value =VXGE_HW_XGMAC_DEBOUNCE_PORT_PERIOD_LINK_UP (0xD ) | +VXGE_HW_XGMAC_DEBOUNCE_PORT_PERIOD_LINK_DOWN (0xD ) | +VXGE_HW_XGMAC_DEBOUNCE_PORT_PERIOD_PORT_UP (0xD ) | +VXGE_HW_XGMAC_DEBOUNCE_PORT_PERIOD_PORT_DOWN (0xD ); + +writeq (value, &hldev->mrpcim_reg->xgmac_debounce_port[0 ]); + +/* debounce configuration for PORT1 */ +writeq (value, &hldev->mrpcim_reg->xgmac_debounce_port[1 ]); + } +exit: + +return status; +} + +/** +* vxge_hw_device_terminate - Terminate Titan device. +* @hldev: HW device handle. +* +* Terminate HW device. +* +* See also: vxge_hw_device_initialize(). +*/ +void +vxge_hw_device_terminate (struct __hw_device *hldev) +{ +vxge_assert (hldev !=NULL ); +vxge_assert (hldev->magic ==VXGE_HW_DEVICE_MAGIC ); + + hldev->is_initialized =0 ; + hldev->magic =VXGE_HW_DEVICE_DEAD ; + +if (hldev->mrpcim_stats_block !=NULL ) { +__hw_blockpool_block_free (hldev, hldev->mrpcim_stats_block); + hldev->mrpcim_stats_block =NULL ; + } + +__hw_blockpool_destroy (&hldev->block_pool); + +vfree (hldev); + +} + +/** +* vxge_hw_device_hw_stats_enable - Enable device h/w statistics. +* @hldev: HW Device. +* +* Enable the DMA vpath statistics for the device. The function is to be called +* to re-enable the adapter to update stats into the host memory +* +*/ +enum vxge_hw_status vxge_hw_device_hw_stats_enable (struct __hw_device *hldev) +{ +u32 i; +u64 val64; +enum vxge_hw_status status =VXGE_HW_OK ; + +vxge_assert (hldev !=NULL ); + + val64 =readq (&hldev->common_reg->stats_cfg0); + +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 )); + +if (hldev->config.stats_read_method == +VXGE_HW_STATS_READ_METHOD_DMA ) { + val64 |=VXGE_HW_STATS_CFG0_STATS_ENABLE ( + (1 << (16 - i))); + }else { + status =__hw_vpath_stats_get ( + &hldev->virtual_paths[i], + hldev->virtual_paths[i].hw_stats); + } + + } + +__hw_pio_mem_write32_upper ((u32 )bVAL32 (val64,0 ), + &hldev->common_reg->stats_cfg0); + +return status; +} + +/** +* vxge_hw_device_stats_get - Get the device hw statistics. +* @hldev: HW Device. +* @hw_stats: Hardware stats +* +* Returns the vpath h/w stats for the device. +* +* See also: vxge_hw_device_hw_stats_enable(), +* vxge_hw_device_hw_stats_disable() +*/ +enum vxge_hw_status vxge_hw_device_stats_get ( +struct __hw_device *hldev, +struct vxge_hw_device_stats_hw_info *hw_stats) +{ +u32 i; +u64 val64 =0 ; +enum vxge_hw_status status =VXGE_HW_OK ; + +vxge_assert ((hldev !=NULL ) && (hw_stats !=NULL )); + +if (hldev->config.stats_read_method == +VXGE_HW_STATS_READ_METHOD_DMA ) { + +for (i =0 ; i <VXGE_HW_MAX_VIRTUAL_PATHS ; i++) { + +if (!(hldev->vpaths_deployed &vxge_mBIT (i))) +continue ; + + val64 |=VXGE_HW_STATS_CFG0_STATS_ENABLE ( + (1 << (16 - i))); + + } + + status =__hw_device_register_poll ( + (u64 *)&hldev->common_reg->stats_cfg0, +0 , + val64, + hldev->config.device_poll_millis); + + } + +if (status ==VXGE_HW_OK ) { +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. +* @hldev: HW Device. +* @sw_stats: Software stats +* +* Returns the vpath s/w stats for the device. +* +* See also: vxge_hw_device_stats_get() +*/ +enum vxge_hw_status vxge_hw_driver_stats_get ( +struct __hw_device *hldev, +struct vxge_hw_device_stats_sw_info *sw_stats) +{ +enum vxge_hw_status status =VXGE_HW_OK ; + +vxge_assert ((hldev !=NULL ) && (sw_stats !=NULL )); + +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 +* @hldev: HW Device handle. +* @operation: Operation to be performed +* @location: Location (one of vpath id, aggregate or port) +* @offset: Offset with in the location +* @stat: Pointer to a buffer to return the value +* +* Get the statistics from the given location and offset. +* +*/ +enum vxge_hw_status +vxge_hw_mrpcim_stats_access ( +struct __hw_device *hldev, +u32 operation, +u32 location, +u32 offset, +u64 *stat) +{ +u64 val64; +enum vxge_hw_status status =VXGE_HW_OK ; + +vxge_assert ((hldev !=NULL ) && (stat !=NULL )); + +if ((hldev->host_type !=VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION ) || + (hldev->func_id !=0 )) { + status =VXGE_HW_ERR_PRIVILAGED_OPEARATION ; + 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); + +__hw_pio_mem_write32_lower ((u32 )bVAL32 (val64,32 ), + &hldev->mrpcim_reg->xmac_stats_sys_cmd); + +wmb (); + +__hw_pio_mem_write32_upper ((u32 )bVAL32 (val64,0 ), + &hldev->mrpcim_reg->xmac_stats_sys_cmd); + +wmb (); + + status =__hw_device_register_poll ( + (u64 *)&hldev->mrpcim_reg->xmac_stats_sys_cmd, +0 , +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 +* @hldev: HW device handle. +* @port: Number of the port (0 or 1) +* @aggr_stats: Buffer to return Statistics on aggregate port. +* +* Get the Statistics on aggregate port +* +*/ +enum vxge_hw_status +vxge_hw_device_xmac_aggr_stats_get (struct __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 ; + +vxge_assert ((hldev !=NULL ) && (aggr_stats !=NULL )); + val64 = (u64 *)aggr_stats; + +if ((hldev->host_type !=VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION ) || + (hldev->func_id !=0 )) { + status =VXGE_HW_ERR_PRIVILAGED_OPEARATION ; + 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 = offset +8 ; + val64++; + } +exit: + +return status; +} + +/** +* vxge_hw_device_xmac_port_stats_get - Get the Statistics on a port +* @hldev: HW device handle. +* @port: Number of the port (wire 0, wire 1 or LAG) +* @port_stats: Buffer to return Statistics on a port. +* +* Get the Statistics on port +* +*/ +enum vxge_hw_status +vxge_hw_device_xmac_port_stats_get (struct __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 ; +vxge_assert ((hldev !=NULL ) && (port_stats !=NULL )); + val64 = (u64 *) port_stats; + +if ((hldev->host_type !=VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION ) || + (hldev->func_id !=0 )) { + status =VXGE_HW_ERR_PRIVILAGED_OPEARATION ; + 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 = offset +8 ; + val64++; + } + +exit: + +return status; +} + +/** +* vxge_hw_device_xmac_stats_get - Get the XMAC Statistics +* @hldev: HW device handle. +* @xmac_stats: Buffer to return XMAC Statistics. +* +* Get the XMAC Statistics +* +*/ +enum vxge_hw_status +vxge_hw_device_xmac_stats_get (struct __hw_device *hldev, +struct vxge_hw_xmac_stats *xmac_stats) +{ +enum vxge_hw_status status =VXGE_HW_OK ; +u32 i; + +vxge_assert ((hldev !=NULL ) && (xmac_stats !=NULL )); + + status =vxge_hw_device_xmac_aggr_stats_get (hldev, +0 , + &xmac_stats->aggr_stats[0 ]); + +if (status !=VXGE_HW_OK ) + goto exit; + + status =vxge_hw_device_xmac_aggr_stats_get (hldev, +1 , + &xmac_stats->aggr_stats[1 ]); + +if (status !=VXGE_HW_OK ) + goto exit; + +for (i =0 ; i <=VXGE_HW_MAC_MAX_MAC_PORT_ID ; i++) { + + status =vxge_hw_device_xmac_port_stats_get (hldev, + i, + &xmac_stats->port_stats[i]); + +if (status !=VXGE_HW_OK ) + goto exit; + + } + +for (i =0 ; i <VXGE_HW_MAX_VIRTUAL_PATHS ; i++) { + +if (!(hldev->vpaths_deployed &vxge_mBIT (i))) +continue ; + + status =__hw_vpath_xmac_tx_stats_get (&hldev->virtual_paths[i], + &xmac_stats->vpath_tx_stats[i]); + +if (status !=VXGE_HW_OK ) + goto exit; + + status =__hw_vpath_xmac_rx_stats_get (&hldev->virtual_paths[i], + &xmac_stats->vpath_rx_stats[i]); + +if (status !=VXGE_HW_OK ) + goto exit; + + } +exit: + +return status; +} + +/** +* vxge_hw_device_debug_set - Set the debug module, level and timestamp +* @hldev: Hal device object +* @level: Debug level as defined in enum enum vxge_debug_level +* @module masks: An or value of component masks as defined in vxge_debug.h +* +* This routine is used to dynamically change the debug output +*/ +void vxge_hw_device_debug_set ( +struct __hw_device *hldev, +enum vxge_debug_level level, +u32 mask) +{ + +if (hldev ==NULL ) +return ; + +#if defined(VXGE_DEBUG_TRACE_MASK ) || \ + defined(VXGE_DEBUG_ERR_MASK ) + hldev->debug_module_mask = mask; + hldev->debug_level = level; +#endif + +#if defined(VXGE_DEBUG_ERR_MASK ) + hldev->level_err = level &VXGE_ERR ; +#endif + +#if defined(VXGE_DEBUG_TRACE_MASK ) + hldev->level_trace = level &VXGE_TRACE ; +#endif + +} + +/** +* vxge_hw_device_debug_level_get - Get the debug level +* @hldev: Hal device object +* +* This routine returns the current debug level set +*/ +u32 +vxge_hw_device_debug_level_get (struct __hw_device *hldev) +{ +#if defined(VXGE_DEBUG_TRACE_MASK ) || defined(VXGE_DEBUG_ERR_MASK ) +if (hldev ==NULL ) +return 0 ; +return hldev->debug_level; +#else +return 0 ; +#endif + +} + +/** +* vxge_hw_device_error_level_get - Get the error level +* @hldev: Hal device object +* +* This routine returns the current error level set +*/ +u32 +vxge_hw_device_error_level_get (struct __hw_device *hldev) +{ +#if defined(VXGE_DEBUG_ERR_MASK ) +if (hldev ==NULL ) +return VXGE_ERR ; +else +return hldev->level_err; +#else +return 0 ; +#endif + +} +/** +* vxge_hw_device_trace_level_get - Get the trace level +* @hldev: Hal device object +* +* This routine returns the current trace level set +*/ +u32 +vxge_hw_device_trace_level_get (struct __hw_device *hldev) +{ +#if defined(VXGE_DEBUG_TRACE_MASK ) +if (hldev ==NULL ) +return VXGE_TRACE ; +else +return hldev->level_trace; +#else +return 0 ; +#endif + +} +/** +* vxge_hw_device_debug_mask_get - Get the debug mask +* @hldev: Hal device object +* +* This routine returns the current debug mask set +*/ +u32 +vxge_hw_device_debug_mask_get (struct __hw_device *hldev) +{ +#if defined(VXGE_DEBUG_TRACE_MASK ) || defined(VXGE_DEBUG_ERR_MASK ) +if (hldev ==NULL ) +return 0 ; +return hldev->debug_module_mask; +#else +return 0 ; +#endif + +} + +/** +* vxge_hw_getpause_data -Pause frame frame generation and reception. +* @hldev: HW device handle. +* @port : Port number 0, 1, or 2 +* @tx : A field to return the pause generation capability of the NIC. +* @rx : A field to return the pause reception capability of the NIC. +* +* Returns the Pause frame generation and reception capability of the NIC. +* Return value: +* status +*/ +enum vxge_hw_status vxge_hw_device_getpause_data ( +struct __hw_device *hldev, +u32 port, +u32 *tx, +u32 *rx) +{ +u64 val64; +enum vxge_hw_status status =VXGE_HW_OK ; +vxge_assert (hldev !=NULL ); + +if ((hldev ==NULL ) || (hldev->magic !=VXGE_HW_DEVICE_MAGIC )) { + status =VXGE_HW_ERR_INVALID_DEVICE ; + goto exit; + } + +if (port >VXGE_HW_MAC_MAX_MAC_PORT_ID ) { + status =VXGE_HW_ERR_INVALID_PORT ; + goto exit; + } + +if (!(hldev->access_rights &VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM )) { + status =VXGE_HW_ERR_PRIVILAGED_OPEARATION ; + goto exit; + } + + val64 =readq (&hldev->mrpcim_reg->rxmac_pause_cfg_port[port]); + +if (val64 &VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN ) + *tx =1 ; + +if (val64 &VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN ) + *rx =1 ; +exit: + +return status; +} + +/** +* vxge_hw_device_setpause_data - set/reset pause frame generation. +* @hldev: HW device handle. +* @port : Port number 0, 1, or 2 +* @tx: A field that indicates the pause generation capability to be +* set on the NIC. +* @rx: A field that indicates the pause reception capability to be +* set on the NIC. +* +* It can be used to set or reset Pause frame generation or reception +* support of the NIC. +* Return value: +* int, returns 0 on Success +*/ + +enum vxge_hw_status vxge_hw_device_setpause_data ( +struct __hw_device *hldev, +u32 port, +u32 tx, +u32 rx) +{ +u64 val64; +enum vxge_hw_status status =VXGE_HW_OK ; +vxge_assert (hldev !=NULL ); + +if ((hldev ==NULL ) || (hldev->magic !=VXGE_HW_DEVICE_MAGIC )) { + status =VXGE_HW_ERR_INVALID_DEVICE ; + goto exit; + } + +if (port >VXGE_HW_MAC_MAX_MAC_PORT_ID ) { + status =VXGE_HW_ERR_INVALID_PORT ; + goto exit; + } + +if ((hldev->host_type !=VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION ) || + (hldev->func_id !=0 )) { + status =VXGE_HW_ERR_PRIVILAGED_OPEARATION ; + goto exit; + } + + val64 =readq (&hldev->mrpcim_reg->rxmac_pause_cfg_port[port]); +if (tx) + val64 |=VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN ; +else + val64 &= ~VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN ; +if (rx) + val64 |=VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN ; +else + val64 &= ~VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN ; + +writeq (val64, &hldev->mrpcim_reg->rxmac_pause_cfg_port[port]); +exit: + +return status; +} + +/** +* vxge_hw_device_private_set - Set driver context. +* @hldev: HW device handle. +* @data: pointer to driver context +* +* Use HW device to set driver context. +* +* See also: vxge_hw_device_private_get() +*/ +void vxge_hw_device_private_set (struct __hw_device *hldev,void *data) +{ + hldev->upper_layer_data = data; +} + +/** +* vxge_hw_device_private_get - Get driver context. +* @hldev: HW device handle. +* +* Use HW device to set driver context. +* +* See also: vxge_hw_device_private_get() +*/ +void *vxge_hw_device_private_get (struct __hw_device *hldev) +{ +return hldev->upper_layer_data; +} + +/* +* vxge_hw_device_serial_number_get - Returns the serial number +* @hldev: HW device handle. +* +* Return the serial number +*/ +const u8 * +vxge_hw_device_serial_number_get (struct __hw_device *hldev) +{ + +vxge_assert (hldev); + +return hldev->vpd_data.serial_num; +} + +/* +* vxge_hw_device_product_name_get - Returns the product name +* @hldev: HW device handle. +* +* Return the product name +*/ +const u8 * +vxge_hw_device_product_name_get (struct __hw_device *hldev) +{ + +vxge_assert (hldev); + +return hldev->vpd_data.product_name; +} + +u8 +vxge_hw_device_link_width_get (struct __hw_device *hldev) +{ +struct vxge_hw_pci_e_capability *pci_e_caps; + +vxge_assert (hldev); + + pci_e_caps = (struct vxge_hw_pci_e_capability *) + (((u8 *)&hldev->pci_config_space_bios) + hldev->pci_e_caps); + +return (pci_e_caps->pci_e_lnksta & +VXGE_HW_PCI_EXP_LNKCAP_LNK_WIDTH ) >>4 ; +} + +#ifdef VXGE_HW_INTERNAL_COMPILER_ERROR + +#pragma optimize("", off) + +#endif + +/* +* __hw_ring_block_memblock_idx - Return the memblock index +* @block: Virtual address of memory block +* +* This function returns the index of memory block +*/ +static inline u32 +__hw_ring_block_memblock_idx ( +u8 (block )[VXGE_HW_BLOCK_SIZE ]) +{ +return (u32)*((u64 *)((u8 *)block + +VXGE_HW_RING_MEMBLOCK_IDX_OFFSET )); +} + +/* +* __hw_ring_block_memblock_idx_set - Sets the memblock index +* @block: Virtual address of memory block +* @memblock_idx: Index of memory block +* +* This function sets index to a memory block +*/ +static inline void +__hw_ring_block_memblock_idx_set ( +u8 (block )[VXGE_HW_BLOCK_SIZE ], +u32 memblock_idx) +{ + *((u64 *)((u8 *)block +VXGE_HW_RING_MEMBLOCK_IDX_OFFSET )) = + memblock_idx; +} + +/* +* __hw_ring_block_next_pointer - Returns the dma address of next block +* @block: RxD block +* +* Returns the dma address of next block stored in the RxD block +*/ +static inline dma_addr_t +__hw_ring_block_next_pointer ( +u8 (*block)[VXGE_HW_BLOCK_SIZE ]) +{ +return (dma_addr_t)*((u64 *)((u8 *)block + +VXGE_HW_RING_NEXT_BLOCK_POINTER_OFFSET )); +} + +/* +* __hw_ring_block_next_pointer_set - Sets the next block pointer in RxD block +* @block: RxD block +* @dma_next: dma address of next block +* +* Sets the next block pointer in RxD block +*/ +static inline void +__hw_ring_block_next_pointer_set ( +u8 (*block)[VXGE_HW_BLOCK_SIZE ], +dma_addr_t dma_next) +{ + *((u64 *)((u8 *)block +VXGE_HW_RING_NEXT_BLOCK_POINTER_OFFSET )) = + dma_next; +} + +/* +* __hw_ring_first_block_address_get - Returns the dma address of the +* first block +* @ringh: Handle to the ring +* +* Returns the dma address of the first RxD block +*/ +u64 +__hw_ring_first_block_address_get (struct __hw_ring *ringh) +{ +struct __hw_ring *ring = (struct __hw_ring *)ringh; +struct vxge_hw_mempool_dma *dma_object; + + dma_object =__hw_mempool_memblock_dma (ring->mempool,0 ); + +vxge_assert (dma_object !=NULL ); + +return dma_object->addr; +} + +/* +* __hw_ring_item_dma_addr - Return the dma address of an item +* @mempoolh: Handle to the memory pool of the ring +* @item: Item for which to get the dma offset +* @dma_handle: dma handle +* +* This function returns the dma address of a given item +*/ +static dma_addr_t +__hw_ring_item_dma_addr ( +struct vxge_hw_mempool *mempoolh, +void *item, +struct pci_dev **dma_handle) +{ +u32 memblock_idx; +void *memblock; +struct vxge_hw_mempool_dma *memblock_dma_object; +#if (VXGE_COMPONENT_HW_POOL &VXGE_DEBUG_MODULE_MASK ) +struct vxge_hw_mempool *mempool = (struct vxge_hw_mempool *)mempoolh; +#endif + +ptrdiff_t dma_item_offset; + +vxge_assert ((mempoolh !=NULL ) && (item !=NULL ) && + (dma_handle !=NULL )); + +/* get owner memblock index */ + memblock_idx =__hw_ring_block_memblock_idx (item); + +/* get owner memblock by memblock index */ + memblock =__hw_mempool_memblock ( + (struct vxge_hw_mempool *) mempoolh, memblock_idx); + +/* get memblock DMA object by memblock index */ + memblock_dma_object =__hw_mempool_memblock_dma ( + (struct vxge_hw_mempool *) mempoolh, memblock_idx); + +/* calculate offset in the memblock of this item */ + dma_item_offset = (u8 *)item - (u8 *)memblock; + + *dma_handle = memblock_dma_object->handle; + +return memblock_dma_object->addr + dma_item_offset; +} + +/* +* __hw_ring_rxdblock_link - Link the RxD blocks +* @mempoolh: Handle to the memory pool of the ring +* @ringh: Handle to the ring object used for receive +* @from: RxD block from which to link +* @to: RxD block to which to link to +* +* This function returns the dma address of a given item +*/ +static void +__hw_ring_rxdblock_link ( +struct vxge_hw_mempool *mempoolh, +struct __hw_ring *ring, +u32 from, +u32 to) +{ +u8 (*to_item)[VXGE_HW_BLOCK_SIZE ], (*from_item)[VXGE_HW_BLOCK_SIZE ]; +dma_addr_t to_dma, from_dma; +struct pci_dev *to_dma_handle, *from_dma_handle; + +vxge_assert ((mempoolh !=NULL ) && (ring !=NULL )); + +/* get "from" RxD block */ + from_item =__hw_mempool_item ( + (struct vxge_hw_mempool *) mempoolh, from); +vxge_assert (from_item); + +/* get "to" RxD block */ + to_item =__hw_mempool_item ( + (struct vxge_hw_mempool *) mempoolh, to); +vxge_assert (to_item); + +/* return address of the beginning of previous RxD block */ + to_dma =__hw_ring_item_dma_addr (mempoolh, to_item, &to_dma_handle); + +/* set next pointer for this RxD block to point on +* previous item's DMA start address */ +__hw_ring_block_next_pointer_set (from_item, to_dma); + +/* return "from" RxD block's DMA start address */ + from_dma =__hw_ring_item_dma_addr ( + mempoolh, from_item, &from_dma_handle); + +} + +/* +* __hw_ring_mempool_item_alloc - Allocate List blocks for RxD block callback +* @mempoolh: Handle to memory pool +* @memblock: Address of this memory block +* @memblock_index: Index of this memory block +* @dma_object: dma object for this block +* @item: Pointer to this item +* @index: Index of this item in memory block +* @is_last: If this is last item in the block +* @userdata: Specific data of user +* +* This function is callback passed to __hw_mempool_create to create memory +* pool for RxD block +*/ +static enum vxge_hw_status +__hw_ring_mempool_item_alloc ( +struct vxge_hw_mempool *mempoolh, +void *memblock, +u32 memblock_index, +struct vxge_hw_mempool_dma *dma_object, +void *item, +u32 index, +u32 is_last, +void *userdata) +{ +u32 i; +struct __hw_ring *ring = (struct __hw_ring *)userdata; + +vxge_assert ((item !=NULL ) && (ring !=NULL )); + +/* format rxds array */ +for (i =0 ; i < ring->rxds_per_block; i++) { +void *rxdblock_priv; +void *uld_priv; +struct vxge_hw_ring_rxd_1 *rxdp; + +u32 reserve_index = ring->channel.reserve_ptr - + (index * ring->rxds_per_block + i +1 ); +u32 memblock_item_idx; + + ring->channel.reserve_arr[reserve_index] = ((u8 *)item) + + i * ring->rxd_size; + +/* Note: memblock_item_idx is index of the item within +* the memblock. For instance, in case of three RxD-blocks +* per memblock this value can be 0, 1 or 2. */ + rxdblock_priv =__hw_mempool_item_priv ( + (struct vxge_hw_mempool *)mempoolh, + memblock_index, item, + &memblock_item_idx); + + rxdp = (struct vxge_hw_ring_rxd_1 *) + ring->channel.reserve_arr[reserve_index]; + + uld_priv = ((u8 *)rxdblock_priv + ring->rxd_priv_size * i); + +/* pre-format Host_Control */ + rxdp->host_control = (u64 )(ptr_t )uld_priv; + } + +__hw_ring_block_memblock_idx_set (item, memblock_index); + +if (is_last) { +/* link last one with first one */ +__hw_ring_rxdblock_link (mempoolh, ring, index,0 ); + } + +if (index >0 ) { +/* link this RxD block with previous one */ +__hw_ring_rxdblock_link (mempoolh, ring, index-1 , index); + } + +return VXGE_HW_OK ; +} + +/* +* __hw_ring_initial_replenish - Initial replenish of RxDs +* @ringh: Handle to the ring object used for receive +* @reopen: Flag to denote if it is open or repopen +* +* This function replenishes the RxDs from reserve array to work array +*/ +enum vxge_hw_status +vxge_hw_ring_replenish ( +struct __hw_ring *ring, +enum vxge_hw_reopen reopen,u16 min_flag) +{ +void *rxd; +int i =0 ; +struct __hw_channel *channel; +enum vxge_hw_status status =VXGE_HW_OK ; + +vxge_assert (ring !=NULL ); + + channel = &ring->channel; + +while (vxge_hw_channel_dtr_count (channel) >0 ) { + + status =vxge_hw_ring_rxd_reserve (ring, &rxd); + +vxge_assert (status ==VXGE_HW_OK ); + +if (ring->rxd_init) { + status = ring->rxd_init (rxd, + channel->reserve_ptr, + channel->userdata, + reopen); +if (status !=VXGE_HW_OK ) { +vxge_hw_ring_rxd_free (ring, rxd); + goto exit; + } + } + +vxge_hw_ring_rxd_post (ring, rxd); +if (min_flag) { + i++; +if (i ==VXGE_HW_RING_MIN_BUFF_ALLOCATION ) +break ; + } + } + status =VXGE_HW_OK ; +exit: + +return status; +} + +/** +* __hw_ring_create - Create a Ring +* @vpath_handle: Handle returned by virtual path open +* @attr: Ring configuration parameters structure +* +* This function creates Ring and initializes it. +* +*/ +enum vxge_hw_status +__hw_ring_create ( +struct __hw_vpath_handle *vp, +struct vxge_hw_ring_attr *attr) +{ +enum vxge_hw_status status =VXGE_HW_OK ; +struct __hw_ring *ring; +u32 ring_length; +struct vxge_hw_ring_config *config; +struct __hw_device *hldev; +u32 vp_id; +struct vxge_hw_mempool_cbs ring_mp_callback; +vxge_assert ((vp !=NULL ) && (attr !=NULL )); + + hldev = vp->vpath->hldev; + vp_id = vp->vpath->vp_id; + +if ((vp ==NULL ) || (attr ==NULL )) { + + status =VXGE_HW_FAIL ; + goto exit; + } + + config = &hldev->config.vp_config[vp_id].ring; + + ring_length = config->ring_blocks * +vxge_hw_ring_rxds_per_block_get (config->buffer_mode); + + ring = (struct __hw_ring *)__hw_channel_allocate ( + (struct __hw_device *)hldev, + vp, +VXGE_HW_CHANNEL_TYPE_RING , + ring_length, + TRUE, + TRUE, + TRUE, + attr->per_rxd_space, + attr->userdata); + +if (ring ==NULL ) { + + status =VXGE_HW_ERR_OUT_OF_MEMORY ; + goto exit; + } + + vp->vpath->ringh = (struct __hw_ring *)ring; + + ring->rpa_strip_vlan_tag = vp->vpath->vp_config->rpa_strip_vlan_tag; + + ring->vp_id = vp_id; + ring->vp_reg = vp->vpath->vp_reg; + ring->common_reg = hldev->common_reg; + ring->stats = &vp->vpath->sw_stats->ring_stats; + ring->config = config; + ring->callback = attr->callback; + ring->rxd_init = attr->rxd_init; + ring->rxd_term = attr->rxd_term; + + ring->indicate_max_pkts = config->indicate_max_pkts; + ring->buffer_mode = config->buffer_mode; + + ring->rxd_size =vxge_hw_ring_rxd_size_get (config->buffer_mode); + ring->rxd_priv_size = +sizeof (struct __hw_ring_rxd_priv ) + attr->per_rxd_space; + ring->per_rxd_space = attr->per_rxd_space; + + ring->rxd_priv_size = + ((ring->rxd_priv_size +VXGE_CACHE_LINE_SIZE -1 ) / +VXGE_CACHE_LINE_SIZE ) *VXGE_CACHE_LINE_SIZE ; + +/* how many RxDs can fit into one block. Depends on configured +* buffer_mode. */ + ring->rxds_per_block = +vxge_hw_ring_rxds_per_block_get (config->buffer_mode); + +/* calculate actual RxD block private size */ + ring->rxdblock_priv_size = ring->rxd_priv_size * ring->rxds_per_block; + ring_mp_callback.item_func_alloc = __hw_ring_mempool_item_alloc; + ring_mp_callback.item_func_free =NULL ; + ring->mempool =__hw_mempool_create ( + (struct __hw_device *)hldev, +VXGE_HW_BLOCK_SIZE , +VXGE_HW_BLOCK_SIZE , + ring->rxdblock_priv_size, + ring->config->ring_blocks, + ring->config->ring_blocks, + &ring_mp_callback, + ring); + +if (ring->mempool ==NULL ) { +__hw_ring_delete (vp); + +return VXGE_HW_ERR_OUT_OF_MEMORY ; + } + + status =__hw_channel_initialize (&ring->channel); +if (status !=VXGE_HW_OK ) { +__hw_ring_delete (vp); + goto exit; + } + +/* Note: +* Specifying rxd_init callback means two things: +* 1) rxds need to be initialized by driver at channel-open time; +* 2) rxds need to be posted at channel-open time +* (that's what the initial_replenish() below does) +* Currently we don't have a case when the 1) is done without the 2). +*/ +if (ring->rxd_init) { + status =vxge_hw_ring_replenish (ring,VXGE_HW_OPEN_NORMAL ,1 ); +if (status !=VXGE_HW_OK ) { +__hw_ring_delete (vp); + goto exit; + } + } + +/* initial replenish will increment the counter in its post() routine, +* we have to reset it */ + ring->stats->common_stats.usage_cnt =0 ; +exit: + +return status; +} + +/* +* __hw_ring_abort - Returns the RxD +* @ringh: Ring to be reset +* @reopen: See enum vxge_hw_reopen{}. +* +* This function terminates the RxDs of ring +*/ +enum vxge_hw_status +__hw_ring_abort ( +struct __hw_ring *ringh, +enum vxge_hw_reopen reopen) +{ +struct __hw_ring *ring = (struct __hw_ring *)ringh; +void *rxdh; +struct __hw_channel *channel; + +vxge_assert (ringh !=NULL ); + + channel = &ring->channel; + +for (;;) { +vxge_hw_channel_dtr_try_complete (channel, &rxdh); + +if (rxdh ==NULL ) +break ; + +vxge_hw_channel_dtr_complete (channel); + +if (ring->rxd_term) { + ring->rxd_term (rxdh, +VXGE_HW_RXD_STATE_POSTED , + channel->userdata, + reopen); + } + +vxge_hw_channel_dtr_free (channel, rxdh); + + } + +return VXGE_HW_OK ; +} + +/* +* __hw_ring_reset - Resets the ring +* @ringh: Ring to be reset +* +* This function resets the ring during vpath reset operation +*/ +enum vxge_hw_status +__hw_ring_reset ( +struct __hw_ring *ringh) +{ +struct __hw_ring *ring = (struct __hw_ring *)ringh; +enum vxge_hw_status status =VXGE_HW_OK ; +struct __hw_channel *channel; + +vxge_assert (ringh !=NULL ); + + channel = &ring->channel; + +__hw_ring_abort (ringh,VXGE_HW_RESET_ONLY ); + + status =__hw_channel_reset (channel); + +if (status !=VXGE_HW_OK ) + goto exit; + +if (ring->rxd_init) { + status =vxge_hw_ring_replenish (ring,VXGE_HW_RESET_ONLY ,1 ); +if (status !=VXGE_HW_OK ) + goto exit; + } +exit: + +return status; +} + +/* +* __hw_ring_delete - Removes the ring +* @vp: Virtual path handle to which this queue belongs +* +* This function freeup the memory pool and removes the ring +*/ +enum vxge_hw_status +__hw_ring_delete ( +struct __hw_vpath_handle *vp) +{ +struct __hw_ring *ring; +struct __hw_channel *channel; +struct __hw_device *hldev; + +vxge_assert (vp !=NULL ); + + hldev = vp->vpath->hldev; + ring = (struct __hw_ring *)vp->vpath->ringh; + +vxge_assert (ring !=NULL ); + + channel = &ring->channel; + +__hw_ring_abort (ring,VXGE_HW_OPEN_NORMAL ); + +if (ring->mempool) +__hw_mempool_destroy (ring->mempool); + + vp->vpath->ringh =NULL ; + +__hw_channel_free (channel); + +return VXGE_HW_OK ; +} + +/* +* __hw_mempool_grow +* +* Will resize mempool up to %num_allocate value. +*/ +enum vxge_hw_status +__hw_mempool_grow ( +struct vxge_hw_mempool *mempool, +u32 num_allocate, +u32 *num_allocated) +{ +u32 i, first_time = mempool->memblocks_allocated ==0 ?1 :0 ; +u32 n_items = mempool->items_per_memblock; +u32 start_block_idx = mempool->memblocks_allocated; +u32 end_block_idx = mempool->memblocks_allocated + num_allocate; +enum vxge_hw_status status =VXGE_HW_OK ; +vxge_assert (mempool !=NULL ); + + *num_allocated =0 ; + +if (end_block_idx > mempool->memblocks_max) { + + status =VXGE_HW_ERR_OUT_OF_MEMORY ; + goto exit; + } + +for (i = start_block_idx; i < end_block_idx; i++) { +u32 j; +u32 is_last = ((end_block_idx-1 ) == i); +struct vxge_hw_mempool_dma *dma_object = + mempool->memblocks_dma_arr + i; +void *the_memblock; + +/* allocate memblock's private part. Each DMA memblock +* has a space allocated for item's private usage upon +* mempool's user request. Each time mempool grows, it will +* allocate new memblock and its private part at once. +* This helps to minimize memory usage a lot. */ + mempool->memblocks_priv_arr[i] = +vmalloc (mempool->items_priv_size * n_items); +if (mempool->memblocks_priv_arr[i] ==NULL ) { + + status =VXGE_HW_ERR_OUT_OF_MEMORY ; + goto exit; + + } + +memset (mempool->memblocks_priv_arr[i],0 , + mempool->items_priv_size * n_items); + +/* allocate DMA-capable memblock */ + mempool->memblocks_arr[i] = +__hw_blockpool_malloc (mempool->devh, + mempool->memblock_size, + &dma_object->addr, + &dma_object->handle, + &dma_object->acc_handle); +if (mempool->memblocks_arr[i] ==NULL ) { +vfree (mempool->memblocks_priv_arr[i]); + + status =VXGE_HW_ERR_OUT_OF_MEMORY ; + goto exit; + } + + (*num_allocated)++; + mempool->memblocks_allocated++; + +memset (mempool->memblocks_arr[i],0 , + mempool->memblock_size); + + the_memblock = mempool->memblocks_arr[i]; + +/* fill the items hash array */ +for (j =0 ; j < n_items; j++) { +u32 index = i*n_items + j; + +if (first_time && index >= mempool->items_initial) +break ; + + mempool->items_arr[index] = + ((char *)the_memblock + j*mempool->item_size); + +/* let caller to do more job on each item */ +if (mempool->item_func_alloc !=NULL ) { +enum vxge_hw_status status; + + status = mempool->item_func_alloc ( + mempool, + the_memblock, + i, + dma_object, + mempool->items_arr[index], + index, + is_last, + mempool->userdata); +if (status !=VXGE_HW_OK ) { + +if (mempool->item_func_free !=NULL ) { +u32 k; + +for (k =0 ; k < j; k++) { + index = i * n_items + k; + (void )mempool-> +item_func_free ( + mempool, the_memblock, + i, dma_object, + mempool-> + items_arr[index], + index, is_last, + mempool->userdata); + } + } + +vfree (mempool->memblocks_priv_arr[i]); + +__hw_blockpool_free (mempool->devh, + the_memblock, + mempool->memblock_size, + &dma_object->addr, + &dma_object->handle, + &dma_object->acc_handle); + + (*num_allocated)--; + mempool->memblocks_allocated--; + goto exit; + } + } + + mempool->items_current = index +1 ; + } + +if (first_time && mempool->items_current == + mempool->items_initial) +break ; + } +exit: + +return status; +} + +/* +* vxge_hw_mempool_create +* @memblock_size: +* @items_initial: +* @items_max: +* @item_size: +* @item_func: +* +* This function will create memory pool object. Pool may grow but will +* never shrink. Pool consists of number of dynamically allocated blocks +* with size enough to hold %items_initial number of items. Memory is +* DMA-able but client must map/unmap before interoperating with the device. +* See also: vxge_os_dma_map(), vxge_hw_dma_unmap(), enum vxge_hw_status{}. +*/ +struct vxge_hw_mempool * +__hw_mempool_create ( +struct __hw_device *devh, +u32 memblock_size, +u32 item_size, +u32 items_priv_size, +u32 items_initial, +u32 items_max, +struct vxge_hw_mempool_cbs *mp_callback, +void *userdata) +{ +enum vxge_hw_status status =VXGE_HW_OK ; +u32 memblocks_to_allocate; +struct vxge_hw_mempool *mempool =NULL ; +u32 allocated; + +vxge_assert (devh !=NULL ); + +if (memblock_size < item_size) { + + status =VXGE_HW_FAIL ; + goto exit; + } + + mempool = (struct vxge_hw_mempool *) \ +vmalloc (sizeof (struct vxge_hw_mempool )); +if (mempool ==NULL ) { + status =VXGE_HW_ERR_OUT_OF_MEMORY ; + goto exit; + } +memset (mempool,0 ,sizeof (struct vxge_hw_mempool )); + + mempool->devh = devh; + mempool->memblock_size = memblock_size; + mempool->items_max = items_max; + mempool->items_initial = items_initial; + mempool->item_size = item_size; + mempool->items_priv_size = items_priv_size; + mempool->item_func_alloc = mp_callback->item_func_alloc; + mempool->item_func_free = mp_callback->item_func_free; + mempool->userdata = userdata; + + mempool->memblocks_allocated =0 ; + +if (memblock_size !=VXGE_HW_BLOCK_SIZE ) + mempool->dma_flags =VXGE_OS_DMA_CACHELINE_ALIGNED ; + +#ifdef VXGE_HW_DMA_CONSISTENT + mempool->dma_flags |=VXGE_OS_DMA_CONSISTENT ; +#else + mempool->dma_flags |=VXGE_OS_DMA_STREAMING ; +#endif + + mempool->items_per_memblock = memblock_size / item_size; + + mempool->memblocks_max = (items_max + mempool->items_per_memblock -1 ) / + mempool->items_per_memblock; + +/* allocate array of memblocks */ + mempool->memblocks_arr = + (void **)vmalloc (sizeof (void *) * mempool->memblocks_max); +if (mempool->memblocks_arr ==NULL ) { +__hw_mempool_destroy (mempool); + status =VXGE_HW_ERR_OUT_OF_MEMORY ; + mempool =NULL ; + goto exit; + } +memset (mempool->memblocks_arr,0 , +sizeof (void *) * mempool->memblocks_max); + +/* allocate array of private parts of items per memblocks */ + mempool->memblocks_priv_arr = + (void **)vmalloc (sizeof (void *) * mempool->memblocks_max); +if (mempool->memblocks_priv_arr ==NULL ) { +__hw_mempool_destroy (mempool); + status =VXGE_HW_ERR_OUT_OF_MEMORY ; + mempool =NULL ; + goto exit; + } +memset (mempool->memblocks_priv_arr,0 , +sizeof (void *) * mempool->memblocks_max); + +/* allocate array of memblocks DMA objects */ + mempool->memblocks_dma_arr = (struct vxge_hw_mempool_dma *)\ +vmalloc (sizeof (struct vxge_hw_mempool_dma ) *\ + mempool->memblocks_max); + +if (mempool->memblocks_dma_arr ==NULL ) { +__hw_mempool_destroy (mempool); + status =VXGE_HW_ERR_OUT_OF_MEMORY ; + mempool =NULL ; + goto exit; + } +memset (mempool->memblocks_dma_arr,0 , +sizeof (struct vxge_hw_mempool_dma ) * + mempool->memblocks_max); + +/* allocate hash array of items */ + mempool->items_arr = + (void **)vmalloc (sizeof (void *) * mempool->items_max); +if (mempool->items_arr ==NULL ) { +__hw_mempool_destroy (mempool); + status =VXGE_HW_ERR_OUT_OF_MEMORY ; + mempool =NULL ; + goto exit; + } +memset (mempool->items_arr,0 ,sizeof (void *) * mempool->items_max); + + mempool->shadow_items_arr = + (void **)vmalloc (sizeof (void *) * mempool->items_max); +if (mempool->shadow_items_arr ==NULL ) { +__hw_mempool_destroy (mempool); + status =VXGE_HW_ERR_OUT_OF_MEMORY ; + mempool =NULL ; + goto exit; + } +memset (mempool->shadow_items_arr,0 , +sizeof (void *) * mempool->items_max); + +/* calculate initial number of memblocks */ + memblocks_to_allocate = (mempool->items_initial + + mempool->items_per_memblock -1 ) / + mempool->items_per_memblock; + +/* pre-allocate the mempool */ + status =__hw_mempool_grow (mempool, memblocks_to_allocate, &allocated); +memcpy (mempool->shadow_items_arr, mempool->items_arr, +sizeof (void *) * mempool->items_max); +if (status !=VXGE_HW_OK ) { +__hw_mempool_destroy (mempool); + status =VXGE_HW_ERR_OUT_OF_MEMORY ; + mempool =NULL ; + goto exit; + } + +exit: + +return mempool; +} + +/* +* vxge_hw_mempool_destroy +*/ +void +__hw_mempool_destroy ( +struct vxge_hw_mempool *mempool) +{ +u32 i, j; +struct __hw_device *devh; + +vxge_assert (mempool !=NULL ); + + devh = (struct __hw_device *)mempool->devh; + +for (i =0 ; i < mempool->memblocks_allocated; i++) { +struct vxge_hw_mempool_dma *dma_object; + +vxge_assert (mempool->memblocks_arr[i]); +vxge_assert (mempool->memblocks_dma_arr + i); + + dma_object = mempool->memblocks_dma_arr + i; + +for (j =0 ; j < mempool->items_per_memblock; j++) { +u32 index = i*mempool->items_per_memblock + j; + +/* to skip last partially filled(if any) memblock */ +if (index >= mempool->items_current) +break ; + +/* let caller to do more job on each item */ +if (mempool->item_func_free !=NULL ) { + + mempool->item_func_free (mempool, + mempool->memblocks_arr[i], + i, dma_object, + mempool->shadow_items_arr[index], + index,/* unused */ -1 , + mempool->userdata); + } + } + +vfree (mempool->memblocks_priv_arr[i]); + +__hw_blockpool_free (devh, + mempool->memblocks_arr[i], + mempool->memblock_size, + &dma_object->addr, + &dma_object->handle, + &dma_object->acc_handle);
Lines of this file are not shown. View the raw message.
drivers/net/vxge/vxge-config.h +3323 -0
3,323 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Part of the diff is not shown here. View the raw message.
Quoted 30 lines · Ramkrishna Vepa
This patch takes care of Initialization and configuration steps of Neterion Inc's X3100 Series 10GbE PCIe I/O Virtualized Server Adapter.
- Device Initialization.
- Verification and setting of device config parameters.
- Allocation of Tx FIFO and Rx Ring descriptors (DTR).
- APIs to get various type of hw stats
- APIs to configure RTS (Receive Traffic Steering)Signed-off-by Sivakumar Subramani <[email protected]>Signed-off-by Rastapur Santosh <[email protected]>Signed-off-by Ramkrishna Vepa <[email protected]>---
diff -urpNpatch_5/drivers/net/vxge/vxge-config.cpatch_6/drivers/net/vxge/vxge-config.cdrivers/net/vxge/vxge-config.c +14
-0@@ -0,0 +1,7576 @@ +/****************************************************************************** +* 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. +******************************************************************************/
drivers/net/vxge/vxge-config.c line 24
Quoted 10 lines
drivers/net/vxge/vxge-config.c +10
-0+#include <linux/version.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/pci.h> +#include <linux/delay.h> + +#include "vxge-traffic.h" +#include "vxge-config.h" + +/*
You need to start a comment with "/**" to make it a kernel-doc comment.
Quoted 6 lines
drivers/net/vxge/vxge-config.c +6
-0+* __hw_channel_allocate - Allocate memory for channel +* @devh: Handle to the device object +* @vph: Handle to Virtual Path +* @type: Type of channel +* @length: Lengths of arrays +* @alloc_work_array: Flag to specify if work array is required
drivers/net/vxge/vxge-config.c line 40
Quoted 10 lines
drivers/net/vxge/vxge-config.c +10
-0+* @alloc_free_array: Flag to specify if free array is required +* @alloc_reserve_array: Flag to specify if reserve array is required +* @per_dtr_space: driver requested per dtr space to be allocated in priv +* @userdata: User data to be passed back in the callback +* +* This function allocates required memory for the channel and various arrays +* in the channel +*/ +struct __hw_channel * +__hw_channel_allocate(
Drivers in the kernel tree are not necessarily compiled as modules, so their external symbols must be globally unique. You should use a driver- specific prefix, presumably "vxge" (possibly with "__" in front of that).
[...]
Quoted 13 lines
drivers/net/vxge/vxge-config.c +13
-0+/* +* __hw_channel_free - Free memory allocated for channel +* @channel: channel to be freed +* +* This function deallocates memory from the channel and various arrays +* in the channel +*/ +void +__hw_channel_free ( +struct __hw_channel *channel) +{ +u32 vp_id =0 ; +struct __hw_device *hldev;
drivers/net/vxge/vxge-config.c line 163
Quoted 10 lines
drivers/net/vxge/vxge-config.c +10
-0+ +vxge_assert (channel !=NULL ); + + hldev = (struct __hw_device *)channel->devh; + + vp_id = ((struct __hw_vpath_handle *)channel->vph)->vpath->vp_id; + +if (channel->work_arr) { +vfree (channel->work_arr); + channel->work_arr =NULL ;
Why bother clearing members of *channel just before you free it?
[...]
Quoted 8 lines
drivers/net/vxge/vxge-config.c +8
-0+/* +* __hw_channel_initialize - Initialize a channel +* @channel: channel to be initialized +* +* This function initializes a channel by properly setting the +* various references +*/ +enum vxge_hw_status
drivers/net/vxge/vxge-config.c line 202
Quoted 10 lines
drivers/net/vxge/vxge-config.c +10
-0+__hw_channel_initialize ( + struct __hw_channel *channel) +{ +u32 i; +struct __hw_virtualpath *vpath; + +vxge_assert (channel !=NULL ); + + vpath = (struct __hw_virtualpath *)((struct __hw_vpath_handle *) \ + channel->vph)->vpath;
Why are you using backslashes in multi-line statements? This is only necessary in macro definitions.
[...]
drivers/net/vxge/vxge-config.c line 269
Quoted 8 lines
drivers/net/vxge/vxge-config.c +8
-0+/* +* __hw_device_pci_caps_list_process +* @hldev: HW device handle. +* +* Process PCI capabilities and initialize the offsets +*/ +void +__hw_device_pci_caps_list_process (struct __hw_device *hldev)
This is redundant with pci_find_capability().
[...]
Quoted 16 lines
drivers/net/vxge/vxge-config.c +16
-0+/* +* __hw_device_pci_e_init +* @hldev: HW device handle. +* +* Initialize certain PCI/PCI-X configuration registers +* with recommended values. Save config space for future hw resets. +*/ +void +__hw_device_pci_e_init(struct __hw_device *hldev)# +{ +int i; +u16 cmd =0 ; +u16 device_id; +u8 revision; + +vxge_assert (hldev !=NULL );
drivers/net/vxge/vxge-config.c line 394
Quoted 10 lines
drivers/net/vxge/vxge-config.c +10
-0+ +/* Store PCI device ID and revision for future references where in we +* decide Xena revision using PCI sub system ID */ +pci_read_config_word (hldev->pdev, + vxge_offsetof(struct vxge_hw_pci_config_le, device_id), + &device_id); + +pci_read_config_byte (hldev->pdev,vxge_offsetof ( + struct vxge_hw_pci_config_le, revision), + &revision);
This information is in *hldev->pdev already.
drivers/net/vxge/vxge-config.c line 400
Quoted 5 lines
drivers/net/vxge/vxge-config.c +5
-0+/* save original PCI config space to restore it on device_terminate() */ +for (i =0 ; i <VXGE_HW_PCI_CONFIG_SPACE_SIZE /4 ; i++) { +pci_read_config_dword (hldev->pdev, i *4 , + (u32 *)&hldev->pci_config_space_bios + i); + }
Since you only change two bits in the command register, maybe you should just save those bits. Or not bother.
Quoted 6 lines
drivers/net/vxge/vxge-config.c +6
-0+__hw_device_pci_caps_list_process (hldev); + +/* Set the PErr Repconse bit and SERR in PCI command register. */ +pci_read_config_word (hldev->pdev, + vxge_offsetof(struct vxge_hw_pci_config_le, command), + &cmd);
drivers/net/vxge/vxge-config.c line 417
Quoted 10 lines
drivers/net/vxge/vxge-config.c +10
-0+ cmd |=0x140 ; +pci_write_config_word (hldev->pdev, + vxge_offsetof(struct vxge_hw_pci_config_le, command), + cmd); + +/* save PCI config space for future resets */ +for (i =0 ; i <VXGE_HW_PCI_CONFIG_SPACE_SIZE /4 ; i++) { +pci_read_config_dword (hldev->pdev, i *4 , + (u32 *)&hldev->pci_config_space + i); + }
You should use pci_save_state() and pci_restore_state() around resets instead.
Quoted 22 lines
drivers/net/vxge/vxge-config.c +22
-0+return ; +} + +/* +* __hw_device_register_poll +* @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. +*/ +enum vxge_hw_status +__hw_device_register_poll (u64 *reg, +u32 op, +u64 mask, +u32 max_millis) +{ +u64 val64; +u32 i =0 ; +enum vxge_hw_status ret =VXGE_HW_FAIL ;
drivers/net/vxge/vxge-config.c line 450
Quoted 10 lines
drivers/net/vxge/vxge-config.c +10
-0+ +vxge_os_udelay (10 ); + + do { + val64 = readq(reg); + if (op == 0 && !(val64 & mask)) + return VXGE_HW_OK; + else if (op == 1 && (val64 & mask) == mask) + return VXGE_HW_OK; + vxge_os_udelay(100);
udelay(100)
drivers/net/vxge/vxge-config.c line 451
Quoted 1 line
drivers/net/vxge/vxge-config.c +1
-0+ }while (++i <=9 );
You need to reset i to 0 or 1 after this, since you've waited 910 us not 9 ms.
drivers/net/vxge/vxge-config.c line 459
Quoted 7 lines
drivers/net/vxge/vxge-config.c +7
-0+ do { + val64 = readq(reg); + if (op == 0 && !(val64 & mask)) + return VXGE_HW_OK; + else if (op == 1 && (val64 & mask) == mask) + return VXGE_HW_OK; + vxge_os_udelay(1000);
mdelay(1)
drivers/net/vxge/vxge-config.c line 460
Quoted 1 line
drivers/net/vxge/vxge-config.c +1
-0+ }while (++i < max_millis);
This should probably be a while() not a do...while().
drivers/net/vxge/vxge-config.c line 488
Quoted 8 lines
drivers/net/vxge/vxge-config.c +8
-0+return ret; +} + +/* +* __hw_device_toc_get +* @bar0: Address of BAR0 in PCI config +* +* This routine sets the sapper and reads the toc pointer and returns the
Based on the function call below I'm guessing "sapper" should be "swapper".
Quoted 57 lines
drivers/net/vxge/vxge-config.c +57
-0+* memory mapped address of the toc +*/ +struct vxge_hw_toc_reg * +__hw_device_toc_get (u8 *bar0) +{ +u64 val64; +struct vxge_hw_toc_reg *toc =NULL ; +enum vxge_hw_status status; +struct vxge_hw_legacy_reg *legacy_reg = + (struct vxge_hw_legacy_reg *)bar0; + + status =__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 *)(bar0+val64); + +exit: + +return toc; +} + +/* +* __hw_device_reg_addr_get +* @hldev: HW Device object. +* +* 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 +__hw_device_reg_addr_get (struct __hw_device *hldev) +{ +u64 val64; +u32 i; +enum vxge_hw_status status =VXGE_HW_OK ; + +vxge_assert (hldev); + + hldev->legacy_reg = (struct vxge_hw_legacy_reg *)hldev->bar0; + + hldev->toc_reg =__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 *)(hldev->bar0 + val64); + + val64 =readq (&hldev->toc_reg->toc_memrepair_pointer); + + hldev->memrepair_reg =
drivers/net/vxge/vxge-config.c line 555
Quoted 10 lines
drivers/net/vxge/vxge-config.c +10
-0+ (struct vxge_hw_memrepair_reg *)(hldev->bar0 + val64); + +for (i =0 ; i <VXGE_HW_TITAN_PCICFGMGMT_REG_SPACES ; i++) { + + val64 =readq (&hldev->toc_reg->toc_pcicfgmgmt_pointer[i]); + + hldev->pcicfgmgmt_reg[i] = (struct vxge_hw_pcicfgmgmt_reg *) \ + (hldev->bar0 + val64); + + }
This function
might have
too much
vertical whitespace.
[...]
Quoted 33 lines
drivers/net/vxge/vxge-config.c +33
-0+/** +* __hw_device_get_vpd_data - Getting vpd_data. +* +* @hldev: HW device handle. +* +* Getting product name and serial number from vpd capabilites structure +* +*/ +void +__hw_device_get_vpd_data (struct __hw_device *hldev) +{ +u8 *vpd_data; +u16 data; +u32 data32; +u32 index =0 , i, count, fail =0 ; +u32 addr_offset; +u32 data_offset; +u32 max_count = hldev->config.device_poll_millis *10 ; + +vxge_assert (hldev); + + addr_offset = hldev->pci_caps.vpd_cap_offset + + vxge_offsetof(struct vxge_hw_vpid_capability_le, vpd_address); + + data_offset = hldev->pci_caps.vpd_cap_offset + + vxge_offsetof(struct vxge_hw_vpid_capability_le, vpd_data); +strcpy ((char *) hldev->vpd_data.product_name, +"10 Gigabit Ethernet Adapter" ); + +strcpy ((char *) hldev->vpd_data.serial_num,"not available" ); + +if ((hldev->host_type !=VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION ) || + (hldev->func_id !=0 )) {
drivers/net/vxge/vxge-config.c line 869
Quoted 10 lines
drivers/net/vxge/vxge-config.c +10
-0+strcpy ((char *) hldev->vpd_data.serial_num, +"not supported" ); +strcpy ((char *) hldev->vpd_data.product_name, +"not supported" ); +return ; + } + vpd_data = (u8 *)vmalloc (VXGE_HW_VPD_BUFFER_SIZE +16 ); +if (vpd_data ==0 ) +return ; +for (index =0 ; index <VXGE_HW_VPD_BUFFER_SIZE ; index +=4 ) {
Use pci_read_vpd() instead of this loop.
[...]
drivers/net/vxge/vxge-config.c line 933
Quoted 11 lines
drivers/net/vxge/vxge-config.c +11
-0+/* +* vxge_hw_wrr_rebalance - Rebalance the RX_WRR and KDFC_WRR calandars. +* @devh: HW device handle. +* +* Rebalance the RX_WRR and KDFC_WRR calandars. +* +*/ +enum vxge_hw_status vxge_hw_wrr_rebalance (struct __hw_device *hldev) +{ +u64 val64; +u32 calender[176 ];
[...]
Why 176? This value should have at least a comment, but preferably a name or explicit formula.
Also should this variable be called "calendar"?
This is as far as I got.
Ben.
Signature · 3 lines
Ben Hutchings, Senior Software Engineer, Solarflare Communications Not speaking for my employer; that's the marketing department's job. They asked us to note that Solarflare product names are trademarked.
drivers/net/vxge/vxge-config.c line 49
Quoted 11 lines · Ramkrishna Vepa
drivers/net/vxge/vxge-config.c +11
-0+struct __hw_channel * +__hw_channel_allocate ( +struct __hw_device *hldev, +struct __hw_vpath_handle *vph, +enum __hw_channel_type type, +u32 length, +u32 alloc_work_array, +u32 alloc_free_array, +u32 alloc_reserve_array, +u32 per_dtr_space, +void *userdata)
Having so many arguments in a function is usually a clear sign that it needs to be refactored into smaller functions.
drivers/net/vxge/vxge-config.c line 72
Quoted 1 line
drivers/net/vxge/vxge-config.c +1
-0+ channel = (struct __hw_channel *)vmalloc (size);
You seem to use vmalloc nearly everywhere. First that has a lot of overhead (rounds up to pages, flushes TLBs) and also will cause more TLB misses. It's better to avoid it when not absolutely needed.
drivers/net/vxge/vxge-config.c line 157
Quoted 3 lines
drivers/net/vxge/vxge-config.c +3
-0+vxge_assert (channel !=NULL ); + + hldev = (struct __hw_device *)channel->devh;
That assert is pretyt pointless because you'll just get a NULL pointer reference next. Same true all over. asserts (or rather BUG_ON) only make sense when they check for something that's not nearly obvious given a oops.
drivers/net/vxge/vxge-config.c line 286
Quoted 8 lines
drivers/net/vxge/vxge-config.c +8
-0+while (next_ptr !=0 ) { + + cap_id =VXGE_HW_PCI_CAP_ID ((((u8 *)pci_config) + next_ptr)); + +switch (cap_id) { + +case VXGE_HW_PCI_CAP_ID_PM : + hldev->pci_caps.pm_cap_offset = next_ptr;
This all could be done much shorter with a table.
drivers/net/vxge/vxge-config.c line 333
Quoted 4 lines
drivers/net/vxge/vxge-config.c +4
-0+if (VXGE_HW_PCI_CONFIG_SPACE_SIZE <=0x100 ) + goto exit; + + next_ptr =0x100 ;
Such magic numbers are frowned upon.
Also in general you should use the pci capabilities accessor functions provided by the PCI layer.
Quoted 5 lines
drivers/net/vxge/vxge-config.c +5
-0+break ; +case VXGE_HW_PCI_EXT_CAP_ID_DSN : + hldev->pci_e_ext_caps.dsn_cap_offset = next_ptr; +break ; +case VXGE_HW_PCI_EXT_CAP_ID_PWR :
drivers/net/vxge/vxge-config.c line 361
Quoted 10 lines
drivers/net/vxge/vxge-config.c +10
-0+ hldev->pci_e_ext_caps.pwr_budget_cap_offset = next_ptr; +break ; + +default : + +break ; + } + + next_ptr = (u16 )VXGE_HW_PCI_EXT_CAP_NEXT ( + *(u32 *)(((u8 *)pci_config) + next_ptr));
Especially the patch orgies are scary. Does that really use readl() et.al. correctly? I doubt it. Again this should use the pci layer code for this.
drivers/net/vxge/vxge-config.c line 2053
Quoted 13 lines
drivers/net/vxge/vxge-config.c +13
-0+/** +* vxge_hw_device_private_set - Set driver context. +* @hldev: HW device handle. +* @data: pointer to driver context +* +* Use HW device to set driver context. +* +* See also: vxge_hw_device_private_get() +*/ +void vxge_hw_device_private_set (struct __hw_device *hldev,void *data) +{ + hldev->upper_layer_data = data; +}
Such wrappers are not encouraged in Linux code, which aims to do with only necessary abstraction. Lots of occurrences.
drivers/net/vxge/vxge-config.c line 2116
Quoted 6 lines
drivers/net/vxge/vxge-config.c +6
-0+ +#ifdef VXGE_HW_INTERNAL_COMPILER_ERROR + +#pragma optimize("", off) + +#endif
That's not for gcc isn't it?
drivers/net/vxge/vxge-config.c line 2129
Quoted 12 lines
drivers/net/vxge/vxge-config.c +12
-0+/* +* __hw_ring_block_memblock_idx - Return the memblock index +* @block: Virtual address of memory block +* +* This function returns the index of memory block +*/ +static inline u32 +__hw_ring_block_memblock_idx ( +u8 (block )[VXGE_HW_BLOCK_SIZE ]) +{ +return (u32)*((u64 *)((u8 *)block + +VXGE_HW_RING_MEMBLOCK_IDX_OFFSET ));
Is that readl/writel clean again?
In general your driver looks like it could use a pass with sparse's __iomem checking (make V=1)
drivers/net/vxge/vxge-config.c line 2311
Quoted 10 lines
drivers/net/vxge/vxge-config.c +10
-0+static enum vxge_hw_status +__hw_ring_mempool_item_alloc ( +struct vxge_hw_mempool *mempoolh, +void *memblock, +u32 memblock_index, +struct vxge_hw_mempool_dma *dma_object, +void *item, +u32 index, +u32 is_last, +void *userdata)
Again far too many arguments.
Stopped reading for now, but that file needs a lot of work in general.
-Andi
Andi,
Thanks for the comments. We are looking into them.
Question of the following -
Quoted 2 lines
In general your driver looks like it could use a pass with sparse's
__iomemchecking (make V=1)
How do I enable this checking?
Ram
Quoted 54 lines
drivers/net/vxge/vxge-config.c line 49
Quoted 11 lines
drivers/net/vxge/vxge-config.c +11
-0+struct __hw_channel * +__hw_channel_allocate ( +struct __hw_device *hldev, +struct __hw_vpath_handle *vph, +enum __hw_channel_type type, +u32 length, +u32 alloc_work_array, +u32 alloc_free_array, +u32 alloc_reserve_array, +u32 per_dtr_space, +void *userdata)Having so many arguments in a function is usually a clear sign that it needs
to be refactored into smaller functions.drivers/net/vxge/vxge-config.c line 72
Quoted 1 line
drivers/net/vxge/vxge-config.c +1
-0+ channel = (struct __hw_channel *)vmalloc (size);You seem to use vmalloc nearly everywhere. First that has a lot of overhead (rounds up to pages, flushes TLBs) and also will cause more TLB misses. It's better to avoid it when not absolutely needed.
drivers/net/vxge/vxge-config.c line 157
Quoted 3 lines
drivers/net/vxge/vxge-config.c +3
-0+vxge_assert (channel !=NULL ); + + hldev = (struct __hw_device *)channel->devh;That assert is pretyt pointless because you'll just get a NULL pointer reference next. Same true all over. asserts (or rather
BUG_ON) only make sense when they check for something that's not nearly obvious given a oops.drivers/net/vxge/vxge-config.c
Quoted 3 lines
drivers/net/vxge/vxge-config.c +3
-0+while (next_ptr !=0 ) { + + cap_id = VXGE_HW_PCI_CAP_ID((((u8 *)pci_config) +
next_ptr));drivers/net/vxge/vxge-config.c line 286
Quoted 5 lines
drivers/net/vxge/vxge-config.c +5
-0+ +switch (cap_id) { + +case VXGE_HW_PCI_CAP_ID_PM : + hldev->pci_caps.pm_cap_offset = next_ptr;This all could be done much shorter with a table.
drivers/net/vxge/vxge-config.c line 333
Quoted 4 lines
drivers/net/vxge/vxge-config.c +4
-0+if (VXGE_HW_PCI_CONFIG_SPACE_SIZE <=0x100 ) + goto exit; + + next_ptr =0x100 ;Such magic numbers are frowned upon.
Also in general you should use the pci capabilities accessor functions provided by the PCI layer.
Quoted 6 lines
drivers/net/vxge/vxge-config.c
Quoted 6 lines
drivers/net/vxge/vxge-config.c +6
-0+break ; +case VXGE_HW_PCI_EXT_CAP_ID_DSN : + hldev->pci_e_ext_caps.dsn_cap_offset = next_ptr; +break ; +case VXGE_HW_PCI_EXT_CAP_ID_PWR : + hldev->pci_e_ext_caps.pwr_budget_cap_offset =
next_ptr;
Quoted 9 lines
drivers/net/vxge/vxge-config.c
Quoted 9 lines
drivers/net/vxge/vxge-config.c +9
-0+break ; + +default : + +break ; + } + + next_ptr = (u16)VXGE_HW_PCI_EXT_CAP_NEXT( + *(u32 *)(((u8 *)pci_config) +
next_ptr));
Quoted 2 lines
Especially the patch orgies are scary. Does that really use
readl()
et.al.
Quoted 1 line
correctly? I doubt it. Again this should use the pci layer code for
this.
Quoted 11 lines
drivers/net/vxge/vxge-config.c
Quoted 11 lines
drivers/net/vxge/vxge-config.c +10
-0+/** +* vxge_hw_device_private_set - Set driver context. +* @hldev: HW device handle. +* @data: pointer to driver context +* +* Use HW device to set driver context. +* +* See also: vxge_hw_device_private_get() +*/ +void vxge_hw_device_private_set(struct __hw_device *hldev, void
*data)
Quoted 57 lines
drivers/net/vxge/vxge-config.c line 2053
Quoted 3 lines
drivers/net/vxge/vxge-config.c +3
-0+{ + hldev->upper_layer_data = data; +}Such wrappers are not encouraged in Linux code, which aims to do with only necessary abstraction. Lots of occurrences.
drivers/net/vxge/vxge-config.c line 2116
Quoted 6 lines
drivers/net/vxge/vxge-config.c +6
-0+ +#ifdef VXGE_HW_INTERNAL_COMPILER_ERROR + +#pragma optimize("", off) + +#endif That's not for gcc isn't it?
drivers/net/vxge/vxge-config.c line 2129
Quoted 12 lines
drivers/net/vxge/vxge-config.c +12
-0+/* +* __hw_ring_block_memblock_idx - Return the memblock index +* @block: Virtual address of memory block +* +* This function returns the index of memory block +*/ +static inline u32 +__hw_ring_block_memblock_idx ( +u8 (block )[VXGE_HW_BLOCK_SIZE ]) +{ +return (u32)*((u64 *)((u8 *)block + +VXGE_HW_RING_MEMBLOCK_IDX_OFFSET ));Is that readl/writel clean again?
In general your driver looks like it could use a pass with sparse's
__iomemchecking (make V=1)drivers/net/vxge/vxge-config.c line 2311
Quoted 10 lines
drivers/net/vxge/vxge-config.c +10
-0+static enum vxge_hw_status +__hw_ring_mempool_item_alloc ( +struct vxge_hw_mempool *mempoolh, +void *memblock, +u32 memblock_index, +struct vxge_hw_mempool_dma *dma_object, +void *item, +u32 index, +u32 is_last, +void *userdata)Again far too many arguments.
Stopped reading for now, but that file needs a lot of work in general.
-Andi
--
To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 8 lines · Ramkrishna Vepa
Andi,
Thanks for the comments. We are looking into them.
Question of the following -
Quoted 2 lines
In general your driver looks like it could use a pass with sparse's
__iomemchecking (make V=1)How do I enable this checking?
What Andi said, only without the typo: run "make C=1 drivers/net/vxge/"
Ben.
Signature · 3 lines
Ben Hutchings, Senior Software Engineer, Solarflare Communications Not speaking for my employer; that's the marketing department's job. They asked us to note that Solarflare product names are trademarked.
RE: [net-2.6 PATCH 6/10] Neterion: New driver: Hardware init &configuration
Ben,
Got it.
Thanks,
Ram
Quoted 8 lines
-----Original Message-----
From: Ben Hutchings [mailto:[email protected]]
Sent: Monday, March 16, 2009 8:35 PM
To: Ramkrishna Vepa
Cc: Andi Kleen; Netdev; David Miller
Subject: RE: [net-2.6 PATCH 6/10] Neterion: New driver: Hardware init &configuration
Quoted 7 lines
Quoted 6 lines · Ramkrishna Vepa
Andi,
Thanks for the comments. We are looking into them.
Question of the following -
Quoted 1 line
In general your driver looks like it could use a pass with
sparse's
Quoted 4 lines
Quoted 2 lines
Quoted 1 line
__iomemchecking (make V=1)How do I enable this checking?
What Andi said, only without the typo: run "make C=1
drivers/net/vxge/"
Quoted 7 lines
Ben.
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications Not speaking for my employer; that's the marketing department's job. They asked us to note that Solarflare product names are trademarked.
Quoted 4 lines · Ramkrishna Vepa
Question of the following -
Quoted 2 lines
In general your driver looks like it could use a pass with sparse's
__iomemchecking (make V=1)How do I enable this checking?
Install sparse and then
make V=1
and add __iomem annotations as needed.
There will be a lot of warnings, it's likely enough to concentrate on iomem first pass.
-Andi