📄 mv_eth.c
字号:
* 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(MV64460_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), (1 << tx_queue))#define ETH_DISABLE_TX_QUEUE(tx_queue, eth_port) \ MV_REG_WRITE(MV64460_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port),\ (1 << (8 + tx_queue)))#define ETH_ENABLE_RX_QUEUE(rx_queue, eth_port) \MV_REG_WRITE(MV64460_ETH_RECEIVE_QUEUE_COMMAND_REG(eth_port), (1 << rx_queue))#define ETH_DISABLE_RX_QUEUE(rx_queue, eth_port) \MV_REG_WRITE(MV64460_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);#endifstatic 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 (MV64460_BASE_ADDR_ENABLE); if (enable & (1 << bank)) return 0; if (bank == BANK0) result = MV_REG_READ (MV64460_CS_0_BASE_ADDR); if (bank == BANK1) result = MV_REG_READ (MV64460_CS_1_BASE_ADDR); if (bank == BANK2) result = MV_REG_READ (MV64460_CS_2_BASE_ADDR); if (bank == BANK3) result = MV_REG_READ (MV64460_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 (MV64460_BASE_ADDR_ENABLE); if (enable & (1 << bank)) return 0; if (bank == BANK0) result = MV_REG_READ (MV64460_CS_0_SIZE); if (bank == BANK1) result = MV_REG_READ (MV64460_CS_1_SIZE); if (bank == BANK2) result = MV_REG_READ (MV64460_CS_2_SIZE); if (bank == BANK3) result = MV_REG_READ (MV64460_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 (MV64460_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 */ 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 Internal SRAM */ win_param.win = ETH_WIN4; /* Use Ethernet window 0 */ win_param.target = EBAR_TARGET_CBS; /* Target - Internal SRAM */ win_param.attributes = EBAR_ATTR_CBS_SRAM | EBAR_ATTR_CBS_SRAM_BLOCK0; win_param.high_addr = 0; win_param.base_addr = mv_get_internal_sram_base (); /* Get base addr */ win_param.size = MV64460_INTERNAL_SRAM_SIZE; /* Get bank size */ 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); eth_port_init_mac_tables (p_eth_port_ctrl->port_num); ethernet_phy_set (p_eth_port_ctrl->port_num, p_eth_port_ctrl->port_phy_addr); return;}/******************************************************************************** eth_port_start - Start the Ethernet port activity.** DESCRIPTION:* This routine prepares the Ethernet port for Rx and Tx activity:* 1. Initialize Tx and Rx Current Descriptor Pointer for each queue that* has been initialized a descriptor's ring (using ether_init_tx_desc_ring* for Tx and ether_init_rx_desc_ring for Rx)* 2. Initialize and enable the Ethernet configuration port by writing to* the port's configuration and command registers.* 3. Initialize and enable the SDMA by writing to the SDMA's* configuration and command registers.* After completing these steps, the ethernet port SDMA can starts to* perform Rx and Tx activities.** Note: Each Rx and Tx queue descriptor's list must be initialized prior* to calling this function (use ether_init_tx_desc_ring for Tx queues and
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -