nes: eeprom and phy routines
Subsystems (3)
PATCH v2 10/14 nes: eeprom and phy routines
Misc eeprom, phy, and debug routines.
Signed-off-by Glenn Grundstrom <[email protected]>
---
drivers/infiniband/hw/nes/nes_utils.c renamed from NULL +873 -0
@@ -0,0 +1,873 @@ +/* +* Copyright (c) 2006 - 2007 NetEffect, Inc. All rights reserved. +* +* This software is available to you under a choice of one of two +* licenses. You may choose to be licensed under the terms of the GNU +* General Public License (GPL) Version 2, available from the file +* COPYING in the main directory of this source tree, or the +* OpenIB.org BSD license below: +* +* Redistribution and use in source and binary forms, with or +* without modification, are permitted provided that the following +* conditions are met: +* +* - Redistributions of source code must retain the above +* copyright notice, this list of conditions and the following +* disclaimer. +* +* - Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +* SOFTWARE. +* +*/ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#include <linux/if_vlan.h> +#include <linux/crc32.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <linux/init.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/byteorder.h> + +#include "nes.h" + +#define BITMASK (X ) (1L << (X)) +#define NES_CRC_WID 32 + +static u16 nes_read16_eeprom (void __iomem *addr,u16 offset); + +static u32 nesCRCTable[256 ]; +static u32 nesCRCInitialized =0 ; + +static u32 nesCRCWidMask (u32 ); +static u32 nes_crc_table_gen (u32 *,u32 ,u32 ,u32 ); +static u32 reflect (u32 ,u32 ); +static u32 byte_swap (u32 ,u32 ); + +u32 mh_detected; +u32 mh_pauses_sent; + +/** +* nes_read_eeprom_values - +*/ +int nes_read_eeprom_values (struct nes_device *nesdev,struct nes_adapter *nesadapter) +{ +u32 mac_addr_low; +u16 mac_addr_high; +u16 eeprom_data; +u16 eeprom_offset; +u16 next_section_address; +u32 index; + +/* TODO: deal with EEPROM endian issues */ +if (nesadapter->firmware_eeprom_offset ==0 ) { +/* Read the EEPROM Parameters */ + eeprom_data =nes_read16_eeprom (nesdev->regs,0 ); +nes_debug (NES_DBG_HW ,"EEPROM Offset 0 = 0x%04X\n" , eeprom_data); + eeprom_offset =2 + (((eeprom_data &0x007f ) <<3 ) << + ((eeprom_data &0x0080 ) >>7 )); +nes_debug (NES_DBG_HW ,"Firmware Offset = 0x%04X\n" , eeprom_offset); + nesadapter->firmware_eeprom_offset = eeprom_offset; + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset +4 ); +if (eeprom_data !=0x5746 ) { +nes_debug (NES_DBG_HW ,"Not a valid Firmware Image = 0x%04X\n" , eeprom_data); +return -1 ; + } + + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset +2 ); +nes_debug (NES_DBG_HW ,"EEPROM Offset %u = 0x%04X\n" , + eeprom_offset +2 , eeprom_data); + eeprom_offset += ((eeprom_data &0x00ff ) <<3 ) << ((eeprom_data &0x0100 ) >>8 ); +nes_debug (NES_DBG_HW ,"Software Offset = 0x%04X\n" , eeprom_offset); + nesadapter->software_eeprom_offset = eeprom_offset; + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset +4 ); +if (eeprom_data !=0x5753 ) { +printk ("Not a valid Software Image = 0x%04X\n" , eeprom_data); +return -1 ; + } + + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset +2 ); +nes_debug (NES_DBG_HW ,"EEPROM Offset %u (next section) = 0x%04X\n" , + eeprom_offset +2 , eeprom_data); + next_section_address = eeprom_offset + (((eeprom_data &0x00ff ) <<3 ) << + ((eeprom_data &0x0100 ) >>8 )); + eeprom_data =nes_read16_eeprom (nesdev->regs, next_section_address +4 ); +if (eeprom_data !=0x414d ) { +nes_debug (NES_DBG_HW ,"EEPROM Changed offset should be 0x414d but was 0x%04X\n" , + eeprom_data); + goto no_fw_rev; + } + eeprom_offset = next_section_address; + + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset +2 ); +nes_debug (NES_DBG_HW ,"EEPROM Offset %u (next section) = 0x%04X\n" , + eeprom_offset +2 , eeprom_data); + next_section_address = eeprom_offset + (((eeprom_data &0x00ff ) <<3 ) << + ((eeprom_data &0x0100 ) >>8 )); + eeprom_data =nes_read16_eeprom (nesdev->regs, next_section_address +4 ); +if (eeprom_data !=0x4f52 ) { +nes_debug (NES_DBG_HW ,"EEPROM Changed offset should be 0x4f52 but was 0x%04X\n" , + eeprom_data); + goto no_fw_rev; + } + eeprom_offset = next_section_address; + + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset +2 ); +nes_debug (NES_DBG_HW ,"EEPROM Offset %u (next section) = 0x%04X\n" , + eeprom_offset +2 , eeprom_data); + next_section_address = eeprom_offset + ((eeprom_data &0x00ff ) <<3 ); + eeprom_data =nes_read16_eeprom (nesdev->regs, next_section_address +4 ); +if (eeprom_data !=0x5746 ) { +nes_debug (NES_DBG_HW ,"EEPROM Changed offset should be 0x5746 but was 0x%04X\n" , + eeprom_data); + goto no_fw_rev; + } + eeprom_offset = next_section_address; + + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset +2 ); +nes_debug (NES_DBG_HW ,"EEPROM Offset %u (next section) = 0x%04X\n" , + eeprom_offset +2 , eeprom_data); + next_section_address = eeprom_offset + ((eeprom_data &0x00ff ) <<3 ); + eeprom_data =nes_read16_eeprom (nesdev->regs, next_section_address +4 ); +if (eeprom_data !=0x5753 ) { +nes_debug (NES_DBG_HW ,"EEPROM Changed offset should be 0x5753 but was 0x%04X\n" , + eeprom_data); + goto no_fw_rev; + } + eeprom_offset = next_section_address; + + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset +2 ); +nes_debug (NES_DBG_HW ,"EEPROM Offset %u (next section) = 0x%04X\n" , + eeprom_offset +2 , eeprom_data); + next_section_address = eeprom_offset + ((eeprom_data &0x00ff ) <<3 ); + eeprom_data =nes_read16_eeprom (nesdev->regs, next_section_address +4 ); +if (eeprom_data !=0x414d ) { +nes_debug (NES_DBG_HW ,"EEPROM Changed offset should be 0x414d but was 0x%04X\n" , + eeprom_data); + goto no_fw_rev; + } + eeprom_offset = next_section_address; + + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset +2 ); +nes_debug (NES_DBG_HW ,"EEPROM Offset %u (next section) = 0x%04X\n" , + eeprom_offset +2 , eeprom_data); + next_section_address = eeprom_offset + ((eeprom_data &0x00ff ) <<3 ); + eeprom_data =nes_read16_eeprom (nesdev->regs, next_section_address +4 ); +if (eeprom_data !=0x464e ) { +nes_debug (NES_DBG_HW ,"EEPROM Changed offset should be 0x464e but was 0x%04X\n" , + eeprom_data); + goto no_fw_rev; + } + eeprom_data =nes_read16_eeprom (nesdev->regs, next_section_address +8 ); +printk (PFX "Firmware version %u.%u\n" , (u8)(eeprom_data>>8 ), (u8 )eeprom_data); + + nesadapter->firmware_version = (((u32)(u8)(eeprom_data>>8 )) <<16 ) + + (u32)((u8 )eeprom_data); + +no_fw_rev: +/* eeprom is valid */ + eeprom_offset = nesadapter->software_eeprom_offset; + eeprom_offset +=8 ; + nesadapter->netdev_max = (u8 )nes_read16_eeprom (nesdev->regs, eeprom_offset); + eeprom_offset +=2 ; + mac_addr_high =nes_read16_eeprom (nesdev->regs, eeprom_offset); + eeprom_offset +=2 ; + mac_addr_low = (u32 )nes_read16_eeprom (nesdev->regs, eeprom_offset); + eeprom_offset +=2 ; + mac_addr_low <<=16 ; + mac_addr_low += (u32 )nes_read16_eeprom (nesdev->regs, eeprom_offset); +nes_debug (NES_DBG_HW ,"Base MAC Address = 0x%04X%08X\n" , + mac_addr_high, mac_addr_low); +nes_debug (NES_DBG_HW ,"MAC Address count = %u\n" , nesadapter->netdev_max); + + nesadapter->mac_addr_low = mac_addr_low; + nesadapter->mac_addr_high = mac_addr_high; + +/* Read the Phy Type array */ + eeprom_offset +=10 ; + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset); +nes_debug (NES_DBG_HW ,"PhyType: 0x%04x\n" , eeprom_data); + +/* Read the port array */ + eeprom_offset +=2 ; + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset); +/* port_count is set by soft reset reg */ +for (index =0 ; index <4 ; index++) { + nesadapter->ports[index] = eeprom_data &0x000f ; + eeprom_data >>=4 ; + } +nes_debug (NES_DBG_HW ,"port_count = %u, port 0 -> %u, port 1 -> %u, port 2 -> %u, port 3 -> %u\n" , + nesadapter->port_count, + nesadapter->ports[0 ], nesadapter->ports[1 ], + nesadapter->ports[2 ], nesadapter->ports[3 ]); + + eeprom_offset +=46 ; + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset); + eeprom_offset +=2 ; + nesadapter->rx_pool_size = (((u32 )eeprom_data) <<16 ) + +nes_read16_eeprom (nesdev->regs, eeprom_offset); +nes_debug (NES_DBG_HW ,"rx_pool_size = 0x%08X\n" , nesadapter->rx_pool_size); + + eeprom_offset +=2 ; + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset); + eeprom_offset +=2 ; + nesadapter->tx_pool_size = (((u32 )eeprom_data) <<16 ) + +nes_read16_eeprom (nesdev->regs, eeprom_offset); +nes_debug (NES_DBG_HW ,"tx_pool_size = 0x%08X\n" , nesadapter->tx_pool_size); + + eeprom_offset +=2 ; + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset); + eeprom_offset +=2 ; + nesadapter->rx_threshold = (((u32 )eeprom_data) <<16 ) + +nes_read16_eeprom (nesdev->regs, eeprom_offset); +nes_debug (NES_DBG_HW ,"rx_threshold = 0x%08X\n" , nesadapter->rx_threshold); + + eeprom_offset +=2 ; + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset); + eeprom_offset +=2 ; + nesadapter->tcp_timer_core_clk_divisor = (((u32 )eeprom_data) <<16 ) + +nes_read16_eeprom (nesdev->regs, eeprom_offset); +nes_debug (NES_DBG_HW ,"tcp_timer_core_clk_divisor = 0x%08X\n" , + nesadapter->tcp_timer_core_clk_divisor); + + eeprom_offset +=2 ; + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset); + eeprom_offset +=2 ; + nesadapter->iwarp_config = (((u32 )eeprom_data) <<16 ) + +nes_read16_eeprom (nesdev->regs, eeprom_offset); +nes_debug (NES_DBG_HW ,"iwarp_config = 0x%08X\n" , nesadapter->iwarp_config); + + eeprom_offset +=2 ; + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset); + eeprom_offset +=2 ; + nesadapter->cm_config = (((u32 )eeprom_data) <<16 ) + +nes_read16_eeprom (nesdev->regs, eeprom_offset); +nes_debug (NES_DBG_HW ,"cm_config = 0x%08X\n" , nesadapter->cm_config); + + eeprom_offset +=2 ; + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset); + eeprom_offset +=2 ; + nesadapter->sws_timer_config = (((u32 )eeprom_data) <<16 ) + +nes_read16_eeprom (nesdev->regs, eeprom_offset); +nes_debug (NES_DBG_HW ,"sws_timer_config = 0x%08X\n" , nesadapter->sws_timer_config); + + eeprom_offset +=2 ; + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset); + eeprom_offset +=2 ; + nesadapter->tcp_config1 = (((u32 )eeprom_data) <<16 ) + +nes_read16_eeprom (nesdev->regs, eeprom_offset); +nes_debug (NES_DBG_HW ,"tcp_config1 = 0x%08X\n" , nesadapter->tcp_config1); + + eeprom_offset +=2 ; + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset); + eeprom_offset +=2 ; + nesadapter->wqm_wat = (((u32 )eeprom_data) <<16 ) + +nes_read16_eeprom (nesdev->regs, eeprom_offset); +nes_debug (NES_DBG_HW ,"wqm_wat = 0x%08X\n" , nesadapter->wqm_wat); + + eeprom_offset +=2 ; + eeprom_data =nes_read16_eeprom (nesdev->regs, eeprom_offset); + eeprom_offset +=2 ; + nesadapter->core_clock = (((u32 )eeprom_data) <<16 ) + +nes_read16_eeprom (nesdev->regs, eeprom_offset); +nes_debug (NES_DBG_HW ,"core_clock = 0x%08X\n" , nesadapter->core_clock); + } + + nesadapter->phy_index[0 ] =4 ; + nesadapter->phy_index[1 ] =5 ; + nesadapter->phy_index[2 ] =6 ; + nesadapter->phy_index[3 ] =7 ; + +/* TODO: get this from EEPROM */ + nesdev->base_doorbell_index =1 ; + +return 0 ; +} + + +/** +* nes_read16_eeprom +*/ +static u16 nes_read16_eeprom (void __iomem *addr,u16 offset) +{ +writel (NES_EEPROM_READ_REQUEST + (offset >>1 ), + (void __iomem *)addr +NES_EEPROM_COMMAND ); + +do { + }while (readl ((void __iomem *)addr +NES_EEPROM_COMMAND ) & +NES_EEPROM_READ_REQUEST ); + +return (readw ((void __iomem *)addr +NES_EEPROM_DATA )); +} + + +/** +* nes_write_1G_phy_reg +*/ +void nes_write_1G_phy_reg (struct nes_device *nesdev,u8 phy_reg,u8 phy_addr,u16 data) +{ +struct nes_adapter *nesadapter = nesdev->nesadapter; +u32 u32temp; +u32 counter; +unsigned long flags; + +spin_lock_irqsave (&nesadapter->phy_lock, flags); + +nes_write_indexed (nesdev,NES_IDX_MAC_MDIO_CONTROL , +0x50020000 | data | ((u32 )phy_reg <<18 ) | ((u32 )phy_addr <<23 )); +for (counter =0 ; counter <100 ; counter++) { +udelay (30 ); + u32temp =nes_read_indexed (nesdev,NES_IDX_MAC_INT_STATUS ); +if (u32temp &1 ) { +/* nes_debug(NES_DBG_PHY, "Phy interrupt status = 0x%X.\n", u32temp); */ +nes_write_indexed (nesdev,NES_IDX_MAC_INT_STATUS ,1 ); +break ; + } + } +if (!(u32temp &1 )) +nes_debug (NES_DBG_PHY ,"Phy is not responding. interrupt status = 0x%X.\n" , + u32temp); + +spin_unlock_irqrestore (&nesadapter->phy_lock, flags); +} + + +/** +* nes_read_1G_phy_reg +* This routine only issues the read, the data must be read +* separately. +*/ +void nes_read_1G_phy_reg (struct nes_device *nesdev,u8 phy_reg,u8 phy_addr,u16 *data) +{ +struct nes_adapter *nesadapter = nesdev->nesadapter; +u32 u32temp; +u32 counter; +unsigned long flags; + +/* nes_debug(NES_DBG_PHY, "%s: phy addr = %d, mac_index = %d\n", +__FUNCTION__, phy_addr, nesdev->mac_index); */ +spin_lock_irqsave (&nesadapter->phy_lock, flags); + +nes_write_indexed (nesdev,NES_IDX_MAC_MDIO_CONTROL , +0x60020000 | ((u32 )phy_reg <<18 ) | ((u32 )phy_addr <<23 )); +for (counter =0 ; counter <100 ; counter++) { +udelay (30 ); + u32temp =nes_read_indexed (nesdev,NES_IDX_MAC_INT_STATUS ); +if (u32temp &1 ) { +/* nes_debug(NES_DBG_PHY, "Phy interrupt status = 0x%X.\n", u32temp); */ +nes_write_indexed (nesdev,NES_IDX_MAC_INT_STATUS ,1 ); +break ; + } + } +if (!(u32temp &1 )) { +nes_debug (NES_DBG_PHY ,"Phy is not responding. interrupt status = 0x%X.\n" , + u32temp); + *data =0xffff ; + }else { + *data = (u16 )nes_read_indexed (nesdev,NES_IDX_MAC_MDIO_CONTROL ); + } +spin_unlock_irqrestore (&nesadapter->phy_lock, flags); +} + + +/** +* nes_write_10G_phy_reg +*/ +void nes_write_10G_phy_reg (struct nes_device *nesdev,u16 phy_reg, +u8 phy_addr,u16 data) +{ +u32 dev_addr; +u32 port_addr; +u32 u32temp; +u32 counter; + + dev_addr =5 ; + port_addr =0 ; + +/* set address */ +nes_write_indexed (nesdev,NES_IDX_MAC_MDIO_CONTROL , +0x00020000 | phy_reg | (dev_addr <<18 ) | (port_addr <<23 )); +for (counter =0 ; counter <100 ; counter++) { +udelay (30 ); + u32temp =nes_read_indexed (nesdev,NES_IDX_MAC_INT_STATUS ); +if (u32temp &1 ) { +nes_write_indexed (nesdev,NES_IDX_MAC_INT_STATUS ,1 ); +break ; + } + } +if (!(u32temp &1 )) +nes_debug (NES_DBG_PHY ,"Phy is not responding. interrupt status = 0x%X.\n" , + u32temp); + +/* set data */ +nes_write_indexed (nesdev,NES_IDX_MAC_MDIO_CONTROL , +0x10020000 | data | (dev_addr <<18 ) | (port_addr <<23 )); +for (counter =0 ; counter <100 ; counter++) { +udelay (30 ); + u32temp =nes_read_indexed (nesdev,NES_IDX_MAC_INT_STATUS ); +if (u32temp &1 ) { +nes_write_indexed (nesdev,NES_IDX_MAC_INT_STATUS ,1 ); +break ; + } + } +if (!(u32temp &1 )) +nes_debug (NES_DBG_PHY ,"Phy is not responding. interrupt status = 0x%X.\n" , + u32temp); +} + + +/** +* nes_read_10G_phy_reg +* This routine only issues the read, the data must be read +* separately. +*/ +void nes_read_10G_phy_reg (struct nes_device *nesdev,u16 phy_reg,u8 phy_addr) +{ +u32 dev_addr; +u32 port_addr; +u32 u32temp; +u32 counter; + + dev_addr =5 ; + port_addr =0 ; + +/* set address */ +nes_write_indexed (nesdev,NES_IDX_MAC_MDIO_CONTROL , +0x00020000 | phy_reg | (dev_addr <<18 ) | (port_addr <<23 )); +for (counter =0 ; counter <100 ; counter++) { +udelay (30 ); + u32temp =nes_read_indexed (nesdev,NES_IDX_MAC_INT_STATUS ); +if (u32temp &1 ) { +nes_write_indexed (nesdev,NES_IDX_MAC_INT_STATUS ,1 ); +break ; + } + } +if (!(u32temp &1 )) +nes_debug (NES_DBG_PHY ,"Phy is not responding. interrupt status = 0x%X.\n" , + u32temp); + +/* issue read */ +nes_write_indexed (nesdev,NES_IDX_MAC_MDIO_CONTROL , +0x30020000 | (dev_addr <<18 ) | (port_addr <<23 )); +for (counter =0 ; counter <100 ; counter++) { +udelay (30 ); + u32temp =nes_read_indexed (nesdev,NES_IDX_MAC_INT_STATUS ); +if (u32temp &1 ) { +nes_write_indexed (nesdev,NES_IDX_MAC_INT_STATUS ,1 ); +break ; + } + } +if (!(u32temp &1 )) +nes_debug (NES_DBG_PHY ,"Phy is not responding. interrupt status = 0x%X.\n" , + u32temp); +} + + +/** +* nes_arp_table +*/ +int nes_arp_table (struct nes_device *nesdev,u32 ip_addr,u8 *mac_addr,u32 action) +{ +struct nes_adapter *nesadapter = nesdev->nesadapter; +int arp_index; +int err =0 ; + +for (arp_index =0 ; (u32 ) arp_index < nesadapter->arp_table_size; arp_index++) { +if (nesadapter->arp_table[arp_index].ip_addr == ip_addr) +break ; + } + +if (action ==NES_ARP_ADD ) { +if (arp_index != nesadapter->arp_table_size) { +return -1 ; + } + + arp_index =0 ; + err =nes_alloc_resource (nesadapter, nesadapter->allocated_arps, + nesadapter->arp_table_size, &arp_index, &nesadapter->next_arp_index); +if (err) { +nes_debug (NES_DBG_NETDEV ,"nes_alloc_resource returned error = %u\n" , err); +return err; + } +nes_debug (NES_DBG_NETDEV ,"ADD, arp_index=%d\n" , arp_index); + + nesadapter->arp_table[arp_index].ip_addr = ip_addr; +memcpy (nesadapter->arp_table[arp_index].mac_addr, mac_addr,ETH_ALEN ); +return arp_index; + } + +/* DELETE or RESOLVE */ +if (arp_index == nesadapter->arp_table_size) { +nes_debug (NES_DBG_NETDEV ,"mac address not in ARP table - cannot delete or resolve\n" ); +return -1 ; + } + +if (action ==NES_ARP_RESOLVE ) { +nes_debug (NES_DBG_NETDEV ,"RESOLVE, arp_index=%d\n" , arp_index); +return arp_index; + } + +if (action ==NES_ARP_DELETE ) { +nes_debug (NES_DBG_NETDEV ,"DELETE, arp_index=%d\n" , arp_index); + nesadapter->arp_table[arp_index].ip_addr =0 ; +memset (nesadapter->arp_table[arp_index].mac_addr,0x00 ,ETH_ALEN ); +nes_free_resource (nesadapter, nesadapter->allocated_arps, arp_index); +return arp_index; + } + +return -1 ; +} + + +/** +* nes_mh_fix +*/ +void nes_mh_fix (unsigned long parm) +{ +unsigned long flags; +struct nes_device *nesdev = (struct nes_device *)parm; +struct nes_adapter *nesadapter = nesdev->nesadapter; +struct nes_vnic *nesvnic; +u32 used_chunks_tx; +u32 temp_used_chunks_tx; +u32 temp_last_used_chunks_tx; +u32 used_chunks_mask; +u32 mac_tx_frames_low; +u32 mac_tx_frames_high; +u32 mac_tx_pauses; +u32 serdes_status; +u32 reset_value; +u32 tx_control; +u32 tx_config; +u32 tx_pause_quanta; +u32 rx_control; +u32 rx_config; +u32 mac_exact_match; +u32 mpp_debug; +u32 i=0 ; +u32 chunks_tx_progress =0 ; + +spin_lock_irqsave (&nesadapter->phy_lock, flags); +if ((nesadapter->mac_sw_state[0 ] !=NES_MAC_SW_IDLE ) || (nesadapter->mac_link_down[0 ])) { +spin_unlock_irqrestore (&nesadapter->phy_lock, flags); + goto no_mh_work; + } + nesadapter->mac_sw_state[0 ] =NES_MAC_SW_MH ; +spin_unlock_irqrestore (&nesadapter->phy_lock, flags); +do { + mac_tx_frames_low =nes_read_indexed (nesdev,NES_IDX_MAC_TX_FRAMES_LOW ); + mac_tx_frames_high =nes_read_indexed (nesdev,NES_IDX_MAC_TX_FRAMES_HIGH ); + mac_tx_pauses =nes_read_indexed (nesdev,NES_IDX_MAC_TX_PAUSE_FRAMES ); + used_chunks_tx =nes_read_indexed (nesdev,NES_IDX_USED_CHUNKS_TX ); + nesdev->mac_pause_frames_sent += mac_tx_pauses; + used_chunks_mask =0 ; + temp_used_chunks_tx = used_chunks_tx; + temp_last_used_chunks_tx = nesdev->last_used_chunks_tx; + +if (nesdev->netdev[0 ]) { + nesvnic =netdev_priv (nesdev->netdev[0 ]); + }else { +break ; + } + +for (i=0 ; i<4 ; i++) { + used_chunks_mask <<=8 ; +if (nesvnic->qp_nic_index[i] !=0xff ) { + used_chunks_mask |=0xff ; +if ((temp_used_chunks_tx&0xff )<(temp_last_used_chunks_tx&0xff )) { + chunks_tx_progress =1 ; + } + } + temp_used_chunks_tx >>=8 ; + temp_last_used_chunks_tx >>=8 ; + } +if ((mac_tx_frames_low) || (mac_tx_frames_high) || + (!(used_chunks_tx&used_chunks_mask)) || + (!(nesdev->last_used_chunks_tx&used_chunks_mask)) || + (chunks_tx_progress) ) { + nesdev->last_used_chunks_tx = used_chunks_tx; +break ; + } + nesdev->last_used_chunks_tx = used_chunks_tx; +barrier (); + +nes_write_indexed (nesdev,NES_IDX_MAC_TX_CONTROL ,0x00000005 ); + mh_pauses_sent++; + mac_tx_pauses =nes_read_indexed (nesdev,NES_IDX_MAC_TX_PAUSE_FRAMES ); +if (mac_tx_pauses) { + nesdev->mac_pause_frames_sent += mac_tx_pauses; +break ; + } + + tx_control =nes_read_indexed (nesdev,NES_IDX_MAC_TX_CONTROL ); + tx_config =nes_read_indexed (nesdev,NES_IDX_MAC_TX_CONFIG ); + tx_pause_quanta =nes_read_indexed (nesdev,NES_IDX_MAC_TX_PAUSE_QUANTA ); + rx_control =nes_read_indexed (nesdev,NES_IDX_MAC_RX_CONTROL ); + rx_config =nes_read_indexed (nesdev,NES_IDX_MAC_RX_CONFIG ); + mac_exact_match =nes_read_indexed (nesdev,NES_IDX_MAC_EXACT_MATCH_BOTTOM ); + mpp_debug =nes_read_indexed (nesdev,NES_IDX_MPP_DEBUG ); + +/* one last ditch effort to avoid a false positive */ + mac_tx_pauses =nes_read_indexed (nesdev,NES_IDX_MAC_TX_PAUSE_FRAMES ); +if (mac_tx_pauses) { + nesdev->last_mac_tx_pauses = nesdev->mac_pause_frames_sent; +nes_debug (NES_DBG_HW ,"failsafe caught slow outbound pause\n" ); +break ; + } + mh_detected++; + +nes_write_indexed (nesdev,NES_IDX_MAC_TX_CONTROL ,0x00000000 ); +nes_write_indexed (nesdev,NES_IDX_MAC_TX_CONFIG ,0x00000000 ); + reset_value =nes_read32 (nesdev->regs+NES_SOFTWARE_RESET ); + +nes_write32 (nesdev->regs+NES_SOFTWARE_RESET , reset_value |0x0000001d ); + +while (((nes_read32 (nesdev->regs+NES_SOFTWARE_RESET ) + &0x00000040 ) !=0x00000040 ) && (i++ <5000 )) { +/* mdelay(1); */ + } + +nes_write_indexed (nesdev,NES_IDX_ETH_SERDES_COMMON_CONTROL0 ,0x00000008 ); + serdes_status =nes_read_indexed (nesdev,NES_IDX_ETH_SERDES_COMMON_STATUS0 ); + +nes_write_indexed (nesdev,NES_IDX_ETH_SERDES_TX_EMP0 ,0x000bdef7 ); +nes_write_indexed (nesdev,NES_IDX_ETH_SERDES_TX_DRIVE0 ,0x9ce73000 ); +nes_write_indexed (nesdev,NES_IDX_ETH_SERDES_RX_MODE0 ,0x0ff00000 ); +nes_write_indexed (nesdev,NES_IDX_ETH_SERDES_RX_SIGDET0 ,0x00000000 ); +nes_write_indexed (nesdev,NES_IDX_ETH_SERDES_BYPASS0 ,0x00000000 ); +nes_write_indexed (nesdev,NES_IDX_ETH_SERDES_LOOPBACK_CONTROL0 ,0x00000000 ); +if (nesadapter->OneG_Mode) { +nes_write_indexed (nesdev,NES_IDX_ETH_SERDES_RX_EQ_CONTROL0 ,0xf0182222 ); + }else { +nes_write_indexed (nesdev,NES_IDX_ETH_SERDES_RX_EQ_CONTROL0 ,0xf0042222 ); + } + serdes_status =nes_read_indexed (nesdev,NES_IDX_ETH_SERDES_RX_EQ_STATUS0 ); +nes_write_indexed (nesdev,NES_IDX_ETH_SERDES_CDR_CONTROL0 ,0x000000ff ); + +nes_write_indexed (nesdev,NES_IDX_MAC_TX_CONTROL , tx_control); +nes_write_indexed (nesdev,NES_IDX_MAC_TX_CONFIG , tx_config); +nes_write_indexed (nesdev,NES_IDX_MAC_TX_PAUSE_QUANTA , tx_pause_quanta); +nes_write_indexed (nesdev,NES_IDX_MAC_RX_CONTROL , rx_control); +nes_write_indexed (nesdev,NES_IDX_MAC_RX_CONFIG , rx_config); +nes_write_indexed (nesdev,NES_IDX_MAC_EXACT_MATCH_BOTTOM , mac_exact_match); +nes_write_indexed (nesdev,NES_IDX_MPP_DEBUG , mpp_debug); + + }while (0 ); + + nesadapter->mac_sw_state[0 ] =NES_MAC_SW_IDLE ; +no_mh_work: + nesdev->nesadapter->mh_timer.expires = jiffies + (HZ /5 ); +add_timer (&nesdev->nesadapter->mh_timer); +} + + +/* +"Everything you wanted to know about CRC algorithms, but were afraid to ask +for fear that errors in your understanding might be detected." Version : 3. +Date : 19 August 1993. +Author : Ross N. Williams. +Net : [email protected]. +FTP : ftp.adelaide.edu.au/pub/rocksoft/crc_v3.txt +Company : Rocksoft™ Pty Ltd. +Snail : 16 Lerwick Avenue, Hazelwood Park 5066, Australia. +Fax : +61 8 373-4911 (c/- Internode Systems Pty Ltd). +Phone : +61 8 379-9217 (10am to 10pm Adelaide Australia time). +Note : "Rocksoft" is a trademark of Rocksoft Pty Ltd, Australia. +Status : Copyright (C) Ross Williams, 1993. However, permission is granted to +make and distribute verbatim copies of this document provided that this information +block and copyright notice is included. Also, the C code modules included in this +document are fully public domain. + +Thanks : Thanks to Jean-loup Gailly ([email protected]) and Mark Adler +([email protected]) who both proof read this document and picked +out lots of nits as well as some big fat bugs. + +The current web page for this seems to be http://www.ross.net/crc/crcpaper.html. + +*/ + +/****************************************************************************/ +/* Generate width mask */ +/****************************************************************************/ +/* */ +/* Returns a longword whose value is (2^p_cm->cm_width)-1. */ +/* The trick is to do this portably (e.g. without doing <<32). */ +/* */ +/* Author: Tristan Gross */ +/* Source: "A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS" */ +/* Ross N. Williams */ +/* http://www.rocksoft.com */ +/* */ +/****************************************************************************/ + +static u32 nesCRCWidMask (u32 width) +{ +return (((1L <<(((u32 )width)-1 ))-1L )<<1 )|1L ; +} + + +/****************************************************************************/ +/* Generate CRC table */ +/****************************************************************************/ +/* */ +/* Source: "A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS" */ +/* Ross N. Williams */ +/* http://www.rocksoft.com */ +/* */ +/****************************************************************************/ +static u32 nes_crc_table_gen (u32 *pCRCTable, +u32 poly, +u32 order, +u32 reflectIn) +{ +u32 i; +u32 reg; +u32 byte; +u32 topbit =BITMASK (NES_CRC_WID -1 ); +u32 tmp; + +for (byte=0 ;byte<256 ;byte++) { + +// If we need to creat a reflected table we must reflect the index (byte) and +// reflect the final reg + tmp = (reflectIn) ?reflect (byte,8 ): byte; + + reg = tmp << (NES_CRC_WID -8 ); + +for (i=0 ; i<8 ; i++) { +if (reg & topbit) { + reg = (reg <<1 ) ^ poly; + }else { + reg <<=1 ; + } + } + + reg = (reflectIn) ?reflect (reg,order): reg; + pCRCTable[byte] = reg &nesCRCWidMask (NES_CRC_WID ); + } + +return 0 ; +} + + +/****************************************************************************/ +/* Perform 32 bit based CRC calculation */ +/****************************************************************************/ +/* */ +/* Source: "A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS" */ +/* Ross N. Williams */ +/* http://www.rocksoft.com */ +/* */ +/* This performs a standard 32 bit crc on an array of arbitrary length */ +/* with an arbitrary initial value and passed generator polynomial */ +/* in the form of a crc table. */ +/* */ +/****************************************************************************/ +static u32 reflect (u32 data,u32 num) +{ +/* Reflects the lower num bits in 'data' around their center point. */ +u32 i; +u32 j =1 ; +u32 result =0 ; + +for (i=(u32 )1 <<(num-1 ); i; i>>=1 ) { +if (data & i) result|=j; + j <<=1 ; + } +return result; +} + + +/** +* byte_swap +*/ +static u32 byte_swap (u32 data,u32 num) +{ +u32 i; +u32 result =0 ; + +if (num%16 ) { +dprintk ("\nbyte_swap: ERROR: num is not an even number of bytes\n" ); +/* ASSERT(0); */ + } + +for (i =0 ; i < num; i +=8 ) { + result |= (0xFF & (data >> i)) << (num-8 -i); + } + +return result; +} + + +/** +* nes_crc32 - +* This is a reflected table algorithm. ReflectIn basically +* means to reflect each incomming byte of the data. But to make +* things more complicated, we can instead reflect the initial +* value, the final crc, and shift data to the right using a +* reflected pCRCTable. CRC is FUN!! +*/ +u32 nes_crc32 (u32 reverse, +u32 initialValue, +u32 finalXOR, +u32 messageLength, +u8 *pMessage, +u32 order, +u32 reflectIn, +u32 reflectOut) + +{ +u8 *pBlockAddr = pMessage; +u32 mlen = messageLength; +u32 crc; + +if (0 == nesCRCInitialized) { +nes_crc_table_gen ( &nesCRCTable[0 ],CRC32C_POLY ,ORDER ,REFIN ); + nesCRCInitialized =1 ; + } + + crc = (reflectIn) ?reflect (initialValue,order): initialValue; + +while (mlen--) { +/* printf("byte = %x, index = %u, crctable[index] = %x\n", +*pBlockAddr, (crc & 0xffL) ^ *pBlockAddr, +nesCRCTable[(crc & 0xffL) ^ *pBlockAddr]); +*/ +if (reflectIn) { + crc = nesCRCTable[(crc &0xffL ) ^ *pBlockAddr++] ^ (crc >>8 ); + }else { + crc = nesCRCTable[((crc>>24 ) ^ *pBlockAddr++) &0xFFL ] ^ (crc <<8 ); + } + } + +/* if reflectOut and reflectIn are both set, we don't */ +/* do anything since reflecting twice effectively does nothing. */ + crc = ((reflectIn)^(reflectOut)) ?reflect (crc,order): crc; + + crc = crc^finalXOR; + +/* We don't really use this, but it is here for completeness */ + crc = (reverse) ?byte_swap (crc,32 ): crc; + +return crc; +} +
drivers/infiniband/hw/nes/nes_utils.c line 81
Quoted 1 line
drivers/infiniband/hw/nes/nes_utils.c renamed from NULL +1
-0+/* TODO: deal with EEPROM endian issues */
This is pretty scary. Is the driver broken on big-endian systems now?
Quoted 3 lines
+/*
+"Everything you wanted to know about CRC algorithms, but were afraid to ask
+ for fear that errors in your understanding might be detected." Version : 3.
etc etc... can all this be replaced with what's in lib/crc32.c? (I hope so)
- R.
Quoted 8 lines
Quoted 2 lines
+/*
+"Everything you wanted to know about CRC algorithms, butwere afraid to ask
Quoted 1 line
+ for fear that errors in your understanding might be
detected." Version : 3.
etc etc... can all this be replaced with what's in
lib/crc32.c? (I hope so)
Replacing this code is already in the works.
Glenn.
Quoted 3 lines
- R.