Commit 40735e75 authored by Jijie Shao's avatar Jijie Shao Committed by Paolo Abeni
Browse files

net: hibmcge: Implement .ndo_start_xmit function



Implement .ndo_start_xmit function to fill the information of the packet
to be transmitted into the tx descriptor, and then the hardware will
transmit the packet using the information in the tx descriptor.
In addition, we also implemented the tx_handler function to enable the
tx descriptor to be reused, and .ndo_tx_timeout function to print some
information when the hardware is busy.

Signed-off-by: default avatarJijie Shao <shaojijie@huawei.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent ff4edac6
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -13,14 +13,61 @@
#define HBG_RX_SKIP1			0x00
#define HBG_RX_SKIP2			0x01
#define HBG_VECTOR_NUM			4
#define HBG_PCU_CACHE_LINE_SIZE		32
#define HBG_TX_TIMEOUT_BUF_LEN		1024

enum hbg_dir {
	HBG_DIR_TX = 1 << 0,
	HBG_DIR_RX = 1 << 1,
	HBG_DIR_TX_RX = HBG_DIR_TX | HBG_DIR_RX,
};

enum hbg_tx_state {
	HBG_TX_STATE_COMPLETE = 0, /* clear state, must fix to 0 */
	HBG_TX_STATE_START,
};

enum hbg_nic_state {
	HBG_NIC_STATE_EVENT_HANDLING = 0,
};

struct hbg_buffer {
	u32 state;
	dma_addr_t state_dma;

	struct sk_buff *skb;
	dma_addr_t skb_dma;
	u32 skb_len;

	enum hbg_dir dir;
	struct hbg_ring *ring;
	struct hbg_priv *priv;
};

struct hbg_ring {
	struct hbg_buffer *queue;
	dma_addr_t queue_dma;

	union {
		u32 head;
		u32 ntc;
	};
	union {
		u32 tail;
		u32 ntu;
	};
	u32 len;

	enum hbg_dir dir;
	struct hbg_priv *priv;
	struct napi_struct napi;
	char *tout_log_buf; /* tx timeout log buffer */
};

enum hbg_hw_event_type {
	HBG_HW_EVENT_NONE = 0,
	HBG_HW_EVENT_INIT, /* driver is loading */
	HBG_HW_EVENT_RESET,
};

struct hbg_dev_specs {
@@ -73,6 +120,7 @@ struct hbg_priv {
	unsigned long state;
	struct hbg_mac mac;
	struct hbg_vector vectors;
	struct hbg_ring tx_ring;
};

#endif
+18 −0
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ static int hbg_hw_dev_specs_init(struct hbg_priv *priv)
	if (!is_valid_ether_addr((u8 *)specs->mac_addr.sa_data))
		return -EADDRNOTAVAIL;

	specs->max_frame_len = HBG_PCU_CACHE_LINE_SIZE + specs->max_mtu;
	return 0;
}

@@ -171,6 +172,23 @@ void hbg_hw_mac_enable(struct hbg_priv *priv, u32 enable)
			    HBG_REG_PORT_ENABLE_RX_B, enable);
}

u32 hbg_hw_get_fifo_used_num(struct hbg_priv *priv, enum hbg_dir dir)
{
	if (dir & HBG_DIR_TX)
		return hbg_reg_read_field(priv, HBG_REG_CF_CFF_DATA_NUM_ADDR,
					  HBG_REG_CF_CFF_DATA_NUM_ADDR_TX_M);

	return 0;
}

void hbg_hw_set_tx_desc(struct hbg_priv *priv, struct hbg_tx_desc *tx_desc)
{
	hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_0_ADDR, tx_desc->word0);
	hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_1_ADDR, tx_desc->word1);
	hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_2_ADDR, tx_desc->word2);
	hbg_reg_write(priv, HBG_REG_TX_CFF_ADDR_3_ADDR, tx_desc->word3);
}

