📄 mv_eth.c
字号:
#endif eth_register (dev); } DP (printf ("%s: exit\n", __FUNCTION__));}/********************************************************************** * mv64460_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 mv64460_eth_open (struct eth_device *dev){ return (mv64460_eth_real_open (dev));}/* Helper function for mv64460_eth_open */static int mv64460_eth_real_open (struct eth_device *dev){ unsigned int queue; ETH_PORT_INFO *ethernet_private; struct mv64460_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 mv64460_eth_priv *) ethernet_private->port_private; port_num = port_private->port_num; /* Stop RX Queues */ MV_REG_WRITE (MV64460_ETH_RECEIVE_QUEUE_COMMAND_REG (port_num), 0x0000ff00); /* Clear the ethernet port interrupts */ MV_REG_WRITE (MV64460_ETH_INTERRUPT_CAUSE_REG (port_num), 0); MV_REG_WRITE (MV64460_ETH_INTERRUPT_CAUSE_EXTEND_REG (port_num), 0); /* Unmask RX buffer and TX end interrupt */ MV_REG_WRITE (MV64460_ETH_INTERRUPT_MASK_REG (port_num), INT_CAUSE_UNMASK_ALL); /* Unmask phy and link status changes interrupts */ MV_REG_WRITE (MV64460_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 < MV64460_TX_QUEUE_NUM; queue++) { unsigned int size; port_private->tx_ring_size[queue] = MV64460_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], MV64460_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 < MV64460_RX_QUEUE_NUM; queue++) { unsigned int size; /* Meantime RX Ring are fixed - but must be configurable by user */ port_private->rx_ring_size[queue] = MV64460_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], MV64460_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 (MV64460_ETH_PORT_SERIAL_CONTROL_REG (port_num), (0x5 << 17) | (MV_REG_READ (MV64460_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 (MV64460_ETH_MAXIMUM_TRANSMIT_UNIT (port_num), 0); port_status = MV_REG_READ (MV64460_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 { mv64460_eth_print_phy_status (dev); } port_private->eth_running = MAGIC_ETH_RUNNING; return 1;}static int mv64460_eth_free_tx_rings (struct eth_device *dev){ unsigned int queue; ETH_PORT_INFO *ethernet_private; struct mv64460_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 mv64460_eth_priv *) ethernet_private->port_private; port_num = port_private->port_num; /* Stop Tx Queues */ MV_REG_WRITE (MV64460_ETH_TRANSMIT_QUEUE_COMMAND_REG (port_num), 0x0000ff00); /* Free TX rings */ DP (printf ("Clearing previously allocated TX queues... ")); for (queue = 0; queue < MV64460_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 mv64460_eth_free_rx_rings (struct eth_device *dev){ unsigned int queue; ETH_PORT_INFO *ethernet_private; struct mv64460_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 mv64460_eth_priv *) ethernet_private->port_private; port_num = port_private->port_num; /* Stop RX Queues */ MV_REG_WRITE (MV64460_ETH_RECEIVE_QUEUE_COMMAND_REG (port_num), 0x0000ff00); /* Free RX rings */ DP (printf ("Clearing previously allocated RX queues... ")); for (queue = 0; queue < MV64460_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;}/********************************************************************** * mv64460_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 mv64460_eth_stop (struct eth_device *dev){ ETH_PORT_INFO *ethernet_private; struct mv64460_eth_priv *port_private; unsigned int port_num; ethernet_private = (ETH_PORT_INFO *) dev->priv; port_private = (struct mv64460_eth_priv *) ethernet_private->port_private; port_num = port_private->port_num; /* Disable all gigE address decoder */ MV_REG_WRITE (MV64460_ETH_BASE_ADDR_ENABLE_REG, 0x3f); DP (printf ("%s Ethernet stop called ... \n", __FUNCTION__)); mv64460_eth_real_stop (dev); return 0;};/* Helper function for mv64460_eth_stop */static int mv64460_eth_real_stop (struct eth_device *dev){ ETH_PORT_INFO *ethernet_private; struct mv64460_eth_priv *port_private; unsigned int port_num; ethernet_private = (ETH_PORT_INFO *) dev->priv; port_private = (struct mv64460_eth_priv *) ethernet_private->port_private; port_num = port_private->port_num; mv64460_eth_free_tx_rings (dev); mv64460_eth_free_rx_rings (dev); eth_port_reset (ethernet_private->port_num); /* Disable ethernet port interrupts */ MV_REG_WRITE (MV64460_ETH_INTERRUPT_CAUSE_REG (port_num), 0); MV_REG_WRITE (MV64460_ETH_INTERRUPT_CAUSE_EXTEND_REG (port_num), 0); /* Mask RX buffer and TX end interrupt */ MV_REG_WRITE (MV64460_ETH_INTERRUPT_MASK_REG (port_num), 0); /* Mask phy and link status changes interrupts */ MV_REG_WRITE (MV64460_ETH_INTERRUPT_EXTEND_MASK_REG (port_num), 0); MV_RESET_REG_BITS (MV64460_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; mv64460_eth_print_stat (dev); } memset (port_private->stats, 0, sizeof (struct net_device_stats));#endif DP (printf ("\nEthernet stopped ... \n")); return 0;}/********************************************************************** * mv64460_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 mv64460_eth_xmit (struct eth_device *dev, volatile void *dataPtr, int dataSize){ ETH_PORT_INFO *ethernet_private; struct mv64460_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 mv64460_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, &pkt_info); switch (release_result) { case ETH_OK: DP (printf ("descriptor released\n")); if (pkt_info.cmd_sts & BIT0) { printf ("Error in TX\n"); stats->tx_errors++; } break; case ETH_RETRY: DP (printf ("transmission still in process\n")); break; case ETH_ERROR: printf ("routine can not access Tx desc ring\n"); break; case ETH_END_OF_JOB: DP (printf ("the routine has nothing to release\n")); break; default: /* should not happen */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -