Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7fd11a1a authored by Peng Li's avatar Peng Li Committed by Greg Kroah-Hartman
Browse files

net: hns: add the code for cleaning pkt in chip



[ Upstream commit 31fabbee8f5c658c3fa1603c66e9e4f51ea8c2c6 ]

If there are packets in hardware when changing the speed
or duplex, it may cause hardware hang up.

This patch adds the code for waiting chip to clean the all
pkts(TX & RX) in chip when the driver uses the function named
"adjust link".

This patch cleans the pkts as follows:
1) close rx of chip, close tx of protocol stack.
2) wait rcb, ppe, mac to clean.
3) adjust link
4) open rx of chip, open tx of protocol stack.

Signed-off-by: default avatarPeng Li <lipeng321@huawei.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarSasha Levin <alexander.levin@microsoft.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent bdd29365
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -486,6 +486,8 @@ struct hnae_ae_ops {
			u8 *auto_neg, u16 *speed, u8 *duplex);
	void (*toggle_ring_irq)(struct hnae_ring *ring, u32 val);
	void (*adjust_link)(struct hnae_handle *handle, int speed, int duplex);
	bool (*need_adjust_link)(struct hnae_handle *handle,
				 int speed, int duplex);
	int (*set_loopback)(struct hnae_handle *handle,
			    enum hnae_loop loop_mode, int en);
	void (*get_ring_bdnum_limit)(struct hnae_queue *queue,
+66 −1
Original line number Diff line number Diff line
@@ -155,6 +155,41 @@ static void hns_ae_put_handle(struct hnae_handle *handle)
		hns_ae_get_ring_pair(handle->qs[i])->used_by_vf = 0;
}

static int hns_ae_wait_flow_down(struct hnae_handle *handle)
{
	struct dsaf_device *dsaf_dev;
	struct hns_ppe_cb *ppe_cb;
	struct hnae_vf_cb *vf_cb;
	int ret;
	int i;

	for (i = 0; i < handle->q_num; i++) {
		ret = hns_rcb_wait_tx_ring_clean(handle->qs[i]);
		if (ret)
			return ret;
	}

	ppe_cb = hns_get_ppe_cb(handle);
	ret = hns_ppe_wait_tx_fifo_clean(ppe_cb);
	if (ret)
		return ret;

	dsaf_dev = hns_ae_get_dsaf_dev(handle->dev);
	if (!dsaf_dev)
		return -EINVAL;
	ret = hns_dsaf_wait_pkt_clean(dsaf_dev, handle->dport_id);
	if (ret)
		return ret;

	vf_cb = hns_ae_get_vf_cb(handle);
	ret = hns_mac_wait_fifo_clean(vf_cb->mac_cb);
	if (ret)
		return ret;

	mdelay(10);
	return 0;
}