void hbg_hw_adjust_link(struct hbg_priv *priv, u32 speed, u32 duplex)
{
	hbg_reg_write_field(priv, HBG_REG_PORT_MODE_ADDR,
+2 −0
Original line number Diff line number Diff line
@@ -52,5 +52,7 @@ void hbg_hw_irq_enable(struct hbg_priv *priv, u32 mask, bool enable);
void hbg_hw_set_mtu(struct hbg_priv *priv, u16 mtu);
void hbg_hw_mac_enable(struct hbg_priv *priv, u32 enable);
void hbg_hw_set_uc_addr(struct hbg_priv *priv, u64 mac_addr);
u32 hbg_hw_get_fifo_used_num(struct hbg_priv *priv, enum hbg_dir dir);
void hbg_hw_set_tx_desc(struct hbg_priv *priv, struct hbg_tx_desc *tx_desc);

#endif
+7 −1
Original line number Diff line number Diff line
@@ -13,6 +13,12 @@ static void hbg_irq_handle_err(struct hbg_priv *priv,
			"receive error interrupt: %s\n", irq_info->name);
}

static void hbg_irq_handle_tx(struct hbg_priv *priv,
			      struct hbg_irq_info *irq_info)
{
	napi_schedule(&priv->tx_ring.napi);
}

#define HBG_TXRX_IRQ_I(name, handle) \
	{#name, HBG_INT_MSK_##name##_B, false, false, 0, handle}
#define HBG_ERR_IRQ_I(name, need_print) \
@@ -20,7 +26,7 @@ static void hbg_irq_handle_err(struct hbg_priv *priv,

static struct hbg_irq_info hbg_irqs[] = {
	HBG_TXRX_IRQ_I(RX, NULL),
	HBG_TXRX_IRQ_I(TX, NULL),
	HBG_TXRX_IRQ_I(TX, hbg_irq_handle_tx),
	HBG_ERR_IRQ_I(MAC_MII_FIFO_ERR, true),
	HBG_ERR_IRQ_I(MAC_PCS_RX_FIFO_ERR, true),
	HBG_ERR_IRQ_I(MAC_PCS_TX_FIFO_ERR, true),
+52 −2
Original line number Diff line number Diff line
@@ -9,6 +9,9 @@
#include "hbg_hw.h"
#include "hbg_irq.h"
#include "hbg_mdio.h"
#include "hbg_txrx.h"

static void hbg_change_mtu(struct hbg_priv *priv, int new_mtu);

static void hbg_all_irq_enable(struct hbg_priv *priv, bool enabled)
{
@@ -24,6 +27,11 @@ static void hbg_all_irq_enable(struct hbg_priv *priv, bool enabled)
static int hbg_net_open(struct net_device *netdev)
{
	struct hbg_priv *priv = netdev_priv(netdev);
	int ret;

	ret = hbg_txrx_init(priv);
	if (ret)
		return ret;

	hbg_all_irq_enable(priv, true);
	hbg_hw_mac_enable(priv, HBG_STATUS_ENABLE);
@@ -33,6 +41,26 @@ static int hbg_net_open(struct net_device *netdev)
	return 0;
}

/* This function only can be called after hbg_txrx_uninit() */
static int hbg_hw_txrx_clear(struct hbg_priv *priv)
{
	int ret;

	/* After ring buffers have been released,
	 * do a reset to release hw fifo rx ring buffer
	 */
	ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_RESET);
	if (ret)
		return ret;

	/* After reset, regs need to be reconfigured */
	hbg_hw_init(priv);
	hbg_hw_set_uc_addr(priv, ether_addr_to_u64(priv->netdev->dev_addr));
	hbg_change_mtu(priv, priv->netdev->mtu);

	return 0;
}

static int hbg_net_stop(struct net_device *netdev)
{
	struct hbg_priv *priv = netdev_priv(netdev);
@@ -41,8 +69,8 @@ static int hbg_net_stop(struct net_device *netdev)
	netif_stop_queue(netdev);
	hbg_hw_mac_enable(priv, HBG_STATUS_DISABLE);
	hbg_all_irq_enable(priv, false);

	return 0;
	hbg_txrx_uninit(priv);
	return hbg_hw_txrx_clear(priv);
}

static int hbg_net_set_mac_address(struct net_device *netdev, void *addr)
@@ -86,12 +114,33 @@ static int hbg_net_change_mtu(struct net_device *netdev, int new_mtu)
	return 0;
}

static void hbg_net_tx_timeout(struct net_device *netdev, unsigned int txqueue)
{
	struct hbg_priv *priv = netdev_priv(netdev);
	struct hbg_ring *ring = &priv->tx_ring;
	char *buf = ring->tout_log_buf;
	u32 pos = 0;

	pos += scnprintf(buf + pos, HBG_TX_TIMEOUT_BUF_LEN - pos,
			 "ring used num: %u, fifo used num: %u\n",
			 hbg_get_queue_used_num(ring),
			 hbg_hw_get_fifo_used_num(priv, HBG_DIR_TX));
	pos += scnprintf(buf + pos, HBG_TX_TIMEOUT_BUF_LEN - pos,
			 "ntc: %u, ntu: %u, irq enabled: %u\n",
			 ring->ntc, ring->ntu,
			 hbg_hw_irq_is_enabled(priv, HBG_INT_MSK_TX_B));

	netdev_info(netdev, "%s", buf);
}

static const struct net_device_ops hbg_netdev_ops = {
	.ndo_open		= hbg_net_open,
	.ndo_stop		= hbg_net_stop,
	.ndo_start_xmit		= hbg_net_start_xmit,
	.ndo_validate_addr	= eth_validate_addr,
	.ndo_set_mac_address	= hbg_net_set_mac_address,
	.ndo_change_mtu		= hbg_net_change_mtu,
	.ndo_tx_timeout		= hbg_net_tx_timeout,
};

static int hbg_init(struct hbg_priv *priv)
@@ -170,6 +219,7 @@ static int hbg_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
	netdev->max_mtu = priv->dev_specs.max_mtu;
	netdev->min_mtu = priv->dev_specs.min_mtu;
	netdev->netdev_ops = &hbg_netdev_ops;
	netdev->watchdog_timeo = 5 * HZ;

	hbg_change_mtu(priv, ETH_DATA_LEN);
	hbg_net_set_mac_address(priv->netdev, &priv->dev_specs.mac_addr);
Loading