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 + -
显示快捷键?