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