static void hns_ae_ring_enable_all(struct hnae_handle *handle, int val)
{
	int q_num = handle->q_num;
@@ -399,12 +434,41 @@ static int hns_ae_get_mac_info(struct hnae_handle *handle,
	return hns_mac_get_port_info(mac_cb, auto_neg, speed, duplex);
}

static bool hns_ae_need_adjust_link(struct hnae_handle *handle, int speed,
				    int duplex)
{
	struct hns_mac_cb *mac_cb = hns_get_mac_cb(handle);

	return hns_mac_need_adjust_link(mac_cb, speed, duplex);
}

static void hns_ae_adjust_link(struct hnae_handle *handle, int speed,
			       int duplex)
{
	struct hns_mac_cb *mac_cb = hns_get_mac_cb(handle);

	switch (mac_cb->dsaf_dev->dsaf_ver) {
	case AE_VERSION_1:
		hns_mac_adjust_link(mac_cb, speed, duplex);
		break;

	case AE_VERSION_2:
		/* chip need to clear all pkt inside */
		hns_mac_disable(mac_cb, MAC_COMM_MODE_RX);
		if (hns_ae_wait_flow_down(handle)) {
			hns_mac_enable(mac_cb, MAC_COMM_MODE_RX);
			break;
		}

		hns_mac_adjust_link(mac_cb, speed, duplex);
		hns_mac_enable(mac_cb, MAC_COMM_MODE_RX);
		break;

	default:
		break;
	}

	return;
}

static void hns_ae_get_ring_bdnum_limit(struct hnae_queue *queue,
@@ -902,6 +966,7 @@ static struct hnae_ae_ops hns_dsaf_ops = {
	.get_status = hns_ae_get_link_status,
	.get_info = hns_ae_get_mac_info,
	.adjust_link = hns_ae_adjust_link,
	.need_adjust_link = hns_ae_need_adjust_link,
	.set_loopback = hns_ae_config_loopback,
	.get_ring_bdnum_limit = hns_ae_get_ring_bdnum_limit,
	.get_pauseparam = hns_ae_get_pauseparam,
+36 −0
Original line number Diff line number Diff line
@@ -257,6 +257,16 @@ static void hns_gmac_get_pausefrm_cfg(void *mac_drv, u32 *rx_pause_en,
	*tx_pause_en = dsaf_get_bit(pause_en, GMAC_PAUSE_EN_TX_FDFC_B);
}

static bool hns_gmac_need_adjust_link(void *mac_drv, enum mac_speed speed,
				      int duplex)
{
	struct mac_driver *drv = (struct mac_driver *)mac_drv;
	struct hns_mac_cb *mac_cb = drv->mac_cb;

	return (mac_cb->speed != speed) ||
		(mac_cb->half_duplex == duplex);
}

static int hns_gmac_adjust_link(void *mac_drv, enum mac_speed speed,
				u32 full_duplex)
{
@@ -309,6 +319,30 @@ static void hns_gmac_set_promisc(void *mac_drv, u8 en)
		hns_gmac_set_uc_match(mac_drv, en);
}

int hns_gmac_wait_fifo_clean(void *mac_drv)
{
	struct mac_driver *drv = (struct mac_driver *)mac_drv;
	int wait_cnt;
	u32 val;

	wait_cnt = 0;
	while (wait_cnt++ < HNS_MAX_WAIT_CNT) {
		val = dsaf_read_dev(drv, GMAC_FIFO_STATE_REG);
		/* bit5~bit0 is not send complete pkts */
		if ((val & 0x3f) == 0)
			break;
		usleep_range(100, 200);
	}

	if (wait_cnt >= HNS_MAX_WAIT_CNT) {
		dev_err(drv->dev,
			"hns ge %d fifo was not idle.\n", drv->mac_id);
		return -EBUSY;
	}

	return 0;
}

static void hns_gmac_init(void *mac_drv)
{
	u32 port;
@@ -690,6 +724,7 @@ void *hns_gmac_config(struct hns_mac_cb *mac_cb, struct mac_params *mac_param)
	mac_drv->mac_disable = hns_gmac_disable;
	mac_drv->mac_free = hns_gmac_free;
	mac_drv->adjust_link = hns_gmac_adjust_link;
	mac_drv->need_adjust_link = hns_gmac_need_adjust_link;
	mac_drv->set_tx_auto_pause_frames = hns_gmac_set_tx_auto_pause_frames;
	mac_drv->config_max_frame_length = hns_gmac_config_max_frame_length;
	mac_drv->mac_pausefrm_cfg = hns_gmac_pause_frm_cfg;
@@ -717,6 +752,7 @@ void *hns_gmac_config(struct hns_mac_cb *mac_cb, struct mac_params *mac_param)
	mac_drv->get_strings = hns_gmac_get_strings;
	mac_drv->update_stats = hns_gmac_update_stats;
	mac_drv->set_promiscuous = hns_gmac_set_promisc;
	mac_drv->wait_fifo_clean = hns_gmac_wait_fifo_clean;

	return (void *)mac_drv;
}
+44 −0
Original line number Diff line number Diff line
@@ -114,6 +114,26 @@ int hns_mac_get_port_info(struct hns_mac_cb *mac_cb,
	return 0;
}

/**
 *hns_mac_is_adjust_link - check is need change mac speed and duplex register
 *@mac_cb: mac device
 *@speed: phy device speed
 *@duplex:phy device duplex
 *
 */
bool hns_mac_need_adjust_link(struct hns_mac_cb *mac_cb, int speed, int duplex)
{
	struct mac_driver *mac_ctrl_drv;

	mac_ctrl_drv = (struct mac_driver *)(mac_cb->priv.mac);

	if (mac_ctrl_drv->need_adjust_link)
		return mac_ctrl_drv->need_adjust_link(mac_ctrl_drv,
			(enum mac_speed)speed, duplex);
	else
		return true;
}

void hns_mac_adjust_link(struct hns_mac_cb *mac_cb, int speed, int duplex)
{
	int ret;
@@ -432,6 +452,16 @@ int hns_mac_vm_config_bc_en(struct hns_mac_cb *mac_cb, u32 vmid, bool enable)
	return 0;
}

int hns_mac_wait_fifo_clean(struct hns_mac_cb *mac_cb)
{
	struct mac_driver *drv = hns_mac_get_drv(mac_cb);

	if (drv->wait_fifo_clean)
		return drv->wait_fifo_clean(drv);

	return 0;
}

void hns_mac_reset(struct hns_mac_cb *mac_cb)
{
	struct mac_driver *drv = hns_mac_get_drv(mac_cb);
@@ -1001,6 +1031,20 @@ static int hns_mac_get_max_port_num(struct dsaf_device *dsaf_dev)
		return  DSAF_MAX_PORT_NUM;
}

void hns_mac_enable(struct hns_mac_cb *mac_cb, enum mac_commom_mode mode)
{
	struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);

	mac_ctrl_drv->mac_enable(mac_cb->priv.mac, mode);
}

void hns_mac_disable(struct hns_mac_cb *mac_cb, enum mac_commom_mode mode)
{
	struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);

	mac_ctrl_drv->mac_disable(mac_cb->priv.mac, mode);
}

/**
 * hns_mac_init - init mac
 * @dsaf_dev: dsa fabric device struct pointer
+8 −0
Original line number Diff line number Diff line
@@ -356,6 +356,9 @@ struct mac_driver {
	/*adjust mac mode of port,include speed and duplex*/
	int (*adjust_link)(void *mac_drv, enum mac_speed speed,
			   u32 full_duplex);
	/* need adjust link */
	bool (*need_adjust_link)(void *mac_drv, enum mac_speed speed,
				 int duplex);
	/* config autoegotaite mode of port*/
	void (*set_an_mode)(void *mac_drv, u8 enable);
	/* config loopbank mode */
@@ -394,6 +397,7 @@ struct mac_driver {
	void (*get_info)(void *mac_drv, struct mac_info *mac_info);

	void (*update_stats)(void *mac_drv);
	int (*wait_fifo_clean)(void *mac_drv);

	enum mac_mode mac_mode;
	u8 mac_id;
@@ -427,6 +431,7 @@ void *hns_xgmac_config(struct hns_mac_cb *mac_cb,

int hns_mac_init(struct dsaf_device *dsaf_dev);
void mac_adjust_link(struct net_device *net_dev);
bool hns_mac_need_adjust_link(struct hns_mac_cb *mac_cb, int speed, int duplex);
void hns_mac_get_link_status(struct hns_mac_cb *mac_cb,	u32 *link_status);
int hns_mac_change_vf_addr(struct hns_mac_cb *mac_cb, u32 vmid, char *addr);
int hns_mac_set_multi(struct hns_mac_cb *mac_cb,
@@ -463,5 +468,8 @@ int hns_mac_add_uc_addr(struct hns_mac_cb *mac_cb, u8 vf_id,
int hns_mac_rm_uc_addr(struct hns_mac_cb *mac_cb, u8 vf_id,
		       const unsigned char *addr);
int hns_mac_clr_multicast(struct hns_mac_cb *mac_cb, int vfn);
void hns_mac_enable(struct hns_mac_cb *mac_cb, enum mac_commom_mode mode);
void hns_mac_disable(struct hns_mac_cb *mac_cb, enum mac_commom_mode mode);
int hns_mac_wait_fifo_clean(struct hns_mac_cb *mac_cb);

#endif /* _HNS_DSAF_MAC_H */
Loading