xgmac.c
来自「linux 内核源代码」· C语言 代码 · 共 656 行 · 第 1/2 页
C
656 行
/* * Copyright (c) 2005-2007 Chelsio, 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 "common.h"#include "regs.h"/* * # of exact address filters. The first one is used for the station address, * the rest are available for multicast addresses. */#define EXACT_ADDR_FILTERS 8static inline int macidx(const struct cmac *mac){ return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);}static void xaui_serdes_reset(struct cmac *mac){ static const unsigned int clear[] = { F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1, F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3 }; int i; struct adapter *adap = mac->adapter; u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset; t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] | F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 | F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 | F_RESETPLL23 | F_RESETPLL01); t3_read_reg(adap, ctrl); udelay(15); for (i = 0; i < ARRAY_SIZE(clear); i++) { t3_set_reg_field(adap, ctrl, clear[i], 0); udelay(15); }}void t3b_pcs_reset(struct cmac *mac){ t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, F_PCS_RESET_, 0); udelay(20); t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0, F_PCS_RESET_);}int t3_mac_reset(struct cmac *mac){ static const struct addr_val_pair mac_reset_avp[] = { {A_XGM_TX_CTRL, 0}, {A_XGM_RX_CTRL, 0}, {A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES | F_RMFCS | F_ENJUMBO | F_ENHASHMCAST}, {A_XGM_RX_HASH_LOW, 0}, {A_XGM_RX_HASH_HIGH, 0}, {A_XGM_RX_EXACT_MATCH_LOW_1, 0}, {A_XGM_RX_EXACT_MATCH_LOW_2, 0}, {A_XGM_RX_EXACT_MATCH_LOW_3, 0}, {A_XGM_RX_EXACT_MATCH_LOW_4, 0}, {A_XGM_RX_EXACT_MATCH_LOW_5, 0}, {A_XGM_RX_EXACT_MATCH_LOW_6, 0}, {A_XGM_RX_EXACT_MATCH_LOW_7, 0}, {A_XGM_RX_EXACT_MATCH_LOW_8, 0}, {A_XGM_STAT_CTRL, F_CLRSTATS} }; u32 val; struct adapter *adap = mac->adapter; unsigned int oft = mac->offset; t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft); t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft, F_RXSTRFRWRD | F_DISERRFRAMES, uses_xaui(adap) ? 0 : F_RXSTRFRWRD); t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX); if (uses_xaui(adap)) { if (adap->params.rev == 0) { t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, F_RXENABLE | F_TXENABLE); if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft, F_CMULOCK, 1, 5, 2)) { CH_ERR(adap, "MAC %d XAUI SERDES CMU lock failed\n", macidx(mac)); return -1; } t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0, F_SERDESRESET_); } else xaui_serdes_reset(mac); } t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft, V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE), V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER); val = F_MAC_RESET_ | F_XGMAC_STOP_EN; if (is_10G(adap)) val |= F_PCS_RESET_; else if (uses_xaui(adap)) val |= F_PCS_RESET_ | F_XG2G_RESET_; else val |= F_RGMII_RESET_ | F_XG2G_RESET_; t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ if ((val & F_PCS_RESET_) && adap->params.rev) { msleep(1); t3b_pcs_reset(mac); } memset(&mac->stats, 0, sizeof(mac->stats)); return 0;}static int t3b2_mac_reset(struct cmac *mac){ struct adapter *adap = mac->adapter; unsigned int oft = mac->offset; u32 val; if (!macidx(mac)) t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0); else t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0); t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_); t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ msleep(10); /* Check for xgm Rx fifo empty */ if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft, 0x80000000, 1, 5, 2)) { CH_ERR(adap, "MAC %d Rx fifo drain failed\n", macidx(mac)); return -1; } t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ val = F_MAC_RESET_; if (is_10G(adap)) val |= F_PCS_RESET_; else if (uses_xaui(adap)) val |= F_PCS_RESET_ | F_XG2G_RESET_; else val |= F_RGMII_RESET_ | F_XG2G_RESET_; t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val); t3_read_reg(adap, A_XGM_RESET_CTRL + oft); /* flush */ if ((val & F_PCS_RESET_) && adap->params.rev) { msleep(1); t3b_pcs_reset(mac); } t3_write_reg(adap, A_XGM_RX_CFG + oft, F_DISPAUSEFRAMES | F_EN1536BFRAMES | F_RMFCS | F_ENJUMBO | F_ENHASHMCAST); if (!macidx(mac)) t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE); else t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE); return 0;}/* * Set the exact match register 'idx' to recognize the given Ethernet address. */static void set_addr_filter(struct cmac *mac, int idx, const u8 * addr){ u32 addr_lo, addr_hi; unsigned int oft = mac->offset + idx * 8; addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; addr_hi = (addr[5] << 8) | addr[4]; t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo); t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);}/* Set one of the station's unicast MAC addresses. */int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]){ if (idx >= mac->nucast) return -EINVAL; set_addr_filter(mac, idx, addr); return 0;}/* * Specify the number of exact address filters that should be reserved for * unicast addresses. Caller should reload the unicast and multicast addresses * after calling this. */int t3_mac_set_num_ucast(struct cmac *mac, int n){ if (n > EXACT_ADDR_FILTERS) return -EINVAL; mac->nucast = n; return 0;}static void disable_exact_filters(struct cmac *mac){ unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1; for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) { u32 v = t3_read_reg(mac->adapter, reg); t3_write_reg(mac->adapter, reg, v); } t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */}static void enable_exact_filters(struct cmac *mac){ unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1; for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) { u32 v = t3_read_reg(mac->adapter, reg); t3_write_reg(mac->adapter, reg, v); } t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */}/* Calculate the RX hash filter index of an Ethernet address */static int hash_hw_addr(const u8 * addr){ int hash = 0, octet, bit, i = 0, c; for (octet = 0; octet < 6; ++octet) for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) { hash ^= (c & 1) << i; if (++i == 6) i = 0; } return hash;}int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm){ u32 val, hash_lo, hash_hi; struct adapter *adap = mac->adapter; unsigned int oft = mac->offset; val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES; if (rm->dev->flags & IFF_PROMISC) val |= F_COPYALLFRAMES; t3_write_reg(adap, A_XGM_RX_CFG + oft, val); if (rm->dev->flags & IFF_ALLMULTI) hash_lo = hash_hi = 0xffffffff; else { u8 *addr; int exact_addr_idx = mac->nucast; hash_lo = hash_hi = 0; while ((addr = t3_get_next_mcaddr(rm))) if (exact_addr_idx < EXACT_ADDR_FILTERS) set_addr_filter(mac, exact_addr_idx++, addr); else { int hash = hash_hw_addr(addr); if (hash < 32) hash_lo |= (1 << hash); else hash_hi |= (1 << (hash - 32)); } } t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo); t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi); return 0;}static int rx_fifo_hwm(int mtu){ int hwm; hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100); return min(hwm, MAC_RXFIFO_SIZE - 8192);}int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu){ int hwm, lwm, divisor; int ipg; unsigned int thres, v, reg; struct adapter *adap = mac->adapter; /* * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't. The HW max * packet size register includes header, but not FCS.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?