X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Ftxgbe%2Fbase%2Ftxgbe_hw.c;h=9023ff1980b6dc00db409e010c9257cbfc185764;hb=127a1abe6cbe7dc9b6f21a3e7d25da72a000868a;hp=3ba2e233c0fd45f338762e68253af1356bd0c294;hpb=01c3cf5c85a796bccd585447ca3832df7350e7ab;p=dpdk.git diff --git a/drivers/net/txgbe/base/txgbe_hw.c b/drivers/net/txgbe/base/txgbe_hw.c index 3ba2e233c0..9023ff1980 100644 --- a/drivers/net/txgbe/base/txgbe_hw.c +++ b/drivers/net/txgbe/base/txgbe_hw.c @@ -11,11 +11,81 @@ #define TXGBE_RAPTOR_MAX_TX_QUEUES 128 #define TXGBE_RAPTOR_MAX_RX_QUEUES 128 #define TXGBE_RAPTOR_RAR_ENTRIES 128 +#define TXGBE_RAPTOR_MC_TBL_SIZE 128 static s32 txgbe_setup_copper_link_raptor(struct txgbe_hw *hw, u32 speed, bool autoneg_wait_to_complete); +static s32 txgbe_mta_vector(struct txgbe_hw *hw, u8 *mc_addr); +static s32 txgbe_get_san_mac_addr_offset(struct txgbe_hw *hw, + u16 *san_mac_offset); + +/** + * txgbe_start_hw - Prepare hardware for Tx/Rx + * @hw: pointer to hardware structure + * + * Starts the hardware by filling the bus info structure and media type, clears + * all on chip counters, initializes receive address registers, multicast + * table, VLAN filter table, calls routine to set up link and flow control + * settings, and leaves transmit and receive units disabled and uninitialized + **/ +s32 txgbe_start_hw(struct txgbe_hw *hw) +{ + u16 device_caps; + + DEBUGFUNC("txgbe_start_hw"); + + /* Set the media type */ + hw->phy.media_type = hw->phy.get_media_type(hw); + + /* Clear statistics registers */ + hw->mac.clear_hw_cntrs(hw); + + /* Cache bit indicating need for crosstalk fix */ + switch (hw->mac.type) { + case txgbe_mac_raptor: + hw->mac.get_device_caps(hw, &device_caps); + if (device_caps & TXGBE_DEVICE_CAPS_NO_CROSSTALK_WR) + hw->need_crosstalk_fix = false; + else + hw->need_crosstalk_fix = true; + break; + default: + hw->need_crosstalk_fix = false; + break; + } + + /* Clear adapter stopped flag */ + hw->adapter_stopped = false; + + return 0; +} + +/** + * txgbe_start_hw_gen2 - Init sequence for common device family + * @hw: pointer to hw structure + * + * Performs the init sequence common to the second generation + * of 10 GbE devices. + **/ +s32 txgbe_start_hw_gen2(struct txgbe_hw *hw) +{ + u32 i; + + /* Clear the rate limiters */ + for (i = 0; i < hw->mac.max_tx_queues; i++) { + wr32(hw, TXGBE_ARBPOOLIDX, i); + wr32(hw, TXGBE_ARBTXRATE, 0); + } + txgbe_flush(hw); + + /* We need to run link autotry after the driver loads */ + hw->mac.autotry_restart = true; + + return 0; +} + /** * txgbe_init_hw - Generic hardware initialization * @hw: pointer to hardware structure @@ -45,6 +115,35 @@ s32 txgbe_init_hw(struct txgbe_hw *hw) return status; } +/** + * txgbe_get_mac_addr - Generic get MAC address + * @hw: pointer to hardware structure + * @mac_addr: Adapter MAC address + * + * Reads the adapter's MAC address from first Receive Address Register (RAR0) + * A reset of the adapter must be performed prior to calling this function + * in order for the MAC address to have been loaded from the EEPROM into RAR0 + **/ +s32 txgbe_get_mac_addr(struct txgbe_hw *hw, u8 *mac_addr) +{ + u32 rar_high; + u32 rar_low; + u16 i; + + DEBUGFUNC("txgbe_get_mac_addr"); + + wr32(hw, TXGBE_ETHADDRIDX, 0); + rar_high = rd32(hw, TXGBE_ETHADDRH); + rar_low = rd32(hw, TXGBE_ETHADDRL); + + for (i = 0; i < 2; i++) + mac_addr[i] = (u8)(rar_high >> (1 - i) * 8); + + for (i = 0; i < 4; i++) + mac_addr[i + 2] = (u8)(rar_low >> (3 - i) * 8); + + return 0; +} /** * txgbe_set_lan_id_multi_port - Set LAN id for PCIe multiple port devices @@ -71,6 +170,59 @@ void txgbe_set_lan_id_multi_port(struct txgbe_hw *hw) bus->func = bus->lan_id; } +/** + * txgbe_stop_hw - Generic stop Tx/Rx units + * @hw: pointer to hardware structure + * + * Sets the adapter_stopped flag within txgbe_hw struct. Clears interrupts, + * disables transmit and receive units. The adapter_stopped flag is used by + * the shared code and drivers to determine if the adapter is in a stopped + * state and should not touch the hardware. + **/ +s32 txgbe_stop_hw(struct txgbe_hw *hw) +{ + u32 reg_val; + u16 i; + + DEBUGFUNC("txgbe_stop_hw"); + + /* + * Set the adapter_stopped flag so other driver functions stop touching + * the hardware + */ + hw->adapter_stopped = true; + + /* Disable the receive unit */ + txgbe_disable_rx(hw); + + /* Clear interrupt mask to stop interrupts from being generated */ + wr32(hw, TXGBE_IENMISC, 0); + wr32(hw, TXGBE_IMS(0), TXGBE_IMS_MASK); + wr32(hw, TXGBE_IMS(1), TXGBE_IMS_MASK); + + /* Clear any pending interrupts, flush previous writes */ + wr32(hw, TXGBE_ICRMISC, TXGBE_ICRMISC_MASK); + wr32(hw, TXGBE_ICR(0), TXGBE_ICR_MASK); + wr32(hw, TXGBE_ICR(1), TXGBE_ICR_MASK); + + /* Disable the transmit unit. Each queue must be disabled. */ + for (i = 0; i < hw->mac.max_tx_queues; i++) + wr32(hw, TXGBE_TXCFG(i), TXGBE_TXCFG_FLUSH); + + /* Disable the receive unit by stopping each queue */ + for (i = 0; i < hw->mac.max_rx_queues; i++) { + reg_val = rd32(hw, TXGBE_RXCFG(i)); + reg_val &= ~TXGBE_RXCFG_ENA; + wr32(hw, TXGBE_RXCFG(i), reg_val); + } + + /* flush all queues disables */ + txgbe_flush(hw); + msec_delay(2); + + return 0; +} + /** * txgbe_validate_mac_addr - Validate MAC address * @mac_addr: pointer to MAC address. @@ -97,6 +249,547 @@ s32 txgbe_validate_mac_addr(u8 *mac_addr) return status; } +/** + * txgbe_set_rar - Set Rx address register + * @hw: pointer to hardware structure + * @index: Receive address register to write + * @addr: Address to put into receive address register + * @vmdq: VMDq "set" or "pool" index + * @enable_addr: set flag that address is active + * + * Puts an ethernet address into a receive address register. + **/ +s32 txgbe_set_rar(struct txgbe_hw *hw, u32 index, u8 *addr, u32 vmdq, + u32 enable_addr) +{ + u32 rar_low, rar_high; + u32 rar_entries = hw->mac.num_rar_entries; + + DEBUGFUNC("txgbe_set_rar"); + + /* Make sure we are using a valid rar index range */ + if (index >= rar_entries) { + DEBUGOUT("RAR index %d is out of range.\n", index); + return TXGBE_ERR_INVALID_ARGUMENT; + } + + /* setup VMDq pool selection before this RAR gets enabled */ + hw->mac.set_vmdq(hw, index, vmdq); + + /* + * HW expects these in little endian so we reverse the byte + * order from network order (big endian) to little endian + */ + rar_low = TXGBE_ETHADDRL_AD0(addr[5]) | + TXGBE_ETHADDRL_AD1(addr[4]) | + TXGBE_ETHADDRL_AD2(addr[3]) | + TXGBE_ETHADDRL_AD3(addr[2]); + /* + * Some parts put the VMDq setting in the extra RAH bits, + * so save everything except the lower 16 bits that hold part + * of the address and the address valid bit. + */ + rar_high = rd32(hw, TXGBE_ETHADDRH); + rar_high &= ~TXGBE_ETHADDRH_AD_MASK; + rar_high |= (TXGBE_ETHADDRH_AD4(addr[1]) | + TXGBE_ETHADDRH_AD5(addr[0])); + + rar_high &= ~TXGBE_ETHADDRH_VLD; + if (enable_addr != 0) + rar_high |= TXGBE_ETHADDRH_VLD; + + wr32(hw, TXGBE_ETHADDRIDX, index); + wr32(hw, TXGBE_ETHADDRL, rar_low); + wr32(hw, TXGBE_ETHADDRH, rar_high); + + return 0; +} + +/** + * txgbe_clear_rar - Remove Rx address register + * @hw: pointer to hardware structure + * @index: Receive address register to write + * + * Clears an ethernet address from a receive address register. + **/ +s32 txgbe_clear_rar(struct txgbe_hw *hw, u32 index) +{ + u32 rar_high; + u32 rar_entries = hw->mac.num_rar_entries; + + DEBUGFUNC("txgbe_clear_rar"); + + /* Make sure we are using a valid rar index range */ + if (index >= rar_entries) { + DEBUGOUT("RAR index %d is out of range.\n", index); + return TXGBE_ERR_INVALID_ARGUMENT; + } + + /* + * Some parts put the VMDq setting in the extra RAH bits, + * so save everything except the lower 16 bits that hold part + * of the address and the address valid bit. + */ + wr32(hw, TXGBE_ETHADDRIDX, index); + rar_high = rd32(hw, TXGBE_ETHADDRH); + rar_high &= ~(TXGBE_ETHADDRH_AD_MASK | TXGBE_ETHADDRH_VLD); + + wr32(hw, TXGBE_ETHADDRL, 0); + wr32(hw, TXGBE_ETHADDRH, rar_high); + + /* clear VMDq pool/queue selection for this RAR */ + hw->mac.clear_vmdq(hw, index, BIT_MASK32); + + return 0; +} + +/** + * txgbe_init_rx_addrs - Initializes receive address filters. + * @hw: pointer to hardware structure + * + * Places the MAC address in receive address register 0 and clears the rest + * of the receive address registers. Clears the multicast table. Assumes + * the receiver is in reset when the routine is called. + **/ +s32 txgbe_init_rx_addrs(struct txgbe_hw *hw) +{ + u32 i; + u32 psrctl; + u32 rar_entries = hw->mac.num_rar_entries; + + DEBUGFUNC("txgbe_init_rx_addrs"); + + /* + * If the current mac address is valid, assume it is a software override + * to the permanent address. + * Otherwise, use the permanent address from the eeprom. + */ + if (txgbe_validate_mac_addr(hw->mac.addr) == + TXGBE_ERR_INVALID_MAC_ADDR) { + /* Get the MAC address from the RAR0 for later reference */ + hw->mac.get_mac_addr(hw, hw->mac.addr); + + DEBUGOUT(" Keeping Current RAR0 Addr =%.2X %.2X %.2X ", + hw->mac.addr[0], hw->mac.addr[1], + hw->mac.addr[2]); + DEBUGOUT("%.2X %.2X %.2X\n", hw->mac.addr[3], + hw->mac.addr[4], hw->mac.addr[5]); + } else { + /* Setup the receive address. */ + DEBUGOUT("Overriding MAC Address in RAR[0]\n"); + DEBUGOUT(" New MAC Addr =%.2X %.2X %.2X ", + hw->mac.addr[0], hw->mac.addr[1], + hw->mac.addr[2]); + DEBUGOUT("%.2X %.2X %.2X\n", hw->mac.addr[3], + hw->mac.addr[4], hw->mac.addr[5]); + + hw->mac.set_rar(hw, 0, hw->mac.addr, 0, true); + } + + /* clear VMDq pool/queue selection for RAR 0 */ + hw->mac.clear_vmdq(hw, 0, BIT_MASK32); + + hw->addr_ctrl.overflow_promisc = 0; + + hw->addr_ctrl.rar_used_count = 1; + + /* Zero out the other receive addresses. */ + DEBUGOUT("Clearing RAR[1-%d]\n", rar_entries - 1); + for (i = 1; i < rar_entries; i++) { + wr32(hw, TXGBE_ETHADDRIDX, i); + wr32(hw, TXGBE_ETHADDRL, 0); + wr32(hw, TXGBE_ETHADDRH, 0); + } + + /* Clear the MTA */ + hw->addr_ctrl.mta_in_use = 0; + psrctl = rd32(hw, TXGBE_PSRCTL); + psrctl &= ~(TXGBE_PSRCTL_ADHF12_MASK | TXGBE_PSRCTL_MCHFENA); + psrctl |= TXGBE_PSRCTL_ADHF12(hw->mac.mc_filter_type); + wr32(hw, TXGBE_PSRCTL, psrctl); + + DEBUGOUT(" Clearing MTA\n"); + for (i = 0; i < hw->mac.mcft_size; i++) + wr32(hw, TXGBE_MCADDRTBL(i), 0); + + txgbe_init_uta_tables(hw); + + return 0; +} + +/** + * txgbe_mta_vector - Determines bit-vector in multicast table to set + * @hw: pointer to hardware structure + * @mc_addr: the multicast address + * + * Extracts the 12 bits, from a multicast address, to determine which + * bit-vector to set in the multicast table. The hardware uses 12 bits, from + * incoming rx multicast addresses, to determine the bit-vector to check in + * the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set + * by the MO field of the PSRCTRL. The MO field is set during initialization + * to mc_filter_type. + **/ +static s32 txgbe_mta_vector(struct txgbe_hw *hw, u8 *mc_addr) +{ + u32 vector = 0; + + DEBUGFUNC("txgbe_mta_vector"); + + switch (hw->mac.mc_filter_type) { + case 0: /* use bits [47:36] of the address */ + vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4)); + break; + case 1: /* use bits [46:35] of the address */ + vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5)); + break; + case 2: /* use bits [45:34] of the address */ + vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6)); + break; + case 3: /* use bits [43:32] of the address */ + vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8)); + break; + default: /* Invalid mc_filter_type */ + DEBUGOUT("MC filter type param set incorrectly\n"); + ASSERT(0); + break; + } + + /* vector can only be 12-bits or boundary will be exceeded */ + vector &= 0xFFF; + return vector; +} + +/** + * txgbe_set_mta - Set bit-vector in multicast table + * @hw: pointer to hardware structure + * @mc_addr: Multicast address + * + * Sets the bit-vector in the multicast table. + **/ +void txgbe_set_mta(struct txgbe_hw *hw, u8 *mc_addr) +{ + u32 vector; + u32 vector_bit; + u32 vector_reg; + + DEBUGFUNC("txgbe_set_mta"); + + hw->addr_ctrl.mta_in_use++; + + vector = txgbe_mta_vector(hw, mc_addr); + DEBUGOUT(" bit-vector = 0x%03X\n", vector); + + /* + * The MTA is a register array of 128 32-bit registers. It is treated + * like an array of 4096 bits. We want to set bit + * BitArray[vector_value]. So we figure out what register the bit is + * in, read it, OR in the new bit, then write back the new value. The + * register is determined by the upper 7 bits of the vector value and + * the bit within that register are determined by the lower 5 bits of + * the value. + */ + vector_reg = (vector >> 5) & 0x7F; + vector_bit = vector & 0x1F; + hw->mac.mta_shadow[vector_reg] |= (1 << vector_bit); +} + +/** + * txgbe_update_mc_addr_list - Updates MAC list of multicast addresses + * @hw: pointer to hardware structure + * @mc_addr_list: the list of new multicast addresses + * @mc_addr_count: number of addresses + * @next: iterator function to walk the multicast address list + * @clear: flag, when set clears the table beforehand + * + * When the clear flag is set, the given list replaces any existing list. + * Hashes the given addresses into the multicast table. + **/ +s32 txgbe_update_mc_addr_list(struct txgbe_hw *hw, u8 *mc_addr_list, + u32 mc_addr_count, txgbe_mc_addr_itr next, + bool clear) +{ + u32 i; + u32 vmdq; + + DEBUGFUNC("txgbe_update_mc_addr_list"); + + /* + * Set the new number of MC addresses that we are being requested to + * use. + */ + hw->addr_ctrl.num_mc_addrs = mc_addr_count; + hw->addr_ctrl.mta_in_use = 0; + + /* Clear mta_shadow */ + if (clear) { + DEBUGOUT(" Clearing MTA\n"); + memset(&hw->mac.mta_shadow, 0, sizeof(hw->mac.mta_shadow)); + } + + /* Update mta_shadow */ + for (i = 0; i < mc_addr_count; i++) { + DEBUGOUT(" Adding the multicast addresses:\n"); + txgbe_set_mta(hw, next(hw, &mc_addr_list, &vmdq)); + } + + /* Enable mta */ + for (i = 0; i < hw->mac.mcft_size; i++) + wr32a(hw, TXGBE_MCADDRTBL(0), i, + hw->mac.mta_shadow[i]); + + if (hw->addr_ctrl.mta_in_use > 0) { + u32 psrctl = rd32(hw, TXGBE_PSRCTL); + psrctl &= ~(TXGBE_PSRCTL_ADHF12_MASK | TXGBE_PSRCTL_MCHFENA); + psrctl |= TXGBE_PSRCTL_MCHFENA | + TXGBE_PSRCTL_ADHF12(hw->mac.mc_filter_type); + wr32(hw, TXGBE_PSRCTL, psrctl); + } + + DEBUGOUT("txgbe update mc addr list complete\n"); + return 0; +} + +/** + * txgbe_disable_sec_rx_path - Stops the receive data path + * @hw: pointer to hardware structure + * + * Stops the receive data path and waits for the HW to internally empty + * the Rx security block + **/ +s32 txgbe_disable_sec_rx_path(struct txgbe_hw *hw) +{ +#define TXGBE_MAX_SECRX_POLL 4000 + + int i; + u32 secrxreg; + + DEBUGFUNC("txgbe_disable_sec_rx_path"); + + secrxreg = rd32(hw, TXGBE_SECRXCTL); + secrxreg |= TXGBE_SECRXCTL_XDSA; + wr32(hw, TXGBE_SECRXCTL, secrxreg); + for (i = 0; i < TXGBE_MAX_SECRX_POLL; i++) { + secrxreg = rd32(hw, TXGBE_SECRXSTAT); + if (!(secrxreg & TXGBE_SECRXSTAT_RDY)) + /* Use interrupt-safe sleep just in case */ + usec_delay(10); + else + break; + } + + /* For informational purposes only */ + if (i >= TXGBE_MAX_SECRX_POLL) + DEBUGOUT("Rx unit being enabled before security " + "path fully disabled. Continuing with init.\n"); + + return 0; +} + +/** + * txgbe_enable_sec_rx_path - Enables the receive data path + * @hw: pointer to hardware structure + * + * Enables the receive data path. + **/ +s32 txgbe_enable_sec_rx_path(struct txgbe_hw *hw) +{ + u32 secrxreg; + + DEBUGFUNC("txgbe_enable_sec_rx_path"); + + secrxreg = rd32(hw, TXGBE_SECRXCTL); + secrxreg &= ~TXGBE_SECRXCTL_XDSA; + wr32(hw, TXGBE_SECRXCTL, secrxreg); + txgbe_flush(hw); + + return 0; +} + +/** + * txgbe_disable_sec_tx_path - Stops the transmit data path + * @hw: pointer to hardware structure + * + * Stops the transmit data path and waits for the HW to internally empty + * the Tx security block + **/ +int txgbe_disable_sec_tx_path(struct txgbe_hw *hw) +{ +#define TXGBE_MAX_SECTX_POLL 40 + + int i; + u32 sectxreg; + + sectxreg = rd32(hw, TXGBE_SECTXCTL); + sectxreg |= TXGBE_SECTXCTL_XDSA; + wr32(hw, TXGBE_SECTXCTL, sectxreg); + for (i = 0; i < TXGBE_MAX_SECTX_POLL; i++) { + sectxreg = rd32(hw, TXGBE_SECTXSTAT); + if (sectxreg & TXGBE_SECTXSTAT_RDY) + break; + /* Use interrupt-safe sleep just in case */ + usec_delay(1000); + } + + /* For informational purposes only */ + if (i >= TXGBE_MAX_SECTX_POLL) + PMD_DRV_LOG(DEBUG, "Tx unit being enabled before security " + "path fully disabled. Continuing with init."); + + return 0; +} + +/** + * txgbe_enable_sec_tx_path - Enables the transmit data path + * @hw: pointer to hardware structure + * + * Enables the transmit data path. + **/ +int txgbe_enable_sec_tx_path(struct txgbe_hw *hw) +{ + uint32_t sectxreg; + + sectxreg = rd32(hw, TXGBE_SECTXCTL); + sectxreg &= ~TXGBE_SECTXCTL_XDSA; + wr32(hw, TXGBE_SECTXCTL, sectxreg); + txgbe_flush(hw); + + return 0; +} + +/** + * txgbe_get_san_mac_addr_offset - Get SAN MAC address offset from the EEPROM + * @hw: pointer to hardware structure + * @san_mac_offset: SAN MAC address offset + * + * This function will read the EEPROM location for the SAN MAC address + * pointer, and returns the value at that location. This is used in both + * get and set mac_addr routines. + **/ +static s32 txgbe_get_san_mac_addr_offset(struct txgbe_hw *hw, + u16 *san_mac_offset) +{ + s32 err; + + DEBUGFUNC("txgbe_get_san_mac_addr_offset"); + + /* + * First read the EEPROM pointer to see if the MAC addresses are + * available. + */ + err = hw->rom.readw_sw(hw, TXGBE_SAN_MAC_ADDR_PTR, + san_mac_offset); + if (err) { + DEBUGOUT("eeprom at offset %d failed", + TXGBE_SAN_MAC_ADDR_PTR); + } + + return err; +} + +/** + * txgbe_get_san_mac_addr - SAN MAC address retrieval from the EEPROM + * @hw: pointer to hardware structure + * @san_mac_addr: SAN MAC address + * + * Reads the SAN MAC address from the EEPROM, if it's available. This is + * per-port, so set_lan_id() must be called before reading the addresses. + * set_lan_id() is called by identify_sfp(), but this cannot be relied + * upon for non-SFP connections, so we must call it here. + **/ +s32 txgbe_get_san_mac_addr(struct txgbe_hw *hw, u8 *san_mac_addr) +{ + u16 san_mac_data, san_mac_offset; + u8 i; + s32 err; + + DEBUGFUNC("txgbe_get_san_mac_addr"); + + /* + * First read the EEPROM pointer to see if the MAC addresses are + * available. If they're not, no point in calling set_lan_id() here. + */ + err = txgbe_get_san_mac_addr_offset(hw, &san_mac_offset); + if (err || san_mac_offset == 0 || san_mac_offset == 0xFFFF) + goto san_mac_addr_out; + + /* apply the port offset to the address offset */ + (hw->bus.func) ? (san_mac_offset += TXGBE_SAN_MAC_ADDR_PORT1_OFFSET) : + (san_mac_offset += TXGBE_SAN_MAC_ADDR_PORT0_OFFSET); + for (i = 0; i < 3; i++) { + err = hw->rom.read16(hw, san_mac_offset, + &san_mac_data); + if (err) { + DEBUGOUT("eeprom read at offset %d failed", + san_mac_offset); + goto san_mac_addr_out; + } + san_mac_addr[i * 2] = (u8)(san_mac_data); + san_mac_addr[i * 2 + 1] = (u8)(san_mac_data >> 8); + san_mac_offset++; + } + return 0; + +san_mac_addr_out: + /* + * No addresses available in this EEPROM. It's not an + * error though, so just wipe the local address and return. + */ + for (i = 0; i < 6; i++) + san_mac_addr[i] = 0xFF; + return 0; +} + +/** + * txgbe_set_san_mac_addr - Write the SAN MAC address to the EEPROM + * @hw: pointer to hardware structure + * @san_mac_addr: SAN MAC address + * + * Write a SAN MAC address to the EEPROM. + **/ +s32 txgbe_set_san_mac_addr(struct txgbe_hw *hw, u8 *san_mac_addr) +{ + s32 err; + u16 san_mac_data, san_mac_offset; + u8 i; + + DEBUGFUNC("txgbe_set_san_mac_addr"); + + /* Look for SAN mac address pointer. If not defined, return */ + err = txgbe_get_san_mac_addr_offset(hw, &san_mac_offset); + if (err || san_mac_offset == 0 || san_mac_offset == 0xFFFF) + return TXGBE_ERR_NO_SAN_ADDR_PTR; + + /* Apply the port offset to the address offset */ + (hw->bus.func) ? (san_mac_offset += TXGBE_SAN_MAC_ADDR_PORT1_OFFSET) : + (san_mac_offset += TXGBE_SAN_MAC_ADDR_PORT0_OFFSET); + + for (i = 0; i < 3; i++) { + san_mac_data = (u16)((u16)(san_mac_addr[i * 2 + 1]) << 8); + san_mac_data |= (u16)(san_mac_addr[i * 2]); + hw->rom.write16(hw, san_mac_offset, san_mac_data); + san_mac_offset++; + } + + return 0; +} + +/** + * txgbe_init_uta_tables - Initialize the Unicast Table Array + * @hw: pointer to hardware structure + **/ +s32 txgbe_init_uta_tables(struct txgbe_hw *hw) +{ + int i; + + DEBUGFUNC("txgbe_init_uta_tables"); + DEBUGOUT(" Clearing UTA\n"); + + for (i = 0; i < 128; i++) + wr32(hw, TXGBE_UCADDRTBL(i), 0); + + return 0; +} + /** * txgbe_need_crosstalk_fix - Determine if we need to do cross talk fix * @hw: pointer to hardware structure @@ -208,6 +901,23 @@ s32 txgbe_check_mac_link(struct txgbe_hw *hw, u32 *speed, return 0; } +/** + * txgbe_get_device_caps - Get additional device capabilities + * @hw: pointer to hardware structure + * @device_caps: the EEPROM word with the extra device capabilities + * + * This function will read the EEPROM location for the device capabilities, + * and return the word through device_caps. + **/ +s32 txgbe_get_device_caps(struct txgbe_hw *hw, u16 *device_caps) +{ + DEBUGFUNC("txgbe_get_device_caps"); + + hw->rom.readw_sw(hw, TXGBE_DEVICE_CAPS, device_caps); + + return 0; +} + /** * txgbe_clear_tx_pending - Clear pending TX work from the PCIe fifo * @hw: pointer to the hardware structure @@ -250,6 +960,38 @@ void txgbe_clear_tx_pending(struct txgbe_hw *hw) wr32(hw, TXGBE_PSRCTL, hlreg0); } +void txgbe_disable_rx(struct txgbe_hw *hw) +{ + u32 pfdtxgswc; + + pfdtxgswc = rd32(hw, TXGBE_PSRCTL); + if (pfdtxgswc & TXGBE_PSRCTL_LBENA) { + pfdtxgswc &= ~TXGBE_PSRCTL_LBENA; + wr32(hw, TXGBE_PSRCTL, pfdtxgswc); + hw->mac.set_lben = true; + } else { + hw->mac.set_lben = false; + } + + wr32m(hw, TXGBE_PBRXCTL, TXGBE_PBRXCTL_ENA, 0); + wr32m(hw, TXGBE_MACRXCFG, TXGBE_MACRXCFG_ENA, 0); +} + +void txgbe_enable_rx(struct txgbe_hw *hw) +{ + u32 pfdtxgswc; + + wr32m(hw, TXGBE_MACRXCFG, TXGBE_MACRXCFG_ENA, TXGBE_MACRXCFG_ENA); + wr32m(hw, TXGBE_PBRXCTL, TXGBE_PBRXCTL_ENA, TXGBE_PBRXCTL_ENA); + + if (hw->mac.set_lben) { + pfdtxgswc = rd32(hw, TXGBE_PSRCTL); + pfdtxgswc |= TXGBE_PSRCTL_LBENA; + wr32(hw, TXGBE_PSRCTL, pfdtxgswc); + hw->mac.set_lben = false; + } +} + /** * txgbe_setup_mac_link_multispeed_fiber - Set MAC link speed * @hw: pointer to hardware structure @@ -578,6 +1320,38 @@ init_phy_ops_out: return err; } +s32 txgbe_setup_sfp_modules(struct txgbe_hw *hw) +{ + s32 err = 0; + + DEBUGFUNC("txgbe_setup_sfp_modules"); + + if (hw->phy.sfp_type == txgbe_sfp_type_unknown) + return 0; + + txgbe_init_mac_link_ops(hw); + + /* PHY config will finish before releasing the semaphore */ + err = hw->mac.acquire_swfw_sync(hw, TXGBE_MNGSEM_SWPHY); + if (err != 0) + return TXGBE_ERR_SWFW_SYNC; + + /* Release the semaphore */ + hw->mac.release_swfw_sync(hw, TXGBE_MNGSEM_SWPHY); + + /* Delay obtaining semaphore again to allow FW access + * prot_autoc_write uses the semaphore too. + */ + msec_delay(hw->rom.semaphore_delay); + + if (err) { + DEBUGOUT("sfp module setup not complete\n"); + return TXGBE_ERR_SFP_SETUP_NOT_COMPLETE; + } + + return err; +} + /** * txgbe_init_ops_pf - Inits func ptrs and MAC type * @hw: pointer to hardware structure @@ -598,6 +1372,7 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw) bus->set_lan_id = txgbe_set_lan_id_multi_port; /* PHY */ + phy->get_media_type = txgbe_get_media_type_raptor; phy->identify = txgbe_identify_phy; phy->init = txgbe_init_phy_raptor; phy->read_reg = txgbe_read_phy_reg; @@ -614,10 +1389,29 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw) /* MAC */ mac->init_hw = txgbe_init_hw; + mac->start_hw = txgbe_start_hw_raptor; + mac->enable_rx_dma = txgbe_enable_rx_dma_raptor; + mac->get_mac_addr = txgbe_get_mac_addr; + mac->stop_hw = txgbe_stop_hw; mac->reset_hw = txgbe_reset_hw; + + mac->disable_sec_rx_path = txgbe_disable_sec_rx_path; + mac->enable_sec_rx_path = txgbe_enable_sec_rx_path; + mac->disable_sec_tx_path = txgbe_disable_sec_tx_path; + mac->enable_sec_tx_path = txgbe_enable_sec_tx_path; + mac->get_san_mac_addr = txgbe_get_san_mac_addr; + mac->set_san_mac_addr = txgbe_set_san_mac_addr; + mac->get_device_caps = txgbe_get_device_caps; mac->autoc_read = txgbe_autoc_read; mac->autoc_write = txgbe_autoc_write; + mac->set_rar = txgbe_set_rar; + mac->clear_rar = txgbe_clear_rar; + mac->init_rx_addrs = txgbe_init_rx_addrs; + mac->enable_rx = txgbe_enable_rx; + mac->disable_rx = txgbe_disable_rx; + mac->init_uta_tables = txgbe_init_uta_tables; + mac->setup_sfp = txgbe_setup_sfp_modules; /* Link */ mac->get_link_capabilities = txgbe_get_link_capabilities_raptor; mac->check_link = txgbe_check_mac_link; @@ -636,6 +1430,7 @@ s32 txgbe_init_ops_pf(struct txgbe_hw *hw) rom->update_checksum = txgbe_update_eeprom_checksum; rom->calc_checksum = txgbe_calc_eeprom_checksum; + mac->mcft_size = TXGBE_RAPTOR_MC_TBL_SIZE; mac->num_rar_entries = TXGBE_RAPTOR_RAR_ENTRIES; mac->max_rx_queues = TXGBE_RAPTOR_MAX_RX_QUEUES; mac->max_tx_queues = TXGBE_RAPTOR_MAX_TX_QUEUES; @@ -753,6 +1548,52 @@ s32 txgbe_get_link_capabilities_raptor(struct txgbe_hw *hw, return status; } +/** + * txgbe_get_media_type_raptor - Get media type + * @hw: pointer to hardware structure + * + * Returns the media type (fiber, copper, backplane) + **/ +u32 txgbe_get_media_type_raptor(struct txgbe_hw *hw) +{ + u32 media_type; + + DEBUGFUNC("txgbe_get_media_type_raptor"); + + /* Detect if there is a copper PHY attached. */ + switch (hw->phy.type) { + case txgbe_phy_cu_unknown: + case txgbe_phy_tn: + media_type = txgbe_media_type_copper; + return media_type; + default: + break; + } + + switch (hw->device_id) { + case TXGBE_DEV_ID_RAPTOR_KR_KX_KX4: + /* Default device ID is mezzanine card KX/KX4 */ + media_type = txgbe_media_type_backplane; + break; + case TXGBE_DEV_ID_RAPTOR_SFP: + case TXGBE_DEV_ID_WX1820_SFP: + media_type = txgbe_media_type_fiber; + break; + case TXGBE_DEV_ID_RAPTOR_QSFP: + media_type = txgbe_media_type_fiber_qsfp; + break; + case TXGBE_DEV_ID_RAPTOR_XAUI: + case TXGBE_DEV_ID_RAPTOR_SGMII: + media_type = txgbe_media_type_copper; + break; + default: + media_type = txgbe_media_type_unknown; + break; + } + + return media_type; +} + /** * txgbe_start_mac_link_raptor - Setup MAC link settings * @hw: pointer to hardware structure @@ -1172,6 +2013,68 @@ txgbe_check_flash_load(struct txgbe_hw *hw, u32 check_bit) return err; } +static void +txgbe_reset_misc(struct txgbe_hw *hw) +{ + int i; + u32 value; + + wr32(hw, TXGBE_ISBADDRL, hw->isb_dma & 0x00000000FFFFFFFF); + wr32(hw, TXGBE_ISBADDRH, hw->isb_dma >> 32); + + value = rd32_epcs(hw, SR_XS_PCS_CTRL2); + if ((value & 0x3) != SR_PCS_CTRL2_TYPE_SEL_X) + hw->link_status = TXGBE_LINK_STATUS_NONE; + + /* receive packets that size > 2048 */ + wr32m(hw, TXGBE_MACRXCFG, + TXGBE_MACRXCFG_JUMBO, TXGBE_MACRXCFG_JUMBO); + + wr32m(hw, TXGBE_FRMSZ, TXGBE_FRMSZ_MAX_MASK, + TXGBE_FRMSZ_MAX(TXGBE_FRAME_SIZE_DFT)); + + /* clear counters on read */ + wr32m(hw, TXGBE_MACCNTCTL, + TXGBE_MACCNTCTL_RC, TXGBE_MACCNTCTL_RC); + + wr32m(hw, TXGBE_RXFCCFG, + TXGBE_RXFCCFG_FC, TXGBE_RXFCCFG_FC); + wr32m(hw, TXGBE_TXFCCFG, + TXGBE_TXFCCFG_FC, TXGBE_TXFCCFG_FC); + + wr32m(hw, TXGBE_MACRXFLT, + TXGBE_MACRXFLT_PROMISC, TXGBE_MACRXFLT_PROMISC); + + wr32m(hw, TXGBE_RSTSTAT, + TXGBE_RSTSTAT_TMRINIT_MASK, TXGBE_RSTSTAT_TMRINIT(30)); + + /* errata 4: initialize mng flex tbl and wakeup flex tbl*/ + wr32(hw, TXGBE_MNGFLEXSEL, 0); + for (i = 0; i < 16; i++) { + wr32(hw, TXGBE_MNGFLEXDWL(i), 0); + wr32(hw, TXGBE_MNGFLEXDWH(i), 0); + wr32(hw, TXGBE_MNGFLEXMSK(i), 0); + } + wr32(hw, TXGBE_LANFLEXSEL, 0); + for (i = 0; i < 16; i++) { + wr32(hw, TXGBE_LANFLEXDWL(i), 0); + wr32(hw, TXGBE_LANFLEXDWH(i), 0); + wr32(hw, TXGBE_LANFLEXMSK(i), 0); + } + + /* set pause frame dst mac addr */ + wr32(hw, TXGBE_RXPBPFCDMACL, 0xC2000001); + wr32(hw, TXGBE_RXPBPFCDMACH, 0x0180); + + hw->mac.init_thermal_sensor_thresh(hw); + + /* enable mac transmitter */ + wr32m(hw, TXGBE_MACTXCFG, TXGBE_MACTXCFG_TXE, TXGBE_MACTXCFG_TXE); + + for (i = 0; i < 4; i++) + wr32m(hw, TXGBE_IVAR(i), 0x80808080, 0); +} + /** * txgbe_reset_hw - Perform hardware reset * @hw: pointer to hardware structure @@ -1230,6 +2133,8 @@ mac_reset_top: } usec_delay(10); + txgbe_reset_misc(hw); + if (hw->bus.lan_id == 0) { status = txgbe_check_flash_load(hw, TXGBE_ILDRSTAT_SWRST_LAN0); @@ -1302,6 +2207,65 @@ mac_reset_top: return status; } +/** + * txgbe_start_hw_raptor - Prepare hardware for Tx/Rx + * @hw: pointer to hardware structure + * + * Starts the hardware using the generic start_hw function + * and the generation start_hw function. + * Then performs revision-specific operations, if any. + **/ +s32 txgbe_start_hw_raptor(struct txgbe_hw *hw) +{ + s32 err = 0; + + DEBUGFUNC("txgbe_start_hw_raptor"); + + err = txgbe_start_hw(hw); + if (err != 0) + goto out; + + err = txgbe_start_hw_gen2(hw); + if (err != 0) + goto out; + + /* We need to run link autotry after the driver loads */ + hw->mac.autotry_restart = true; + +out: + return err; +} + +/** + * txgbe_enable_rx_dma_raptor - Enable the Rx DMA unit + * @hw: pointer to hardware structure + * @regval: register value to write to RXCTRL + * + * Enables the Rx DMA unit + **/ +s32 txgbe_enable_rx_dma_raptor(struct txgbe_hw *hw, u32 regval) +{ + DEBUGFUNC("txgbe_enable_rx_dma_raptor"); + + /* + * Workaround silicon errata when enabling the Rx datapath. + * If traffic is incoming before we enable the Rx unit, it could hang + * the Rx DMA unit. Therefore, make sure the security engine is + * completely disabled prior to enabling the Rx unit. + */ + + hw->mac.disable_sec_rx_path(hw); + + if (regval & TXGBE_PBRXCTL_ENA) + txgbe_enable_rx(hw); + else + txgbe_disable_rx(hw); + + hw->mac.enable_sec_rx_path(hw); + + return 0; +} + /** * txgbe_verify_lesm_fw_enabled_raptor - Checks LESM FW module state. * @hw: pointer to hardware structure