mv_eth.c
来自「适合KS8695X」· C语言 代码 · 共 1,878 行 · 第 1/5 页
C
1,878 行
* memory parameters are used by the Rx and Tx ring initialization
* routines in order to curve the descriptor linked list in a form
* of a ring.
* Note: Pay special attention to alignment issues when using
* cached descriptors/buffers. In this phase the driver store
* information in the ETH_PORT_INFO struct regarding each queue
* ring.
*
* Driver start
* This phase prepares the Ethernet port for Rx and Tx activity.
* It uses the information stored in the ETH_PORT_INFO struct to
* initialize the various port registers.
*
* Data flow:
* All packet references to/from the driver are done using PKT_INFO
* struct.
* This struct is a unified struct used with Rx and Tx operations.
* This way the user is not required to be familiar with neither
* Tx nor Rx descriptors structures.
* The driver's descriptors rings are management by indexes.
* Those indexes controls the ring resources and used to indicate
* a SW resource error:
* 'current'
* This index points to the current available resource for use. For
* example in Rx process this index will point to the descriptor
* that will be passed to the user upon calling the receive routine.
* In Tx process, this index will point to the descriptor
* that will be assigned with the user packet info and transmitted.
* 'used'
* This index points to the descriptor that need to restore its
* resources. For example in Rx process, using the Rx buffer return
* API will attach the buffer returned in packet info to the
* descriptor pointed by 'used'. In Tx process, using the Tx
* descriptor return will merely return the user packet info with
* the command status of the transmitted buffer pointed by the
* 'used' index. Nevertheless, it is essential to use this routine
* to update the 'used' index.
* 'first'
* This index supports Tx Scatter-Gather. It points to the first
* descriptor of a packet assembled of multiple buffers. For example
* when in middle of Such packet we have a Tx resource error the
* 'curr' index get the value of 'first' to indicate that the ring
* returned to its state before trying to transmit this packet.
*
* Receive operation:
* The eth_port_receive API set the packet information struct,
* passed by the caller, with received information from the
* 'current' SDMA descriptor.
* It is the user responsibility to return this resource back
* to the Rx descriptor ring to enable the reuse of this source.
* Return Rx resource is done using the eth_rx_return_buff API.
*
* Transmit operation:
* The eth_port_send API supports Scatter-Gather which enables to
* send a packet spanned over multiple buffers. This means that
* for each packet info structure given by the user and put into
* the Tx descriptors ring, will be transmitted only if the 'LAST'
* bit will be set in the packet info command status field. This
* API also consider restriction regarding buffer alignments and
* sizes.
* The user must return a Tx resource after ensuring the buffer
* has been transmitted to enable the Tx ring indexes to update.
*
* BOARD LAYOUT
* This device is on-board. No jumper diagram is necessary.
*
* EXTERNAL INTERFACE
*
* Prior to calling the initialization routine eth_port_init() the user
* must set the following fields under ETH_PORT_INFO struct:
* port_num User Ethernet port number.
* port_phy_addr User PHY address of Ethernet port.
* port_mac_addr[6] User defined port MAC address.
* port_config User port configuration value.
* port_config_extend User port config extend value.
* port_sdma_config User port SDMA config value.
* port_serial_control User port serial control value.
* *port_virt_to_phys () User function to cast virtual addr to CPU bus addr.
* *port_private User scratch pad for user specific data structures.
*
* This driver introduce a set of default values:
* PORT_CONFIG_VALUE Default port configuration value
* PORT_CONFIG_EXTEND_VALUE Default port extend configuration value
* PORT_SDMA_CONFIG_VALUE Default sdma control value
* PORT_SERIAL_CONTROL_VALUE Default port serial control value
*
* This driver data flow is done using the PKT_INFO struct which is
* a unified struct for Rx and Tx operations:
* byte_cnt Tx/Rx descriptor buffer byte count.
* l4i_chk CPU provided TCP Checksum. For Tx operation only.
* cmd_sts Tx/Rx descriptor command status.
* buf_ptr Tx/Rx descriptor buffer pointer.
* return_info Tx/Rx user resource return information.
*
*
* EXTERNAL SUPPORT REQUIREMENTS
*
* This driver requires the following external support:
*
* D_CACHE_FLUSH_LINE (address, address offset)
*
* This macro applies assembly code to flush and invalidate cache
* line.
* address - address base.
* address offset - address offset
*
*
* CPU_PIPE_FLUSH
*
* This macro applies assembly code to flush the CPU pipeline.
*
*******************************************************************************/
/* includes */
/* defines */
/* SDMA command macros */
#define ETH_ENABLE_TX_QUEUE(tx_queue, eth_port) \
MV_REG_WRITE(MV64360_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), (1 << tx_queue))
#define ETH_DISABLE_TX_QUEUE(tx_queue, eth_port) \
MV_REG_WRITE(MV64360_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port),\
(1 << (8 + tx_queue)))
#define ETH_ENABLE_RX_QUEUE(rx_queue, eth_port) \
MV_REG_WRITE(MV64360_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port), (1 << rx_queue))
#define ETH_DISABLE_RX_QUEUE(rx_queue, eth_port) \
MV_REG_WRITE(MV64360_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port), (1 << (8 + rx_queue)))
#define CURR_RFD_GET(p_curr_desc, queue) \
((p_curr_desc) = p_eth_port_ctrl->p_rx_curr_desc_q[queue])
#define CURR_RFD_SET(p_curr_desc, queue) \
(p_eth_port_ctrl->p_rx_curr_desc_q[queue] = (p_curr_desc))
#define USED_RFD_GET(p_used_desc, queue) \
((p_used_desc) = p_eth_port_ctrl->p_rx_used_desc_q[queue])
#define USED_RFD_SET(p_used_desc, queue)\
(p_eth_port_ctrl->p_rx_used_desc_q[queue] = (p_used_desc))
#define CURR_TFD_GET(p_curr_desc, queue) \
((p_curr_desc) = p_eth_port_ctrl->p_tx_curr_desc_q[queue])
#define CURR_TFD_SET(p_curr_desc, queue) \
(p_eth_port_ctrl->p_tx_curr_desc_q[queue] = (p_curr_desc))
#define USED_TFD_GET(p_used_desc, queue) \
((p_used_desc) = p_eth_port_ctrl->p_tx_used_desc_q[queue])
#define USED_TFD_SET(p_used_desc, queue) \
(p_eth_port_ctrl->p_tx_used_desc_q[queue] = (p_used_desc))
#define FIRST_TFD_GET(p_first_desc, queue) \
((p_first_desc) = p_eth_port_ctrl->p_tx_first_desc_q[queue])
#define FIRST_TFD_SET(p_first_desc, queue) \
(p_eth_port_ctrl->p_tx_first_desc_q[queue] = (p_first_desc))
/* Macros that save access to desc in order to find next desc pointer */
#define RX_NEXT_DESC_PTR(p_rx_desc, queue) (ETH_RX_DESC*)(((((unsigned int)p_rx_desc - (unsigned int)p_eth_port_ctrl->p_rx_desc_area_base[queue]) + RX_DESC_ALIGNED_SIZE) % p_eth_port_ctrl->rx_desc_area_size[queue]) + (unsigned int)p_eth_port_ctrl->p_rx_desc_area_base[queue])
#define TX_NEXT_DESC_PTR(p_tx_desc, queue) (ETH_TX_DESC*)(((((unsigned int)p_tx_desc - (unsigned int)p_eth_port_ctrl->p_tx_desc_area_base[queue]) + TX_DESC_ALIGNED_SIZE) % p_eth_port_ctrl->tx_desc_area_size[queue]) + (unsigned int)p_eth_port_ctrl->p_tx_desc_area_base[queue])
#define LINK_UP_TIMEOUT 100000
#define PHY_BUSY_TIMEOUT 10000000
/* locals */
/* PHY routines */
static void ethernet_phy_set (ETH_PORT eth_port_num, int phy_addr);
static int ethernet_phy_get (ETH_PORT eth_port_num);
/* Ethernet Port routines */
static void eth_set_access_control (ETH_PORT eth_port_num,
ETH_WIN_PARAM * param);
static bool eth_port_uc_addr (ETH_PORT eth_port_num, unsigned char uc_nibble,
ETH_QUEUE queue, int option);
#if 0 /* FIXME */
static bool eth_port_smc_addr (ETH_PORT eth_port_num,
unsigned char mc_byte,
ETH_QUEUE queue, int option);
static bool eth_port_omc_addr (ETH_PORT eth_port_num,
unsigned char crc8,
ETH_QUEUE queue, int option);
#endif
static void eth_b_copy (unsigned int src_addr, unsigned int dst_addr,
int byte_count);
void eth_dbg (ETH_PORT_INFO * p_eth_port_ctrl);
typedef enum _memory_bank { BANK0, BANK1, BANK2, BANK3 } MEMORY_BANK;
u32 mv_get_dram_bank_base_addr (MEMORY_BANK bank)
{
u32 result = 0;
u32 enable = MV_REG_READ (MV64360_BASE_ADDR_ENABLE);
if (enable & (1 << bank))
return 0;
if (bank == BANK0)
result = MV_REG_READ (MV64360_CS_0_BASE_ADDR);
if (bank == BANK1)
result = MV_REG_READ (MV64360_CS_1_BASE_ADDR);
if (bank == BANK2)
result = MV_REG_READ (MV64360_CS_2_BASE_ADDR);
if (bank == BANK3)
result = MV_REG_READ (MV64360_CS_3_BASE_ADDR);
result &= 0x0000ffff;
result = result << 16;
return result;
}
u32 mv_get_dram_bank_size (MEMORY_BANK bank)
{
u32 result = 0;
u32 enable = MV_REG_READ (MV64360_BASE_ADDR_ENABLE);
if (enable & (1 << bank))
return 0;
if (bank == BANK0)
result = MV_REG_READ (MV64360_CS_0_SIZE);
if (bank == BANK1)
result = MV_REG_READ (MV64360_CS_1_SIZE);
if (bank == BANK2)
result = MV_REG_READ (MV64360_CS_2_SIZE);
if (bank == BANK3)
result = MV_REG_READ (MV64360_CS_3_SIZE);
result += 1;
result &= 0x0000ffff;
result = result << 16;
return result;
}
u32 mv_get_internal_sram_base (void)
{
u32 result;
result = MV_REG_READ (MV64360_INTEGRATED_SRAM_BASE_ADDR);
result &= 0x0000ffff;
result = result << 16;
return result;
}
/*******************************************************************************
* eth_port_init - Initialize the Ethernet port driver
*
* DESCRIPTION:
* This function prepares the ethernet port to start its activity:
* 1) Completes the ethernet port driver struct initialization toward port
* start routine.
* 2) Resets the device to a quiescent state in case of warm reboot.
* 3) Enable SDMA access to all four DRAM banks as well as internal SRAM.
* 4) Clean MAC tables. The reset status of those tables is unknown.
* 5) Set PHY address.
* Note: Call this routine prior to eth_port_start routine and after setting
* user values in the user fields of Ethernet port control struct (i.e.
* port_phy_addr).
*
* INPUT:
* ETH_PORT_INFO *p_eth_port_ctrl Ethernet port control struct
*
* OUTPUT:
* See description.
*
* RETURN:
* None.
*
*******************************************************************************/
static void eth_port_init (ETH_PORT_INFO * p_eth_port_ctrl)
{
int queue;
ETH_WIN_PARAM win_param;
p_eth_port_ctrl->port_config = PORT_CONFIG_VALUE;
p_eth_port_ctrl->port_config_extend = PORT_CONFIG_EXTEND_VALUE;
p_eth_port_ctrl->port_sdma_config = PORT_SDMA_CONFIG_VALUE;
p_eth_port_ctrl->port_serial_control = PORT_SERIAL_CONTROL_VALUE;
p_eth_port_ctrl->port_rx_queue_command = 0;
p_eth_port_ctrl->port_tx_queue_command = 0;
/* Zero out SW structs */
for (queue = 0; queue < MAX_RX_QUEUE_NUM; queue++) {
CURR_RFD_SET ((ETH_RX_DESC *) 0x00000000, queue);
USED_RFD_SET ((ETH_RX_DESC *) 0x00000000, queue);
p_eth_port_ctrl->rx_resource_err[queue] = false;
}
for (queue = 0; queue < MAX_TX_QUEUE_NUM; queue++) {
CURR_TFD_SET ((ETH_TX_DESC *) 0x00000000, queue);
USED_TFD_SET ((ETH_TX_DESC *) 0x00000000, queue);
FIRST_TFD_SET ((ETH_TX_DESC *) 0x00000000, queue);
p_eth_port_ctrl->tx_resource_err[queue] = false;
}
eth_port_reset (p_eth_port_ctrl->port_num);
/* Set access parameters for DRAM bank 0 */
win_param.win = ETH_WIN0; /* Use Ethernet window 0 */
win_param.target = ETH_TARGET_DRAM; /* Window target - DDR */
win_param.attributes = EBAR_ATTR_DRAM_CS0; /* Enable DRAM bank */
#ifndef CONFIG_NOT_COHERENT_CACHE
win_param.attributes |= EBAR_ATTR_DRAM_CACHE_COHERENCY_WB;
#endif
win_param.high_addr = 0;
/* Get bank base */
win_param.base_addr = mv_get_dram_bank_base_addr (BANK0);
win_param.size = mv_get_dram_bank_size (BANK0); /* Get bank size */
if (win_param.size == 0)
win_param.enable = 0;
else
win_param.enable = 1; /* Enable the access */
win_param.access_ctrl = EWIN_ACCESS_FULL; /* Enable full access */
/* Set the access control for address window (EPAPR) READ & WRITE */
eth_set_access_control (p_eth_port_ctrl->port_num, &win_param);
/* Set access parameters for DRAM bank 1 */
win_param.win = ETH_WIN1; /* Use Ethernet window 1 */
win_param.target = ETH_TARGET_DRAM; /* Window target - DDR */
win_param.attributes = EBAR_ATTR_DRAM_CS1; /* Enable DRAM bank */
#ifndef CONFIG_NOT_COHERENT_CACHE
win_param.attributes |= EBAR_ATTR_DRAM_CACHE_COHERENCY_WB;
#endif
win_param.high_addr = 0;
/* Get bank base */
win_param.base_addr = mv_get_dram_bank_base_addr (BANK1);
win_param.size = mv_get_dram_bank_size (BANK1); /* Get bank size */
if (win_param.size == 0)
win_param.enable = 0;
else
win_param.enable = 1; /* Enable the access */
win_param.access_ctrl = EWIN_ACCESS_FULL; /* Enable full access */
/* Set the access control for address window (EPAPR) READ & WRITE */
eth_set_access_control (p_eth_port_ctrl->port_num, &win_param);
/* Set access parameters for DRAM bank 2 */
win_param.win = ETH_WIN2; /* Use Ethernet window 2 */
win_param.target = ETH_TARGET_DRAM; /* Window target - DDR */
win_param.attributes = EBAR_ATTR_DRAM_CS2; /* Enable DRAM bank */
#ifndef CONFIG_NOT_COHERENT_CACHE
win_param.attributes |= EBAR_ATTR_DRAM_CACHE_COHERENCY_WB;
#endif
win_param.high_addr = 0;
/* Get bank base */
win_param.base_addr = mv_get_dram_bank_base_addr (BANK2);
win_param.size = mv_get_dram_bank_size (BANK2); /* Get bank size */
if (win_param.size == 0)
win_param.enable = 0;
else
win_param.enable = 1; /* Enable the access */
win_param.access_ctrl = EWIN_ACCESS_FULL; /* Enable full access */
/* Set the access control for address window (EPAPR) READ & WRITE */
eth_set_access_control (p_eth_port_ctrl->port_num, &win_param);
/* Set access parameters for DRAM bank 3 */
win_param.win = ETH_WIN3; /* Use Ethernet window 3 */
win_param.target = ETH_TARGET_DRAM; /* Window target - DDR */
win_param.attributes = EBAR_ATTR_DRAM_CS3; /* Enable DRAM bank */
#ifndef CONFIG_NOT_COHERENT_CACHE
win_param.attributes |= EBAR_ATTR_DRAM_CACHE_COHERENCY_WB;
#endif
win_param.high_addr = 0;
/* Get bank base */
win_param.base_addr = mv_get_dram_bank_base_addr (BANK3);
win_param.size = mv_get_dram_bank_size (BANK3); /* Get bank size */
if (win_param.size == 0)
win_param.enable = 0;
else
win_param.enable = 1; /* Enable the access */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?