mv_eth.c
来自「适合KS8695X」· C语言 代码 · 共 1,878 行 · 第 1/5 页
C
1,878 行
(char *) memalign (16,
MV64360_RX_QUEUE_SIZE *
MV64360_TX_BUFFER_SIZE + 1);
ethernet_private->p_tx_buffer_base[0] =
(char *) memalign (16,
MV64360_RX_QUEUE_SIZE *
MV64360_TX_BUFFER_SIZE + 1);
#ifdef DEBUG_MV_ETH
/* DEBUG OUTPUT prints adresses of globals */
print_globals (dev);
#endif
eth_register (dev);
}
DP (printf ("%s: exit\n", __FUNCTION__));
}
/**********************************************************************
* mv64360_eth_open
*
* This function is called when openning the network device. The function
* should initialize all the hardware, initialize cyclic Rx/Tx
* descriptors chain and buffers and allocate an IRQ to the network
* device.
*
* Input : a pointer to the network device structure
* / / ronen - changed the output to match net/eth.c needs
* Output : nonzero of success , zero if fails.
* under construction
**********************************************************************/
int mv64360_eth_open (struct eth_device *dev)
{
return (mv64360_eth_real_open (dev));
}
/* Helper function for mv64360_eth_open */
static int mv64360_eth_real_open (struct eth_device *dev)
{
unsigned int queue;
ETH_PORT_INFO *ethernet_private;
struct mv64360_eth_priv *port_private;
unsigned int port_num;
u32 port_status, phy_reg_data;
ethernet_private = (ETH_PORT_INFO *) dev->priv;
/* ronen - when we update the MAC env params we only update dev->enetaddr
see ./net/eth.c eth_set_enetaddr() */
memcpy (ethernet_private->port_mac_addr, dev->enetaddr, 6);
port_private =
(struct mv64360_eth_priv *) ethernet_private->port_private;
port_num = port_private->port_num;
/* Stop RX Queues */
MV_REG_WRITE (MV64360_ETH_RECEIVE_QUEUE_COMMAND_REG (port_num),
0x0000ff00);
/* Clear the ethernet port interrupts */
MV_REG_WRITE (MV64360_ETH_INTERRUPT_CAUSE_REG (port_num), 0);
MV_REG_WRITE (MV64360_ETH_INTERRUPT_CAUSE_EXTEND_REG (port_num), 0);
/* Unmask RX buffer and TX end interrupt */
MV_REG_WRITE (MV64360_ETH_INTERRUPT_MASK_REG (port_num),
INT_CAUSE_UNMASK_ALL);
/* Unmask phy and link status changes interrupts */
MV_REG_WRITE (MV64360_ETH_INTERRUPT_EXTEND_MASK_REG (port_num),
INT_CAUSE_UNMASK_ALL_EXT);
/* Set phy address of the port */
ethernet_private->port_phy_addr = 0x8 + port_num;
/* Activate the DMA channels etc */
eth_port_init (ethernet_private);
/* "Allocate" setup TX rings */
for (queue = 0; queue < MV64360_TX_QUEUE_NUM; queue++) {
unsigned int size;
port_private->tx_ring_size[queue] = MV64360_TX_QUEUE_SIZE;
size = (port_private->tx_ring_size[queue] * TX_DESC_ALIGNED_SIZE); /*size = no of DESCs times DESC-size */
ethernet_private->tx_desc_area_size[queue] = size;
/* first clear desc area completely */
memset ((void *) ethernet_private->p_tx_desc_area_base[queue],
0, ethernet_private->tx_desc_area_size[queue]);
/* initialize tx desc ring with low level driver */
if (ether_init_tx_desc_ring
(ethernet_private, ETH_Q0,
port_private->tx_ring_size[queue],
MV64360_TX_BUFFER_SIZE /* Each Buffer is 1600 Byte */ ,
(unsigned int) ethernet_private->
p_tx_desc_area_base[queue],
(unsigned int) ethernet_private->
p_tx_buffer_base[queue]) == false)
printf ("### Error initializing TX Ring\n");
}
/* "Allocate" setup RX rings */
for (queue = 0; queue < MV64360_RX_QUEUE_NUM; queue++) {
unsigned int size;
/* Meantime RX Ring are fixed - but must be configurable by user */
port_private->rx_ring_size[queue] = MV64360_RX_QUEUE_SIZE;
size = (port_private->rx_ring_size[queue] *
RX_DESC_ALIGNED_SIZE);
ethernet_private->rx_desc_area_size[queue] = size;
/* first clear desc area completely */
memset ((void *) ethernet_private->p_rx_desc_area_base[queue],
0, ethernet_private->rx_desc_area_size[queue]);
if ((ether_init_rx_desc_ring
(ethernet_private, ETH_Q0,
port_private->rx_ring_size[queue],
MV64360_RX_BUFFER_SIZE /* Each Buffer is 1600 Byte */ ,
(unsigned int) ethernet_private->
p_rx_desc_area_base[queue],
(unsigned int) ethernet_private->
p_rx_buffer_base[queue])) == false)
printf ("### Error initializing RX Ring\n");
}
eth_port_start (ethernet_private);
/* Set maximum receive buffer to 9700 bytes */
MV_REG_WRITE (MV64360_ETH_PORT_SERIAL_CONTROL_REG (port_num),
(0x5 << 17) |
(MV_REG_READ
(MV64360_ETH_PORT_SERIAL_CONTROL_REG (port_num))
& 0xfff1ffff));
/*
* Set ethernet MTU for leaky bucket mechanism to 0 - this will
* disable the leaky bucket mechanism .
*/
MV_REG_WRITE (MV64360_ETH_MAXIMUM_TRANSMIT_UNIT (port_num), 0);
port_status = MV_REG_READ (MV64360_ETH_PORT_STATUS_REG (port_num));
/* Check Link status on phy */
eth_port_read_smi_reg (port_num, 1, &phy_reg_data);
if (!(phy_reg_data & 0x20)) {
/* Reset PHY */
if ((ethernet_phy_reset (port_num)) != true) {
printf ("$$ Warnning: No link on port %d \n",
port_num);
return 0;
} else {
eth_port_read_smi_reg (port_num, 1, &phy_reg_data);
if (!(phy_reg_data & 0x20)) {
printf ("### Error: Phy is not active\n");
return 0;
}
}
} else {
mv64360_eth_print_phy_status (dev);
}
port_private->eth_running = MAGIC_ETH_RUNNING;
return 1;
}
static int mv64360_eth_free_tx_rings (struct eth_device *dev)
{
unsigned int queue;
ETH_PORT_INFO *ethernet_private;
struct mv64360_eth_priv *port_private;
unsigned int port_num;
volatile ETH_TX_DESC *p_tx_curr_desc;
ethernet_private = (ETH_PORT_INFO *) dev->priv;
port_private =
(struct mv64360_eth_priv *) ethernet_private->port_private;
port_num = port_private->port_num;
/* Stop Tx Queues */
MV_REG_WRITE (MV64360_ETH_TRANSMIT_QUEUE_COMMAND_REG (port_num),
0x0000ff00);
/* Free TX rings */
DP (printf ("Clearing previously allocated TX queues... "));
for (queue = 0; queue < MV64360_TX_QUEUE_NUM; queue++) {
/* Free on TX rings */
for (p_tx_curr_desc =
ethernet_private->p_tx_desc_area_base[queue];
((unsigned int) p_tx_curr_desc <= (unsigned int)
ethernet_private->p_tx_desc_area_base[queue] +
ethernet_private->tx_desc_area_size[queue]);
p_tx_curr_desc =
(ETH_TX_DESC *) ((unsigned int) p_tx_curr_desc +
TX_DESC_ALIGNED_SIZE)) {
/* this is inside for loop */
if (p_tx_curr_desc->return_info != 0) {
p_tx_curr_desc->return_info = 0;
DP (printf ("freed\n"));
}
}
DP (printf ("Done\n"));
}
return 0;
}
static int mv64360_eth_free_rx_rings (struct eth_device *dev)
{
unsigned int queue;
ETH_PORT_INFO *ethernet_private;
struct mv64360_eth_priv *port_private;
unsigned int port_num;
volatile ETH_RX_DESC *p_rx_curr_desc;
ethernet_private = (ETH_PORT_INFO *) dev->priv;
port_private =
(struct mv64360_eth_priv *) ethernet_private->port_private;
port_num = port_private->port_num;
/* Stop RX Queues */
MV_REG_WRITE (MV64360_ETH_RECEIVE_QUEUE_COMMAND_REG (port_num),
0x0000ff00);
/* Free RX rings */
DP (printf ("Clearing previously allocated RX queues... "));
for (queue = 0; queue < MV64360_RX_QUEUE_NUM; queue++) {
/* Free preallocated skb's on RX rings */
for (p_rx_curr_desc =
ethernet_private->p_rx_desc_area_base[queue];
(((unsigned int) p_rx_curr_desc <
((unsigned int) ethernet_private->
p_rx_desc_area_base[queue] +
ethernet_private->rx_desc_area_size[queue])));
p_rx_curr_desc =
(ETH_RX_DESC *) ((unsigned int) p_rx_curr_desc +
RX_DESC_ALIGNED_SIZE)) {
if (p_rx_curr_desc->return_info != 0) {
p_rx_curr_desc->return_info = 0;
DP (printf ("freed\n"));
}
}
DP (printf ("Done\n"));
}
return 0;
}
/**********************************************************************
* mv64360_eth_stop
*
* This function is used when closing the network device.
* It updates the hardware,
* release all memory that holds buffers and descriptors and release the IRQ.
* Input : a pointer to the device structure
* Output : zero if success , nonzero if fails
*********************************************************************/
int mv64360_eth_stop (struct eth_device *dev)
{
ETH_PORT_INFO *ethernet_private;
struct mv64360_eth_priv *port_private;
unsigned int port_num;
ethernet_private = (ETH_PORT_INFO *) dev->priv;
port_private =
(struct mv64360_eth_priv *) ethernet_private->port_private;
port_num = port_private->port_num;
/* Disable all gigE address decoder */
MV_REG_WRITE (MV64360_ETH_BASE_ADDR_ENABLE_REG, 0x3f);
DP (printf ("%s Ethernet stop called ... \n", __FUNCTION__));
mv64360_eth_real_stop (dev);
return 0;
};
/* Helper function for mv64360_eth_stop */
static int mv64360_eth_real_stop (struct eth_device *dev)
{
ETH_PORT_INFO *ethernet_private;
struct mv64360_eth_priv *port_private;
unsigned int port_num;
ethernet_private = (ETH_PORT_INFO *) dev->priv;
port_private =
(struct mv64360_eth_priv *) ethernet_private->port_private;
port_num = port_private->port_num;
mv64360_eth_free_tx_rings (dev);
mv64360_eth_free_rx_rings (dev);
eth_port_reset (ethernet_private->port_num);
/* Disable ethernet port interrupts */
MV_REG_WRITE (MV64360_ETH_INTERRUPT_CAUSE_REG (port_num), 0);
MV_REG_WRITE (MV64360_ETH_INTERRUPT_CAUSE_EXTEND_REG (port_num), 0);
/* Mask RX buffer and TX end interrupt */
MV_REG_WRITE (MV64360_ETH_INTERRUPT_MASK_REG (port_num), 0);
/* Mask phy and link status changes interrupts */
MV_REG_WRITE (MV64360_ETH_INTERRUPT_EXTEND_MASK_REG (port_num), 0);
MV_RESET_REG_BITS (MV64360_CPU_INTERRUPT0_MASK_HIGH,
BIT0 << port_num);
/* Print Network statistics */
#ifndef UPDATE_STATS_BY_SOFTWARE
/*
* Print statistics (only if ethernet is running),
* then zero all the stats fields in memory
*/
if (port_private->eth_running == MAGIC_ETH_RUNNING) {
port_private->eth_running = 0;
mv64360_eth_print_stat (dev);
}
memset (port_private->stats, 0, sizeof (struct net_device_stats));
#endif
DP (printf ("\nEthernet stopped ... \n"));
return 0;
}
/**********************************************************************
* mv64360_eth_start_xmit
*
* This function is queues a packet in the Tx descriptor for
* required port.
*
* Input : skb - a pointer to socket buffer
* dev - a pointer to the required port
*
* Output : zero upon success
**********************************************************************/
int mv64360_eth_xmit (struct eth_device *dev, volatile void *dataPtr,
int dataSize)
{
ETH_PORT_INFO *ethernet_private;
struct mv64360_eth_priv *port_private;
unsigned int port_num;
PKT_INFO pkt_info;
ETH_FUNC_RET_STATUS status;
struct net_device_stats *stats;
ETH_FUNC_RET_STATUS release_result;
ethernet_private = (ETH_PORT_INFO *) dev->priv;
port_private =
(struct mv64360_eth_priv *) ethernet_private->port_private;
port_num = port_private->port_num;
stats = port_private->stats;
/* Update packet info data structure */
pkt_info.cmd_sts = ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC; /* DMA owned, first last */
pkt_info.byte_cnt = dataSize;
pkt_info.buf_ptr = (unsigned int) dataPtr;
status = eth_port_send (ethernet_private, ETH_Q0, &pkt_info);
if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL)) {
printf ("Error on transmitting packet ..");
if (status == ETH_QUEUE_FULL)
printf ("ETH Queue is full. \n");
if (status == ETH_QUEUE_LAST_RESOURCE)
printf ("ETH Queue: using last available resource. \n");
goto error;
}
/* Update statistics and start of transmittion time */
stats->tx_bytes += dataSize;
stats->tx_packets++;
/* Check if packet(s) is(are) transmitted correctly (release everything) */
do {
release_result =
eth_tx_return_desc (ethernet_private, ETH_Q0,
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?