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

Commit def70b61 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'hns-fixes'



Peng Li says:

====================
net: hns: fix some bugs about speed and duplex change

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

This patchset 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 patchset 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 avatarDavid S. Miller <davem@davemloft.net>
parents 05212ba8 455c4401
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;
@@ -430,6 +450,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);
@@ -998,6 +1028,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