12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2511e6bc0Shuangdaode /*
3511e6bc0Shuangdaode * Copyright (c) 2014-2015 Hisilicon Limited.
4511e6bc0Shuangdaode */
5511e6bc0Shuangdaode
61d1afa2eSKejian Yan #include <linux/acpi.h>
7511e6bc0Shuangdaode #include <linux/init.h>
8511e6bc0Shuangdaode #include <linux/interrupt.h>
92e2591b1SDaode Huang #include <linux/kernel.h>
10831d828bSYisen.Zhuang\(Zhuangyuzeng\) #include <linux/mfd/syscon.h>
112e2591b1SDaode Huang #include <linux/module.h>
122e2591b1SDaode Huang #include <linux/netdevice.h>
13511e6bc0Shuangdaode #include <linux/of.h>
14511e6bc0Shuangdaode #include <linux/of_address.h>
15652d39b0SKejian Yan #include <linux/of_mdio.h>
16652d39b0SKejian Yan #include <linux/phy.h>
172e2591b1SDaode Huang #include <linux/platform_device.h>
18511e6bc0Shuangdaode
19511e6bc0Shuangdaode #include "hns_dsaf_main.h"
202e2591b1SDaode Huang #include "hns_dsaf_misc.h"
21511e6bc0Shuangdaode #include "hns_dsaf_rcb.h"
22511e6bc0Shuangdaode
23511e6bc0Shuangdaode #define MAC_EN_FLAG_V 0xada0328
24511e6bc0Shuangdaode
25511e6bc0Shuangdaode static const u16 mac_phy_to_speed[] = {
26511e6bc0Shuangdaode [PHY_INTERFACE_MODE_MII] = MAC_SPEED_100,
27511e6bc0Shuangdaode [PHY_INTERFACE_MODE_GMII] = MAC_SPEED_1000,
28511e6bc0Shuangdaode [PHY_INTERFACE_MODE_SGMII] = MAC_SPEED_1000,
29511e6bc0Shuangdaode [PHY_INTERFACE_MODE_TBI] = MAC_SPEED_1000,
30511e6bc0Shuangdaode [PHY_INTERFACE_MODE_RMII] = MAC_SPEED_100,
31511e6bc0Shuangdaode [PHY_INTERFACE_MODE_RGMII] = MAC_SPEED_1000,
32511e6bc0Shuangdaode [PHY_INTERFACE_MODE_RGMII_ID] = MAC_SPEED_1000,
33511e6bc0Shuangdaode [PHY_INTERFACE_MODE_RGMII_RXID] = MAC_SPEED_1000,
34511e6bc0Shuangdaode [PHY_INTERFACE_MODE_RGMII_TXID] = MAC_SPEED_1000,
35511e6bc0Shuangdaode [PHY_INTERFACE_MODE_RTBI] = MAC_SPEED_1000,
36511e6bc0Shuangdaode [PHY_INTERFACE_MODE_XGMII] = MAC_SPEED_10000
37511e6bc0Shuangdaode };
38511e6bc0Shuangdaode
39511e6bc0Shuangdaode static const enum mac_mode g_mac_mode_100[] = {
40511e6bc0Shuangdaode [PHY_INTERFACE_MODE_MII] = MAC_MODE_MII_100,
41511e6bc0Shuangdaode [PHY_INTERFACE_MODE_RMII] = MAC_MODE_RMII_100
42511e6bc0Shuangdaode };
43511e6bc0Shuangdaode
44511e6bc0Shuangdaode static const enum mac_mode g_mac_mode_1000[] = {
45511e6bc0Shuangdaode [PHY_INTERFACE_MODE_GMII] = MAC_MODE_GMII_1000,
46511e6bc0Shuangdaode [PHY_INTERFACE_MODE_SGMII] = MAC_MODE_SGMII_1000,
47511e6bc0Shuangdaode [PHY_INTERFACE_MODE_TBI] = MAC_MODE_TBI_1000,
48511e6bc0Shuangdaode [PHY_INTERFACE_MODE_RGMII] = MAC_MODE_RGMII_1000,
49511e6bc0Shuangdaode [PHY_INTERFACE_MODE_RGMII_ID] = MAC_MODE_RGMII_1000,
50511e6bc0Shuangdaode [PHY_INTERFACE_MODE_RGMII_RXID] = MAC_MODE_RGMII_1000,
51511e6bc0Shuangdaode [PHY_INTERFACE_MODE_RGMII_TXID] = MAC_MODE_RGMII_1000,
52511e6bc0Shuangdaode [PHY_INTERFACE_MODE_RTBI] = MAC_MODE_RTBI_1000
53511e6bc0Shuangdaode };
54511e6bc0Shuangdaode
hns_get_enet_interface(const struct hns_mac_cb * mac_cb)55511e6bc0Shuangdaode static enum mac_mode hns_get_enet_interface(const struct hns_mac_cb *mac_cb)
56511e6bc0Shuangdaode {
57511e6bc0Shuangdaode switch (mac_cb->max_speed) {
58511e6bc0Shuangdaode case MAC_SPEED_100:
59511e6bc0Shuangdaode return g_mac_mode_100[mac_cb->phy_if];
60511e6bc0Shuangdaode case MAC_SPEED_1000:
61511e6bc0Shuangdaode return g_mac_mode_1000[mac_cb->phy_if];
62511e6bc0Shuangdaode case MAC_SPEED_10000:
63511e6bc0Shuangdaode return MAC_MODE_XGMII_10000;
64511e6bc0Shuangdaode default:
65511e6bc0Shuangdaode return MAC_MODE_MII_100;
66511e6bc0Shuangdaode }
67511e6bc0Shuangdaode }
68511e6bc0Shuangdaode
hns_mac_link_anti_shake(struct mac_driver * mac_ctrl_drv)692daea952SYonglong Liu static u32 hns_mac_link_anti_shake(struct mac_driver *mac_ctrl_drv)
702daea952SYonglong Liu {
712daea952SYonglong Liu #define HNS_MAC_LINK_WAIT_TIME 5
722daea952SYonglong Liu #define HNS_MAC_LINK_WAIT_CNT 40
732daea952SYonglong Liu
742daea952SYonglong Liu u32 link_status = 0;
752daea952SYonglong Liu int i;
762daea952SYonglong Liu
772daea952SYonglong Liu if (!mac_ctrl_drv->get_link_status)
782daea952SYonglong Liu return link_status;
792daea952SYonglong Liu
802daea952SYonglong Liu for (i = 0; i < HNS_MAC_LINK_WAIT_CNT; i++) {
812daea952SYonglong Liu msleep(HNS_MAC_LINK_WAIT_TIME);
822daea952SYonglong Liu mac_ctrl_drv->get_link_status(mac_ctrl_drv, &link_status);
832daea952SYonglong Liu if (!link_status)
842daea952SYonglong Liu break;
852daea952SYonglong Liu }
862daea952SYonglong Liu
872daea952SYonglong Liu return link_status;
882daea952SYonglong Liu }
892daea952SYonglong Liu
hns_mac_get_link_status(struct hns_mac_cb * mac_cb,u32 * link_status)90511e6bc0Shuangdaode void hns_mac_get_link_status(struct hns_mac_cb *mac_cb, u32 *link_status)
91511e6bc0Shuangdaode {
92511e6bc0Shuangdaode struct mac_driver *mac_ctrl_drv;
93511e6bc0Shuangdaode int ret, sfp_prsnt;
94511e6bc0Shuangdaode
95511e6bc0Shuangdaode mac_ctrl_drv = hns_mac_get_drv(mac_cb);
96511e6bc0Shuangdaode
97511e6bc0Shuangdaode if (mac_ctrl_drv->get_link_status)
98511e6bc0Shuangdaode mac_ctrl_drv->get_link_status(mac_ctrl_drv, link_status);
99511e6bc0Shuangdaode else
100511e6bc0Shuangdaode *link_status = 0;
101511e6bc0Shuangdaode
102b917078cSDaode Huang if (mac_cb->media_type == HNAE_MEDIA_TYPE_FIBER) {
103b917078cSDaode Huang ret = mac_cb->dsaf_dev->misc_op->get_sfp_prsnt(mac_cb,
104b917078cSDaode Huang &sfp_prsnt);
105511e6bc0Shuangdaode if (!ret)
106511e6bc0Shuangdaode *link_status = *link_status && sfp_prsnt;
1072daea952SYonglong Liu
1082daea952SYonglong Liu /* for FIBER port, it may have a fake link up.
1092daea952SYonglong Liu * when the link status changes from down to up, we need to do
1102daea952SYonglong Liu * anti-shake. the anti-shake time is base on tests.
1112daea952SYonglong Liu * only FIBER port need to do this.
1122daea952SYonglong Liu */
1132daea952SYonglong Liu if (*link_status && !mac_cb->link)
1142daea952SYonglong Liu *link_status = hns_mac_link_anti_shake(mac_ctrl_drv);
115b917078cSDaode Huang }
116511e6bc0Shuangdaode
117511e6bc0Shuangdaode mac_cb->link = *link_status;
118511e6bc0Shuangdaode }
119511e6bc0Shuangdaode
hns_mac_get_port_info(struct hns_mac_cb * mac_cb,u8 * auto_neg,u16 * speed,u8 * duplex)120511e6bc0Shuangdaode int hns_mac_get_port_info(struct hns_mac_cb *mac_cb,
121511e6bc0Shuangdaode u8 *auto_neg, u16 *speed, u8 *duplex)
122511e6bc0Shuangdaode {
123511e6bc0Shuangdaode struct mac_driver *mac_ctrl_drv;
124511e6bc0Shuangdaode struct mac_info info;
125511e6bc0Shuangdaode
126511e6bc0Shuangdaode mac_ctrl_drv = hns_mac_get_drv(mac_cb);
127511e6bc0Shuangdaode
128511e6bc0Shuangdaode if (!mac_ctrl_drv->get_info)
129511e6bc0Shuangdaode return -ENODEV;
130511e6bc0Shuangdaode
131511e6bc0Shuangdaode mac_ctrl_drv->get_info(mac_ctrl_drv, &info);
132511e6bc0Shuangdaode if (auto_neg)
133511e6bc0Shuangdaode *auto_neg = info.auto_neg;
134511e6bc0Shuangdaode if (speed)
135511e6bc0Shuangdaode *speed = info.speed;
136511e6bc0Shuangdaode if (duplex)
137511e6bc0Shuangdaode *duplex = info.duplex;
138511e6bc0Shuangdaode
139511e6bc0Shuangdaode return 0;
140511e6bc0Shuangdaode }
141511e6bc0Shuangdaode
14231fabbeeSPeng Li /**
1435a9594cfSYang Shen *hns_mac_need_adjust_link - check is need change mac speed and duplex register
14431fabbeeSPeng Li *@mac_cb: mac device
14531fabbeeSPeng Li *@speed: phy device speed
14631fabbeeSPeng Li *@duplex:phy device duplex
14731fabbeeSPeng Li *
14831fabbeeSPeng Li */
hns_mac_need_adjust_link(struct hns_mac_cb * mac_cb,int speed,int duplex)14931fabbeeSPeng Li bool hns_mac_need_adjust_link(struct hns_mac_cb *mac_cb, int speed, int duplex)
15031fabbeeSPeng Li {
15131fabbeeSPeng Li struct mac_driver *mac_ctrl_drv;
15231fabbeeSPeng Li
15331fabbeeSPeng Li mac_ctrl_drv = (struct mac_driver *)(mac_cb->priv.mac);
15431fabbeeSPeng Li
15531fabbeeSPeng Li if (mac_ctrl_drv->need_adjust_link)
15631fabbeeSPeng Li return mac_ctrl_drv->need_adjust_link(mac_ctrl_drv,
15731fabbeeSPeng Li (enum mac_speed)speed, duplex);
15831fabbeeSPeng Li else
15931fabbeeSPeng Li return true;
16031fabbeeSPeng Li }
16131fabbeeSPeng Li
hns_mac_adjust_link(struct hns_mac_cb * mac_cb,int speed,int duplex)162511e6bc0Shuangdaode void hns_mac_adjust_link(struct hns_mac_cb *mac_cb, int speed, int duplex)
163511e6bc0Shuangdaode {
164511e6bc0Shuangdaode int ret;
165511e6bc0Shuangdaode struct mac_driver *mac_ctrl_drv;
166511e6bc0Shuangdaode
167511e6bc0Shuangdaode mac_ctrl_drv = (struct mac_driver *)(mac_cb->priv.mac);
168511e6bc0Shuangdaode
169511e6bc0Shuangdaode mac_cb->speed = speed;
170511e6bc0Shuangdaode mac_cb->half_duplex = !duplex;
171511e6bc0Shuangdaode
172511e6bc0Shuangdaode if (mac_ctrl_drv->adjust_link) {
173511e6bc0Shuangdaode ret = mac_ctrl_drv->adjust_link(mac_ctrl_drv,
174511e6bc0Shuangdaode (enum mac_speed)speed, duplex);
175511e6bc0Shuangdaode if (ret) {
176511e6bc0Shuangdaode dev_err(mac_cb->dev,
177511e6bc0Shuangdaode "adjust_link failed, %s mac%d ret = %#x!\n",
178511e6bc0Shuangdaode mac_cb->dsaf_dev->ae_dev.name,
179511e6bc0Shuangdaode mac_cb->mac_id, ret);
180511e6bc0Shuangdaode return;
181511e6bc0Shuangdaode }
182511e6bc0Shuangdaode }
183511e6bc0Shuangdaode }
184511e6bc0Shuangdaode
185511e6bc0Shuangdaode /**
186511e6bc0Shuangdaode *hns_mac_get_inner_port_num - get mac table inner port number
187511e6bc0Shuangdaode *@mac_cb: mac device
188511e6bc0Shuangdaode *@vmid: vm id
189511e6bc0Shuangdaode *@port_num:port number
190511e6bc0Shuangdaode *
191511e6bc0Shuangdaode */
hns_mac_get_inner_port_num(struct hns_mac_cb * mac_cb,u8 vmid,u8 * port_num)19258035fd9SDaode Huang int hns_mac_get_inner_port_num(struct hns_mac_cb *mac_cb, u8 vmid, u8 *port_num)
193511e6bc0Shuangdaode {
19458035fd9SDaode Huang int q_num_per_vf, vf_num_per_port;
19558035fd9SDaode Huang int vm_queue_id;
196511e6bc0Shuangdaode u8 tmp_port;
197511e6bc0Shuangdaode
198511e6bc0Shuangdaode if (mac_cb->dsaf_dev->dsaf_mode <= DSAF_MODE_ENABLE) {
199831d828bSYisen.Zhuang\(Zhuangyuzeng\) if (mac_cb->mac_id != DSAF_MAX_PORT_NUM) {
200511e6bc0Shuangdaode dev_err(mac_cb->dev,
201511e6bc0Shuangdaode "input invalid, %s mac%d vmid%d !\n",
202511e6bc0Shuangdaode mac_cb->dsaf_dev->ae_dev.name,
203511e6bc0Shuangdaode mac_cb->mac_id, vmid);
204511e6bc0Shuangdaode return -EINVAL;
205511e6bc0Shuangdaode }
206511e6bc0Shuangdaode } else if (mac_cb->dsaf_dev->dsaf_mode < DSAF_MODE_MAX) {
207831d828bSYisen.Zhuang\(Zhuangyuzeng\) if (mac_cb->mac_id >= DSAF_MAX_PORT_NUM) {
208511e6bc0Shuangdaode dev_err(mac_cb->dev,
209511e6bc0Shuangdaode "input invalid, %s mac%d vmid%d!\n",
210511e6bc0Shuangdaode mac_cb->dsaf_dev->ae_dev.name,
211511e6bc0Shuangdaode mac_cb->mac_id, vmid);
212511e6bc0Shuangdaode return -EINVAL;
213511e6bc0Shuangdaode }
214511e6bc0Shuangdaode } else {
215511e6bc0Shuangdaode dev_err(mac_cb->dev, "dsaf mode invalid, %s mac%d!\n",
216511e6bc0Shuangdaode mac_cb->dsaf_dev->ae_dev.name, mac_cb->mac_id);
217511e6bc0Shuangdaode return -EINVAL;
218511e6bc0Shuangdaode }
219511e6bc0Shuangdaode
220831d828bSYisen.Zhuang\(Zhuangyuzeng\) if (vmid >= mac_cb->dsaf_dev->rcb_common[0]->max_vfn) {
221511e6bc0Shuangdaode dev_err(mac_cb->dev, "input invalid, %s mac%d vmid%d !\n",
222511e6bc0Shuangdaode mac_cb->dsaf_dev->ae_dev.name, mac_cb->mac_id, vmid);
223511e6bc0Shuangdaode return -EINVAL;
224511e6bc0Shuangdaode }
225511e6bc0Shuangdaode
22658035fd9SDaode Huang q_num_per_vf = mac_cb->dsaf_dev->rcb_common[0]->max_q_per_vf;
22758035fd9SDaode Huang vf_num_per_port = mac_cb->dsaf_dev->rcb_common[0]->max_vfn;
22858035fd9SDaode Huang
22958035fd9SDaode Huang vm_queue_id = vmid * q_num_per_vf +
23058035fd9SDaode Huang vf_num_per_port * q_num_per_vf * mac_cb->mac_id;
23158035fd9SDaode Huang
232511e6bc0Shuangdaode switch (mac_cb->dsaf_dev->dsaf_mode) {
233511e6bc0Shuangdaode case DSAF_MODE_ENABLE_FIX:
234511e6bc0Shuangdaode tmp_port = 0;
235511e6bc0Shuangdaode break;
236511e6bc0Shuangdaode case DSAF_MODE_DISABLE_FIX:
237511e6bc0Shuangdaode tmp_port = 0;
238511e6bc0Shuangdaode break;
239511e6bc0Shuangdaode case DSAF_MODE_ENABLE_0VM:
240511e6bc0Shuangdaode case DSAF_MODE_ENABLE_8VM:
241511e6bc0Shuangdaode case DSAF_MODE_ENABLE_16VM:
242511e6bc0Shuangdaode case DSAF_MODE_ENABLE_32VM:
243511e6bc0Shuangdaode case DSAF_MODE_ENABLE_128VM:
244511e6bc0Shuangdaode case DSAF_MODE_DISABLE_2PORT_8VM:
245511e6bc0Shuangdaode case DSAF_MODE_DISABLE_2PORT_16VM:
246511e6bc0Shuangdaode case DSAF_MODE_DISABLE_2PORT_64VM:
247511e6bc0Shuangdaode case DSAF_MODE_DISABLE_6PORT_0VM:
248511e6bc0Shuangdaode case DSAF_MODE_DISABLE_6PORT_2VM:
249511e6bc0Shuangdaode case DSAF_MODE_DISABLE_6PORT_4VM:
250511e6bc0Shuangdaode case DSAF_MODE_DISABLE_6PORT_16VM:
25158035fd9SDaode Huang tmp_port = vm_queue_id;
252511e6bc0Shuangdaode break;
253511e6bc0Shuangdaode default:
254511e6bc0Shuangdaode dev_err(mac_cb->dev, "dsaf mode invalid, %s mac%d!\n",
255511e6bc0Shuangdaode mac_cb->dsaf_dev->ae_dev.name, mac_cb->mac_id);
256511e6bc0Shuangdaode return -EINVAL;
257511e6bc0Shuangdaode }
258511e6bc0Shuangdaode tmp_port += DSAF_BASE_INNER_PORT_NUM;
259511e6bc0Shuangdaode
260511e6bc0Shuangdaode *port_num = tmp_port;
261511e6bc0Shuangdaode
262511e6bc0Shuangdaode return 0;
263511e6bc0Shuangdaode }
264511e6bc0Shuangdaode
265511e6bc0Shuangdaode /**
266831d828bSYisen.Zhuang\(Zhuangyuzeng\) *hns_mac_change_vf_addr - change vf mac address
267511e6bc0Shuangdaode *@mac_cb: mac device
268511e6bc0Shuangdaode *@vmid: vmid
269511e6bc0Shuangdaode *@addr:mac address
270511e6bc0Shuangdaode */
hns_mac_change_vf_addr(struct hns_mac_cb * mac_cb,u32 vmid,const char * addr)271511e6bc0Shuangdaode int hns_mac_change_vf_addr(struct hns_mac_cb *mac_cb,
27276660757SJakub Kicinski u32 vmid, const char *addr)
273511e6bc0Shuangdaode {
274511e6bc0Shuangdaode int ret;
275511e6bc0Shuangdaode struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
276511e6bc0Shuangdaode struct dsaf_device *dsaf_dev = mac_cb->dsaf_dev;
277511e6bc0Shuangdaode struct dsaf_drv_mac_single_dest_entry mac_entry;
278511e6bc0Shuangdaode struct mac_entry_idx *old_entry;
279511e6bc0Shuangdaode
280511e6bc0Shuangdaode old_entry = &mac_cb->addr_entry_idx[vmid];
28189a44093SYisen.Zhuang\(Zhuangyuzeng\) if (!HNS_DSAF_IS_DEBUG(dsaf_dev)) {
282511e6bc0Shuangdaode memcpy(mac_entry.addr, addr, sizeof(mac_entry.addr));
283511e6bc0Shuangdaode mac_entry.in_vlan_id = old_entry->vlan_id;
284511e6bc0Shuangdaode mac_entry.in_port_num = mac_cb->mac_id;
285511e6bc0Shuangdaode ret = hns_mac_get_inner_port_num(mac_cb, (u8)vmid,
286511e6bc0Shuangdaode &mac_entry.port_num);
287511e6bc0Shuangdaode if (ret)
288511e6bc0Shuangdaode return ret;
289511e6bc0Shuangdaode
290511e6bc0Shuangdaode if ((old_entry->valid != 0) &&
291511e6bc0Shuangdaode (memcmp(old_entry->addr,
292511e6bc0Shuangdaode addr, sizeof(mac_entry.addr)) != 0)) {
293511e6bc0Shuangdaode ret = hns_dsaf_del_mac_entry(dsaf_dev,
294511e6bc0Shuangdaode old_entry->vlan_id,
295511e6bc0Shuangdaode mac_cb->mac_id,
296511e6bc0Shuangdaode old_entry->addr);
297511e6bc0Shuangdaode if (ret)
298511e6bc0Shuangdaode return ret;
299511e6bc0Shuangdaode }
300511e6bc0Shuangdaode
301511e6bc0Shuangdaode ret = hns_dsaf_set_mac_uc_entry(dsaf_dev, &mac_entry);
302511e6bc0Shuangdaode if (ret)
303511e6bc0Shuangdaode return ret;
304511e6bc0Shuangdaode }
305511e6bc0Shuangdaode
306511e6bc0Shuangdaode if ((mac_ctrl_drv->set_mac_addr) && (vmid == 0))
307511e6bc0Shuangdaode mac_ctrl_drv->set_mac_addr(mac_cb->priv.mac, addr);
308511e6bc0Shuangdaode
309511e6bc0Shuangdaode memcpy(old_entry->addr, addr, sizeof(old_entry->addr));
310511e6bc0Shuangdaode old_entry->valid = 1;
311511e6bc0Shuangdaode return 0;
312511e6bc0Shuangdaode }
313511e6bc0Shuangdaode
hns_mac_add_uc_addr(struct hns_mac_cb * mac_cb,u8 vf_id,const unsigned char * addr)31466355f52SKejian Yan int hns_mac_add_uc_addr(struct hns_mac_cb *mac_cb, u8 vf_id,
31566355f52SKejian Yan const unsigned char *addr)
31666355f52SKejian Yan {
31766355f52SKejian Yan struct dsaf_device *dsaf_dev = mac_cb->dsaf_dev;
31866355f52SKejian Yan struct dsaf_drv_mac_single_dest_entry mac_entry;
31966355f52SKejian Yan int ret;
32066355f52SKejian Yan
32166355f52SKejian Yan if (HNS_DSAF_IS_DEBUG(dsaf_dev))
32266355f52SKejian Yan return -ENOSPC;
32366355f52SKejian Yan
32466355f52SKejian Yan memset(&mac_entry, 0, sizeof(mac_entry));
32566355f52SKejian Yan memcpy(mac_entry.addr, addr, sizeof(mac_entry.addr));
32666355f52SKejian Yan mac_entry.in_port_num = mac_cb->mac_id;
32766355f52SKejian Yan ret = hns_mac_get_inner_port_num(mac_cb, vf_id, &mac_entry.port_num);
32866355f52SKejian Yan if (ret)
32966355f52SKejian Yan return ret;
33066355f52SKejian Yan
33166355f52SKejian Yan return hns_dsaf_set_mac_uc_entry(dsaf_dev, &mac_entry);
33266355f52SKejian Yan }
33366355f52SKejian Yan
hns_mac_rm_uc_addr(struct hns_mac_cb * mac_cb,u8 vf_id,const unsigned char * addr)33466355f52SKejian Yan int hns_mac_rm_uc_addr(struct hns_mac_cb *mac_cb, u8 vf_id,
33566355f52SKejian Yan const unsigned char *addr)
33666355f52SKejian Yan {
33766355f52SKejian Yan struct dsaf_device *dsaf_dev = mac_cb->dsaf_dev;
33866355f52SKejian Yan struct dsaf_drv_mac_single_dest_entry mac_entry;
33966355f52SKejian Yan int ret;
34066355f52SKejian Yan
34166355f52SKejian Yan if (HNS_DSAF_IS_DEBUG(dsaf_dev))
34266355f52SKejian Yan return -ENOSPC;
34366355f52SKejian Yan
34466355f52SKejian Yan memset(&mac_entry, 0, sizeof(mac_entry));
34566355f52SKejian Yan memcpy(mac_entry.addr, addr, sizeof(mac_entry.addr));
34666355f52SKejian Yan mac_entry.in_port_num = mac_cb->mac_id;
34766355f52SKejian Yan ret = hns_mac_get_inner_port_num(mac_cb, vf_id, &mac_entry.port_num);
34866355f52SKejian Yan if (ret)
34966355f52SKejian Yan return ret;
35066355f52SKejian Yan
35166355f52SKejian Yan return hns_dsaf_rm_mac_addr(dsaf_dev, &mac_entry);
35266355f52SKejian Yan }
35366355f52SKejian Yan
hns_mac_set_multi(struct hns_mac_cb * mac_cb,u32 port_num,char * addr,bool enable)354511e6bc0Shuangdaode int hns_mac_set_multi(struct hns_mac_cb *mac_cb,
35513ac695eSSalil u32 port_num, char *addr, bool enable)
356511e6bc0Shuangdaode {
357511e6bc0Shuangdaode int ret;
358511e6bc0Shuangdaode struct dsaf_device *dsaf_dev = mac_cb->dsaf_dev;
359511e6bc0Shuangdaode struct dsaf_drv_mac_single_dest_entry mac_entry;
360511e6bc0Shuangdaode
36189a44093SYisen.Zhuang\(Zhuangyuzeng\) if (!HNS_DSAF_IS_DEBUG(dsaf_dev) && addr) {
362511e6bc0Shuangdaode memcpy(mac_entry.addr, addr, sizeof(mac_entry.addr));
363511e6bc0Shuangdaode mac_entry.in_vlan_id = 0;/*vlan_id;*/
364511e6bc0Shuangdaode mac_entry.in_port_num = mac_cb->mac_id;
365511e6bc0Shuangdaode mac_entry.port_num = port_num;
366511e6bc0Shuangdaode
36713ac695eSSalil if (!enable)
368511e6bc0Shuangdaode ret = hns_dsaf_del_mac_mc_port(dsaf_dev, &mac_entry);
369511e6bc0Shuangdaode else
370511e6bc0Shuangdaode ret = hns_dsaf_add_mac_mc_port(dsaf_dev, &mac_entry);
371511e6bc0Shuangdaode if (ret) {
372511e6bc0Shuangdaode dev_err(dsaf_dev->dev,
373511e6bc0Shuangdaode "set mac mc port failed, %s mac%d ret = %#x!\n",
374511e6bc0Shuangdaode mac_cb->dsaf_dev->ae_dev.name,
375511e6bc0Shuangdaode mac_cb->mac_id, ret);
376511e6bc0Shuangdaode return ret;
377511e6bc0Shuangdaode }
378511e6bc0Shuangdaode }
379511e6bc0Shuangdaode
380511e6bc0Shuangdaode return 0;
381511e6bc0Shuangdaode }
382511e6bc0Shuangdaode
hns_mac_clr_multicast(struct hns_mac_cb * mac_cb,int vfn)383ec2cafe6SKejian Yan int hns_mac_clr_multicast(struct hns_mac_cb *mac_cb, int vfn)
384ec2cafe6SKejian Yan {
385ec2cafe6SKejian Yan struct dsaf_device *dsaf_dev = mac_cb->dsaf_dev;
386ec2cafe6SKejian Yan u8 port_num;
387ec2cafe6SKejian Yan int ret = hns_mac_get_inner_port_num(mac_cb, vfn, &port_num);
388ec2cafe6SKejian Yan
389ec2cafe6SKejian Yan if (ret)
390ec2cafe6SKejian Yan return ret;
391ec2cafe6SKejian Yan
392ec2cafe6SKejian Yan return hns_dsaf_clr_mac_mc_port(dsaf_dev, mac_cb->mac_id, port_num);
393ec2cafe6SKejian Yan }
394ec2cafe6SKejian Yan
hns_mac_param_get(struct mac_params * param,struct hns_mac_cb * mac_cb)395511e6bc0Shuangdaode static void hns_mac_param_get(struct mac_params *param,
396511e6bc0Shuangdaode struct hns_mac_cb *mac_cb)
397511e6bc0Shuangdaode {
39815400663SYonglong Liu param->vaddr = mac_cb->vaddr;
399511e6bc0Shuangdaode param->mac_mode = hns_get_enet_interface(mac_cb);
400153b1d48SKejian Yan ether_addr_copy(param->addr, mac_cb->addr_entry_idx[0].addr);
401511e6bc0Shuangdaode param->mac_id = mac_cb->mac_id;
402511e6bc0Shuangdaode param->dev = mac_cb->dev;
403511e6bc0Shuangdaode }
404511e6bc0Shuangdaode
405511e6bc0Shuangdaode /**
4065a9594cfSYang Shen * hns_mac_port_config_bc_en - set broadcast rx&tx enable
407511e6bc0Shuangdaode * @mac_cb: mac device
408d0ea5cbdSJesse Brandeburg * @port_num: queue number
409d0ea5cbdSJesse Brandeburg * @vlan_id: vlan id`
410d0ea5cbdSJesse Brandeburg * @enable: enable
411d0ea5cbdSJesse Brandeburg * return 0 - success , negative --fail
412511e6bc0Shuangdaode */
hns_mac_port_config_bc_en(struct hns_mac_cb * mac_cb,u32 port_num,u16 vlan_id,bool enable)413511e6bc0Shuangdaode static int hns_mac_port_config_bc_en(struct hns_mac_cb *mac_cb,
41413ac695eSSalil u32 port_num, u16 vlan_id, bool enable)
415511e6bc0Shuangdaode {
416511e6bc0Shuangdaode int ret;
417511e6bc0Shuangdaode struct dsaf_device *dsaf_dev = mac_cb->dsaf_dev;
418511e6bc0Shuangdaode struct dsaf_drv_mac_single_dest_entry mac_entry;
419511e6bc0Shuangdaode
420511e6bc0Shuangdaode /* directy return ok in debug network mode */
421511e6bc0Shuangdaode if (mac_cb->mac_type == HNAE_PORT_DEBUG)
422511e6bc0Shuangdaode return 0;
423511e6bc0Shuangdaode
42489a44093SYisen.Zhuang\(Zhuangyuzeng\) if (!HNS_DSAF_IS_DEBUG(dsaf_dev)) {
42549b44aa2SJoe Perches eth_broadcast_addr(mac_entry.addr);
426511e6bc0Shuangdaode mac_entry.in_vlan_id = vlan_id;
427511e6bc0Shuangdaode mac_entry.in_port_num = mac_cb->mac_id;
428511e6bc0Shuangdaode mac_entry.port_num = port_num;
429511e6bc0Shuangdaode
43013ac695eSSalil if (!enable)
431511e6bc0Shuangdaode ret = hns_dsaf_del_mac_mc_port(dsaf_dev, &mac_entry);
432511e6bc0Shuangdaode else
433511e6bc0Shuangdaode ret = hns_dsaf_add_mac_mc_port(dsaf_dev, &mac_entry);
434511e6bc0Shuangdaode return ret;
435511e6bc0Shuangdaode }
436511e6bc0Shuangdaode
437511e6bc0Shuangdaode return 0;
438511e6bc0Shuangdaode }
439511e6bc0Shuangdaode
440511e6bc0Shuangdaode /**
441511e6bc0Shuangdaode * hns_mac_vm_config_bc_en - set broadcast rx&tx enable
442511e6bc0Shuangdaode * @mac_cb: mac device
443511e6bc0Shuangdaode * @vmid: vm id
444d0ea5cbdSJesse Brandeburg * @enable: enable
445d0ea5cbdSJesse Brandeburg * return 0 - success , negative --fail
446511e6bc0Shuangdaode */
hns_mac_vm_config_bc_en(struct hns_mac_cb * mac_cb,u32 vmid,bool enable)44713ac695eSSalil int hns_mac_vm_config_bc_en(struct hns_mac_cb *mac_cb, u32 vmid, bool enable)
448511e6bc0Shuangdaode {
449511e6bc0Shuangdaode int ret;
450511e6bc0Shuangdaode struct dsaf_device *dsaf_dev = mac_cb->dsaf_dev;
451511e6bc0Shuangdaode u8 port_num;
452511e6bc0Shuangdaode struct mac_entry_idx *uc_mac_entry;
453511e6bc0Shuangdaode struct dsaf_drv_mac_single_dest_entry mac_entry;
454511e6bc0Shuangdaode
455511e6bc0Shuangdaode if (mac_cb->mac_type == HNAE_PORT_DEBUG)
456511e6bc0Shuangdaode return 0;
457511e6bc0Shuangdaode
458511e6bc0Shuangdaode uc_mac_entry = &mac_cb->addr_entry_idx[vmid];
459511e6bc0Shuangdaode
46089a44093SYisen.Zhuang\(Zhuangyuzeng\) if (!HNS_DSAF_IS_DEBUG(dsaf_dev)) {
46149b44aa2SJoe Perches eth_broadcast_addr(mac_entry.addr);
462511e6bc0Shuangdaode mac_entry.in_vlan_id = uc_mac_entry->vlan_id;
463511e6bc0Shuangdaode mac_entry.in_port_num = mac_cb->mac_id;
464511e6bc0Shuangdaode ret = hns_mac_get_inner_port_num(mac_cb, vmid, &port_num);
465511e6bc0Shuangdaode if (ret)
466511e6bc0Shuangdaode return ret;
467511e6bc0Shuangdaode mac_entry.port_num = port_num;
468511e6bc0Shuangdaode
46913ac695eSSalil if (!enable)
470511e6bc0Shuangdaode ret = hns_dsaf_del_mac_mc_port(dsaf_dev, &mac_entry);
471511e6bc0Shuangdaode else
472511e6bc0Shuangdaode ret = hns_dsaf_add_mac_mc_port(dsaf_dev, &mac_entry);
473511e6bc0Shuangdaode return ret;
474511e6bc0Shuangdaode }
475511e6bc0Shuangdaode
476511e6bc0Shuangdaode return 0;
477511e6bc0Shuangdaode }
478511e6bc0Shuangdaode
hns_mac_wait_fifo_clean(struct hns_mac_cb * mac_cb)47931fabbeeSPeng Li int hns_mac_wait_fifo_clean(struct hns_mac_cb *mac_cb)
48031fabbeeSPeng Li {
48131fabbeeSPeng Li struct mac_driver *drv = hns_mac_get_drv(mac_cb);
48231fabbeeSPeng Li
48331fabbeeSPeng Li if (drv->wait_fifo_clean)
48431fabbeeSPeng Li return drv->wait_fifo_clean(drv);
48531fabbeeSPeng Li
48631fabbeeSPeng Li return 0;
48731fabbeeSPeng Li }
48831fabbeeSPeng Li
hns_mac_reset(struct hns_mac_cb * mac_cb)489511e6bc0Shuangdaode void hns_mac_reset(struct hns_mac_cb *mac_cb)
490511e6bc0Shuangdaode {
4915ada37b5SLisheng struct mac_driver *drv = hns_mac_get_drv(mac_cb);
4925ada37b5SLisheng bool is_ver1 = AE_IS_VER1(mac_cb->dsaf_dev->dsaf_ver);
493511e6bc0Shuangdaode
494511e6bc0Shuangdaode drv->mac_init(drv);
495511e6bc0Shuangdaode
496511e6bc0Shuangdaode if (drv->config_max_frame_length)
497511e6bc0Shuangdaode drv->config_max_frame_length(drv, mac_cb->max_frm);
498511e6bc0Shuangdaode
499511e6bc0Shuangdaode if (drv->set_tx_auto_pause_frames)
500511e6bc0Shuangdaode drv->set_tx_auto_pause_frames(drv, mac_cb->tx_pause_frm_time);
501511e6bc0Shuangdaode
502511e6bc0Shuangdaode if (drv->set_an_mode)
503511e6bc0Shuangdaode drv->set_an_mode(drv, 1);
504511e6bc0Shuangdaode
505511e6bc0Shuangdaode if (drv->mac_pausefrm_cfg) {
506511e6bc0Shuangdaode if (mac_cb->mac_type == HNAE_PORT_DEBUG)
5075ada37b5SLisheng drv->mac_pausefrm_cfg(drv, !is_ver1, !is_ver1);
508511e6bc0Shuangdaode else /* mac rx must disable, dsaf pfc close instead of it*/
509511e6bc0Shuangdaode drv->mac_pausefrm_cfg(drv, 0, 1);
510511e6bc0Shuangdaode }
511511e6bc0Shuangdaode }
512511e6bc0Shuangdaode
hns_mac_set_mtu(struct hns_mac_cb * mac_cb,u32 new_mtu,u32 buf_size)513b29bd412Slipeng int hns_mac_set_mtu(struct hns_mac_cb *mac_cb, u32 new_mtu, u32 buf_size)
514511e6bc0Shuangdaode {
515511e6bc0Shuangdaode struct mac_driver *drv = hns_mac_get_drv(mac_cb);
516511e6bc0Shuangdaode u32 new_frm = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
517211b1384SKejian Yan
51844770e11SJarod Wilson if (new_frm > HNS_RCB_RING_MAX_BD_PER_PKT * buf_size)
519511e6bc0Shuangdaode return -EINVAL;
520511e6bc0Shuangdaode
521511e6bc0Shuangdaode if (!drv->config_max_frame_length)
522511e6bc0Shuangdaode return -ECHILD;
523511e6bc0Shuangdaode
524511e6bc0Shuangdaode /* adjust max frame to be at least the size of a standard frame */
525511e6bc0Shuangdaode if (new_frm < (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN))
526511e6bc0Shuangdaode new_frm = (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN);
527511e6bc0Shuangdaode
528511e6bc0Shuangdaode drv->config_max_frame_length(drv, new_frm);
529511e6bc0Shuangdaode
530511e6bc0Shuangdaode mac_cb->max_frm = new_frm;
531511e6bc0Shuangdaode
532511e6bc0Shuangdaode return 0;
533511e6bc0Shuangdaode }
534511e6bc0Shuangdaode
hns_mac_start(struct hns_mac_cb * mac_cb)535511e6bc0Shuangdaode void hns_mac_start(struct hns_mac_cb *mac_cb)
536511e6bc0Shuangdaode {
537511e6bc0Shuangdaode struct mac_driver *mac_drv = hns_mac_get_drv(mac_cb);
538511e6bc0Shuangdaode
539511e6bc0Shuangdaode /* for virt */
540511e6bc0Shuangdaode if (mac_drv->mac_en_flg == MAC_EN_FLAG_V) {
541511e6bc0Shuangdaode /*plus 1 when the virtual mac has been enabled */
542511e6bc0Shuangdaode mac_drv->virt_dev_num += 1;
543511e6bc0Shuangdaode return;
544511e6bc0Shuangdaode }
545511e6bc0Shuangdaode
546511e6bc0Shuangdaode if (mac_drv->mac_enable) {
547511e6bc0Shuangdaode mac_drv->mac_enable(mac_cb->priv.mac, MAC_COMM_MODE_RX_AND_TX);
548511e6bc0Shuangdaode mac_drv->mac_en_flg = MAC_EN_FLAG_V;
549511e6bc0Shuangdaode }
550511e6bc0Shuangdaode }
551511e6bc0Shuangdaode
hns_mac_stop(struct hns_mac_cb * mac_cb)552511e6bc0Shuangdaode void hns_mac_stop(struct hns_mac_cb *mac_cb)
553511e6bc0Shuangdaode {
554511e6bc0Shuangdaode struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
555511e6bc0Shuangdaode
556511e6bc0Shuangdaode /*modified for virtualization */
557511e6bc0Shuangdaode if (mac_ctrl_drv->virt_dev_num > 0) {
558511e6bc0Shuangdaode mac_ctrl_drv->virt_dev_num -= 1;
559511e6bc0Shuangdaode if (mac_ctrl_drv->virt_dev_num > 0)
560511e6bc0Shuangdaode return;
561511e6bc0Shuangdaode }
562511e6bc0Shuangdaode
563511e6bc0Shuangdaode if (mac_ctrl_drv->mac_disable)
564511e6bc0Shuangdaode mac_ctrl_drv->mac_disable(mac_cb->priv.mac,
565511e6bc0Shuangdaode MAC_COMM_MODE_RX_AND_TX);
566511e6bc0Shuangdaode
567511e6bc0Shuangdaode mac_ctrl_drv->mac_en_flg = 0;
568511e6bc0Shuangdaode mac_cb->link = 0;
569a24274aaSKejian Yan mac_cb->dsaf_dev->misc_op->cpld_reset_led(mac_cb);
570511e6bc0Shuangdaode }
571511e6bc0Shuangdaode
572511e6bc0Shuangdaode /**
573511e6bc0Shuangdaode * hns_mac_get_autoneg - get auto autonegotiation
574511e6bc0Shuangdaode * @mac_cb: mac control block
575d0ea5cbdSJesse Brandeburg * @auto_neg: output pointer to autoneg result
576d0ea5cbdSJesse Brandeburg * return 0 - success , negative --fail
577511e6bc0Shuangdaode */
hns_mac_get_autoneg(struct hns_mac_cb * mac_cb,u32 * auto_neg)578511e6bc0Shuangdaode void hns_mac_get_autoneg(struct hns_mac_cb *mac_cb, u32 *auto_neg)
579511e6bc0Shuangdaode {
580511e6bc0Shuangdaode struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
581511e6bc0Shuangdaode
582511e6bc0Shuangdaode if (mac_ctrl_drv->autoneg_stat)
583511e6bc0Shuangdaode mac_ctrl_drv->autoneg_stat(mac_ctrl_drv, auto_neg);
584511e6bc0Shuangdaode else
585511e6bc0Shuangdaode *auto_neg = 0;
586511e6bc0Shuangdaode }
587511e6bc0Shuangdaode
588511e6bc0Shuangdaode /**
589511e6bc0Shuangdaode * hns_mac_get_pauseparam - set rx & tx pause parameter
590511e6bc0Shuangdaode * @mac_cb: mac control block
591511e6bc0Shuangdaode * @rx_en: rx enable status
592511e6bc0Shuangdaode * @tx_en: tx enable status
593d0ea5cbdSJesse Brandeburg * return 0 - success , negative --fail
594511e6bc0Shuangdaode */
hns_mac_get_pauseparam(struct hns_mac_cb * mac_cb,u32 * rx_en,u32 * tx_en)595511e6bc0Shuangdaode void hns_mac_get_pauseparam(struct hns_mac_cb *mac_cb, u32 *rx_en, u32 *tx_en)
596511e6bc0Shuangdaode {
597511e6bc0Shuangdaode struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
598511e6bc0Shuangdaode
599511e6bc0Shuangdaode if (mac_ctrl_drv->get_pause_enable) {
600511e6bc0Shuangdaode mac_ctrl_drv->get_pause_enable(mac_ctrl_drv, rx_en, tx_en);
601511e6bc0Shuangdaode } else {
602511e6bc0Shuangdaode *rx_en = 0;
603511e6bc0Shuangdaode *tx_en = 0;
604511e6bc0Shuangdaode }
605511e6bc0Shuangdaode }
606511e6bc0Shuangdaode
607511e6bc0Shuangdaode /**
608511e6bc0Shuangdaode * hns_mac_set_autoneg - set auto autonegotiation
609511e6bc0Shuangdaode * @mac_cb: mac control block
610511e6bc0Shuangdaode * @enable: enable or not
611d0ea5cbdSJesse Brandeburg * return 0 - success , negative --fail
612511e6bc0Shuangdaode */
hns_mac_set_autoneg(struct hns_mac_cb * mac_cb,u8 enable)613511e6bc0Shuangdaode int hns_mac_set_autoneg(struct hns_mac_cb *mac_cb, u8 enable)
614511e6bc0Shuangdaode {
615511e6bc0Shuangdaode struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
616511e6bc0Shuangdaode
617511e6bc0Shuangdaode if (mac_cb->phy_if == PHY_INTERFACE_MODE_XGMII && enable) {
618451e856eSColin Ian King dev_err(mac_cb->dev, "enabling autoneg is not allowed!\n");
619511e6bc0Shuangdaode return -ENOTSUPP;
620511e6bc0Shuangdaode }
621511e6bc0Shuangdaode
622511e6bc0Shuangdaode if (mac_ctrl_drv->set_an_mode)
623511e6bc0Shuangdaode mac_ctrl_drv->set_an_mode(mac_ctrl_drv, enable);
624511e6bc0Shuangdaode
625511e6bc0Shuangdaode return 0;
626511e6bc0Shuangdaode }
627511e6bc0Shuangdaode
628511e6bc0Shuangdaode /**
6295a9594cfSYang Shen * hns_mac_set_pauseparam - set rx & tx pause parameter
630511e6bc0Shuangdaode * @mac_cb: mac control block
631511e6bc0Shuangdaode * @rx_en: rx enable or not
632511e6bc0Shuangdaode * @tx_en: tx enable or not
633511e6bc0Shuangdaode * return 0 - success , negative --fail
634511e6bc0Shuangdaode */
hns_mac_set_pauseparam(struct hns_mac_cb * mac_cb,u32 rx_en,u32 tx_en)635511e6bc0Shuangdaode int hns_mac_set_pauseparam(struct hns_mac_cb *mac_cb, u32 rx_en, u32 tx_en)
636511e6bc0Shuangdaode {
637511e6bc0Shuangdaode struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
6385ada37b5SLisheng bool is_ver1 = AE_IS_VER1(mac_cb->dsaf_dev->dsaf_ver);
639511e6bc0Shuangdaode
6405ada37b5SLisheng if (mac_cb->mac_type == HNAE_PORT_DEBUG) {
6415ada37b5SLisheng if (is_ver1 && (tx_en || rx_en)) {
642451e856eSColin Ian King dev_err(mac_cb->dev, "macv1 can't enable tx/rx_pause!\n");
643511e6bc0Shuangdaode return -EINVAL;
644511e6bc0Shuangdaode }
645511e6bc0Shuangdaode }
646511e6bc0Shuangdaode
647511e6bc0Shuangdaode if (mac_ctrl_drv->mac_pausefrm_cfg)
648511e6bc0Shuangdaode mac_ctrl_drv->mac_pausefrm_cfg(mac_ctrl_drv, rx_en, tx_en);
649511e6bc0Shuangdaode
650511e6bc0Shuangdaode return 0;
651511e6bc0Shuangdaode }
652511e6bc0Shuangdaode
653511e6bc0Shuangdaode /**
654511e6bc0Shuangdaode * hns_mac_init_ex - mac init
655511e6bc0Shuangdaode * @mac_cb: mac control block
656d0ea5cbdSJesse Brandeburg * return 0 - success , negative --fail
657511e6bc0Shuangdaode */
hns_mac_init_ex(struct hns_mac_cb * mac_cb)658511e6bc0Shuangdaode static int hns_mac_init_ex(struct hns_mac_cb *mac_cb)
659511e6bc0Shuangdaode {
660511e6bc0Shuangdaode int ret;
661511e6bc0Shuangdaode struct mac_params param;
662511e6bc0Shuangdaode struct mac_driver *drv;
663511e6bc0Shuangdaode
664511e6bc0Shuangdaode hns_dsaf_fix_mac_mode(mac_cb);
665511e6bc0Shuangdaode
666511e6bc0Shuangdaode memset(¶m, 0, sizeof(struct mac_params));
667511e6bc0Shuangdaode hns_mac_param_get(¶m, mac_cb);
668511e6bc0Shuangdaode
669511e6bc0Shuangdaode if (MAC_SPEED_FROM_MODE(param.mac_mode) < MAC_SPEED_10000)
670511e6bc0Shuangdaode drv = (struct mac_driver *)hns_gmac_config(mac_cb, ¶m);
671511e6bc0Shuangdaode else
672511e6bc0Shuangdaode drv = (struct mac_driver *)hns_xgmac_config(mac_cb, ¶m);
673511e6bc0Shuangdaode
674511e6bc0Shuangdaode if (!drv)
675511e6bc0Shuangdaode return -ENOMEM;
676511e6bc0Shuangdaode
677511e6bc0Shuangdaode mac_cb->priv.mac = (void *)drv;
678511e6bc0Shuangdaode hns_mac_reset(mac_cb);
679511e6bc0Shuangdaode
680511e6bc0Shuangdaode hns_mac_adjust_link(mac_cb, mac_cb->speed, !mac_cb->half_duplex);
681511e6bc0Shuangdaode
68213ac695eSSalil ret = hns_mac_port_config_bc_en(mac_cb, mac_cb->mac_id, 0, true);
683511e6bc0Shuangdaode if (ret)
684511e6bc0Shuangdaode goto free_mac_drv;
685511e6bc0Shuangdaode
686511e6bc0Shuangdaode return 0;
687511e6bc0Shuangdaode
688511e6bc0Shuangdaode free_mac_drv:
689511e6bc0Shuangdaode drv->mac_free(mac_cb->priv.mac);
690511e6bc0Shuangdaode mac_cb->priv.mac = NULL;
691511e6bc0Shuangdaode
692511e6bc0Shuangdaode return ret;
693511e6bc0Shuangdaode }
694511e6bc0Shuangdaode
6951d1afa2eSKejian Yan static int
hns_mac_phy_parse_addr(struct device * dev,struct fwnode_handle * fwnode)6961d1afa2eSKejian Yan hns_mac_phy_parse_addr(struct device *dev, struct fwnode_handle *fwnode)
6971d1afa2eSKejian Yan {
6981d1afa2eSKejian Yan u32 addr;
6991d1afa2eSKejian Yan int ret;
7001d1afa2eSKejian Yan
7011d1afa2eSKejian Yan ret = fwnode_property_read_u32(fwnode, "phy-addr", &addr);
7021d1afa2eSKejian Yan if (ret) {
7031d1afa2eSKejian Yan dev_err(dev, "has invalid PHY address ret:%d\n", ret);
7041d1afa2eSKejian Yan return ret;
7051d1afa2eSKejian Yan }
7061d1afa2eSKejian Yan
7071d1afa2eSKejian Yan if (addr >= PHY_MAX_ADDR) {
7081d1afa2eSKejian Yan dev_err(dev, "PHY address %i is too large\n", addr);
7091d1afa2eSKejian Yan return -EINVAL;
7101d1afa2eSKejian Yan }
7111d1afa2eSKejian Yan
7121d1afa2eSKejian Yan return addr;
7131d1afa2eSKejian Yan }
7141d1afa2eSKejian Yan
7151d1afa2eSKejian Yan static int
hns_mac_register_phydev(struct mii_bus * mdio,struct hns_mac_cb * mac_cb,u32 addr)7161d1afa2eSKejian Yan hns_mac_register_phydev(struct mii_bus *mdio, struct hns_mac_cb *mac_cb,
7171d1afa2eSKejian Yan u32 addr)
7181d1afa2eSKejian Yan {
7191d1afa2eSKejian Yan struct phy_device *phy;
7201d1afa2eSKejian Yan const char *phy_type;
7211d1afa2eSKejian Yan bool is_c45;
7221d1afa2eSKejian Yan int rc;
7231d1afa2eSKejian Yan
7241d1afa2eSKejian Yan rc = fwnode_property_read_string(mac_cb->fw_port,
7251d1afa2eSKejian Yan "phy-mode", &phy_type);
7261d1afa2eSKejian Yan if (rc < 0)
7271d1afa2eSKejian Yan return rc;
7281d1afa2eSKejian Yan
7291d1afa2eSKejian Yan if (!strcmp(phy_type, phy_modes(PHY_INTERFACE_MODE_XGMII)))
7306d927977SJason Yan is_c45 = true;
7311d1afa2eSKejian Yan else if (!strcmp(phy_type, phy_modes(PHY_INTERFACE_MODE_SGMII)))
7326d927977SJason Yan is_c45 = false;
7331d1afa2eSKejian Yan else
7341d1afa2eSKejian Yan return -ENODATA;
7351d1afa2eSKejian Yan
7361d1afa2eSKejian Yan phy = get_phy_device(mdio, addr, is_c45);
7371d1afa2eSKejian Yan if (!phy || IS_ERR(phy))
7381d1afa2eSKejian Yan return -EIO;
7391d1afa2eSKejian Yan
7401d1afa2eSKejian Yan phy->irq = mdio->irq[addr];
7411d1afa2eSKejian Yan
7421d1afa2eSKejian Yan /* All data is now stored in the phy struct;
7431d1afa2eSKejian Yan * register it
7441d1afa2eSKejian Yan */
7451d1afa2eSKejian Yan rc = phy_device_register(phy);
7461d1afa2eSKejian Yan if (rc) {
7471d1afa2eSKejian Yan phy_device_free(phy);
748804ffe5cSlipeng dev_err(&mdio->dev, "registered phy fail at address %i\n",
749804ffe5cSlipeng addr);
7501d1afa2eSKejian Yan return -ENODEV;
7511d1afa2eSKejian Yan }
7521d1afa2eSKejian Yan
7531d1afa2eSKejian Yan mac_cb->phy_dev = phy;
7541d1afa2eSKejian Yan
7551d1afa2eSKejian Yan dev_dbg(&mdio->dev, "registered phy at address %i\n", addr);
7561d1afa2eSKejian Yan
7571d1afa2eSKejian Yan return 0;
7581d1afa2eSKejian Yan }
7591d1afa2eSKejian Yan
hns_mac_register_phy(struct hns_mac_cb * mac_cb)760804ffe5cSlipeng static int hns_mac_register_phy(struct hns_mac_cb *mac_cb)
7611d1afa2eSKejian Yan {
762977d5ad3SSakari Ailus struct fwnode_reference_args args;
7631d1afa2eSKejian Yan struct platform_device *pdev;
7641d1afa2eSKejian Yan struct mii_bus *mii_bus;
7651d1afa2eSKejian Yan int rc;
7661d1afa2eSKejian Yan int addr;
7671d1afa2eSKejian Yan
7681d1afa2eSKejian Yan /* Loop over the child nodes and register a phy_device for each one */
7691d1afa2eSKejian Yan if (!to_acpi_device_node(mac_cb->fw_port))
770804ffe5cSlipeng return -ENODEV;
7711d1afa2eSKejian Yan
7721d1afa2eSKejian Yan rc = acpi_node_get_property_reference(
7731d1afa2eSKejian Yan mac_cb->fw_port, "mdio-node", 0, &args);
7741d1afa2eSKejian Yan if (rc)
775804ffe5cSlipeng return rc;
776977d5ad3SSakari Ailus if (!is_acpi_device_node(args.fwnode))
777977d5ad3SSakari Ailus return -EINVAL;
7781d1afa2eSKejian Yan
7791d1afa2eSKejian Yan addr = hns_mac_phy_parse_addr(mac_cb->dev, mac_cb->fw_port);
7801d1afa2eSKejian Yan if (addr < 0)
781804ffe5cSlipeng return addr;
7821d1afa2eSKejian Yan
7831d1afa2eSKejian Yan /* dev address in adev */
784977d5ad3SSakari Ailus pdev = hns_dsaf_find_platform_device(args.fwnode);
785804ffe5cSlipeng if (!pdev) {
786804ffe5cSlipeng dev_err(mac_cb->dev, "mac%d mdio pdev is NULL\n",
787804ffe5cSlipeng mac_cb->mac_id);
788804ffe5cSlipeng return -EINVAL;
789804ffe5cSlipeng }
790804ffe5cSlipeng
7911d1afa2eSKejian Yan mii_bus = platform_get_drvdata(pdev);
792804ffe5cSlipeng if (!mii_bus) {
793804ffe5cSlipeng dev_err(mac_cb->dev,
794804ffe5cSlipeng "mac%d mdio is NULL, dsaf will probe again later\n",
795804ffe5cSlipeng mac_cb->mac_id);
796804ffe5cSlipeng return -EPROBE_DEFER;
797804ffe5cSlipeng }
798804ffe5cSlipeng
7991d1afa2eSKejian Yan rc = hns_mac_register_phydev(mii_bus, mac_cb, addr);
8001d1afa2eSKejian Yan if (!rc)
8011d1afa2eSKejian Yan dev_dbg(mac_cb->dev, "mac%d register phy addr:%d\n",
8021d1afa2eSKejian Yan mac_cb->mac_id, addr);
803804ffe5cSlipeng
804804ffe5cSlipeng return rc;
8051d1afa2eSKejian Yan }
8061d1afa2eSKejian Yan
hns_mac_remove_phydev(struct hns_mac_cb * mac_cb)807308c6cafSYonglong Liu static void hns_mac_remove_phydev(struct hns_mac_cb *mac_cb)
808308c6cafSYonglong Liu {
809308c6cafSYonglong Liu if (!to_acpi_device_node(mac_cb->fw_port) || !mac_cb->phy_dev)
810308c6cafSYonglong Liu return;
811308c6cafSYonglong Liu
812308c6cafSYonglong Liu phy_device_remove(mac_cb->phy_dev);
813308c6cafSYonglong Liu phy_device_free(mac_cb->phy_dev);
814308c6cafSYonglong Liu
815308c6cafSYonglong Liu mac_cb->phy_dev = NULL;
816308c6cafSYonglong Liu }
817308c6cafSYonglong Liu
8185d2525f7SKejian Yan #define MAC_MEDIA_TYPE_MAX_LEN 16
8195d2525f7SKejian Yan
8205d2525f7SKejian Yan static const struct {
8215d2525f7SKejian Yan enum hnae_media_type value;
8225d2525f7SKejian Yan const char *name;
8235d2525f7SKejian Yan } media_type_defs[] = {
8245d2525f7SKejian Yan {HNAE_MEDIA_TYPE_UNKNOWN, "unknown" },
8255d2525f7SKejian Yan {HNAE_MEDIA_TYPE_FIBER, "fiber" },
8265d2525f7SKejian Yan {HNAE_MEDIA_TYPE_COPPER, "copper" },
8275d2525f7SKejian Yan {HNAE_MEDIA_TYPE_BACKPLANE, "backplane" },
8285d2525f7SKejian Yan };
8295d2525f7SKejian Yan
830511e6bc0Shuangdaode /**
831831d828bSYisen.Zhuang\(Zhuangyuzeng\) *hns_mac_get_info - get mac information from device node
832511e6bc0Shuangdaode *@mac_cb: mac device
833831d828bSYisen.Zhuang\(Zhuangyuzeng\) * return: 0 --success, negative --fail
834511e6bc0Shuangdaode */
hns_mac_get_info(struct hns_mac_cb * mac_cb)835831d828bSYisen.Zhuang\(Zhuangyuzeng\) static int hns_mac_get_info(struct hns_mac_cb *mac_cb)
836511e6bc0Shuangdaode {
837652d39b0SKejian Yan struct device_node *np;
838831d828bSYisen.Zhuang\(Zhuangyuzeng\) struct regmap *syscon;
8391ffdfac9SYisen.Zhuang\(Zhuangyuzeng\) struct of_phandle_args cpld_args;
8405d2525f7SKejian Yan const char *media_type;
8415d2525f7SKejian Yan u32 i;
84231d4446dSYisen.Zhuang\(Zhuangyuzeng\) u32 ret;
84331d4446dSYisen.Zhuang\(Zhuangyuzeng\)
844511e6bc0Shuangdaode mac_cb->link = false;
845511e6bc0Shuangdaode mac_cb->half_duplex = false;
8465d2525f7SKejian Yan mac_cb->media_type = HNAE_MEDIA_TYPE_UNKNOWN;
847511e6bc0Shuangdaode mac_cb->speed = mac_phy_to_speed[mac_cb->phy_if];
848511e6bc0Shuangdaode mac_cb->max_speed = mac_cb->speed;
849511e6bc0Shuangdaode
850511e6bc0Shuangdaode if (mac_cb->phy_if == PHY_INTERFACE_MODE_SGMII) {
851511e6bc0Shuangdaode mac_cb->if_support = MAC_GMAC_SUPPORTED;
852511e6bc0Shuangdaode mac_cb->if_support |= SUPPORTED_1000baseT_Full;
853511e6bc0Shuangdaode } else if (mac_cb->phy_if == PHY_INTERFACE_MODE_XGMII) {
854511e6bc0Shuangdaode mac_cb->if_support = SUPPORTED_10000baseR_FEC;
855511e6bc0Shuangdaode mac_cb->if_support |= SUPPORTED_10000baseKR_Full;
856511e6bc0Shuangdaode }
857511e6bc0Shuangdaode
858511e6bc0Shuangdaode mac_cb->max_frm = MAC_DEFAULT_MTU;
859511e6bc0Shuangdaode mac_cb->tx_pause_frm_time = MAC_DEFAULT_PAUSE_TIME;
860850bfa3bSYisen.Zhuang\(Zhuangyuzeng\) mac_cb->port_rst_off = mac_cb->mac_id;
8610d768fc6SYisen.Zhuang\(Zhuangyuzeng\) mac_cb->port_mode_off = 0;
862511e6bc0Shuangdaode
863831d828bSYisen.Zhuang\(Zhuangyuzeng\) /* if the dsaf node doesn't contain a port subnode, get phy-handle
864831d828bSYisen.Zhuang\(Zhuangyuzeng\) * from dsaf node
865831d828bSYisen.Zhuang\(Zhuangyuzeng\) */
866831d828bSYisen.Zhuang\(Zhuangyuzeng\) if (!mac_cb->fw_port) {
867652d39b0SKejian Yan np = of_parse_phandle(mac_cb->dev->of_node, "phy-handle",
868831d828bSYisen.Zhuang\(Zhuangyuzeng\) mac_cb->mac_id);
869652d39b0SKejian Yan mac_cb->phy_dev = of_phy_find_device(np);
870652d39b0SKejian Yan if (mac_cb->phy_dev) {
871652d39b0SKejian Yan /* refcount is held by of_phy_find_device()
872652d39b0SKejian Yan * if the phy_dev is found
873652d39b0SKejian Yan */
874652d39b0SKejian Yan put_device(&mac_cb->phy_dev->mdio.dev);
875652d39b0SKejian Yan
87621c328dcSRob Herring dev_dbg(mac_cb->dev, "mac%d phy_node: %pOFn\n",
87721c328dcSRob Herring mac_cb->mac_id, np);
878652d39b0SKejian Yan }
879b2e45406SPeter Chen of_node_put(np);
880652d39b0SKejian Yan
881831d828bSYisen.Zhuang\(Zhuangyuzeng\) return 0;
882831d828bSYisen.Zhuang\(Zhuangyuzeng\) }
883652d39b0SKejian Yan
8848413b3beSKejian Yan if (is_of_node(mac_cb->fw_port)) {
885831d828bSYisen.Zhuang\(Zhuangyuzeng\) /* parse property from port subnode in dsaf */
8861d1afa2eSKejian Yan np = of_parse_phandle(to_of_node(mac_cb->fw_port),
8871d1afa2eSKejian Yan "phy-handle", 0);
888652d39b0SKejian Yan mac_cb->phy_dev = of_phy_find_device(np);
889652d39b0SKejian Yan if (mac_cb->phy_dev) {
8901d1afa2eSKejian Yan /* refcount is held by of_phy_find_device()
8911d1afa2eSKejian Yan * if the phy_dev is found
8921d1afa2eSKejian Yan */
893652d39b0SKejian Yan put_device(&mac_cb->phy_dev->mdio.dev);
89421c328dcSRob Herring dev_dbg(mac_cb->dev, "mac%d phy_node: %pOFn\n",
89521c328dcSRob Herring mac_cb->mac_id, np);
896652d39b0SKejian Yan }
897b2e45406SPeter Chen of_node_put(np);
898652d39b0SKejian Yan
899b2e45406SPeter Chen np = of_parse_phandle(to_of_node(mac_cb->fw_port),
900b2e45406SPeter Chen "serdes-syscon", 0);
901b2e45406SPeter Chen syscon = syscon_node_to_regmap(np);
902b2e45406SPeter Chen of_node_put(np);
903831d828bSYisen.Zhuang\(Zhuangyuzeng\) if (IS_ERR_OR_NULL(syscon)) {
904831d828bSYisen.Zhuang\(Zhuangyuzeng\) dev_err(mac_cb->dev, "serdes-syscon is needed!\n");
905831d828bSYisen.Zhuang\(Zhuangyuzeng\) return -EINVAL;
906831d828bSYisen.Zhuang\(Zhuangyuzeng\) }
907831d828bSYisen.Zhuang\(Zhuangyuzeng\) mac_cb->serdes_ctrl = syscon;
90831d4446dSYisen.Zhuang\(Zhuangyuzeng\)
909850bfa3bSYisen.Zhuang\(Zhuangyuzeng\) ret = fwnode_property_read_u32(mac_cb->fw_port,
910850bfa3bSYisen.Zhuang\(Zhuangyuzeng\) "port-rst-offset",
911850bfa3bSYisen.Zhuang\(Zhuangyuzeng\) &mac_cb->port_rst_off);
912850bfa3bSYisen.Zhuang\(Zhuangyuzeng\) if (ret) {
913850bfa3bSYisen.Zhuang\(Zhuangyuzeng\) dev_dbg(mac_cb->dev,
914850bfa3bSYisen.Zhuang\(Zhuangyuzeng\) "mac%d port-rst-offset not found, use default value.\n",
915850bfa3bSYisen.Zhuang\(Zhuangyuzeng\) mac_cb->mac_id);
916850bfa3bSYisen.Zhuang\(Zhuangyuzeng\) }
917850bfa3bSYisen.Zhuang\(Zhuangyuzeng\)
9180d768fc6SYisen.Zhuang\(Zhuangyuzeng\) ret = fwnode_property_read_u32(mac_cb->fw_port,
9190d768fc6SYisen.Zhuang\(Zhuangyuzeng\) "port-mode-offset",
9200d768fc6SYisen.Zhuang\(Zhuangyuzeng\) &mac_cb->port_mode_off);
9210d768fc6SYisen.Zhuang\(Zhuangyuzeng\) if (ret) {
9220d768fc6SYisen.Zhuang\(Zhuangyuzeng\) dev_dbg(mac_cb->dev,
9230d768fc6SYisen.Zhuang\(Zhuangyuzeng\) "mac%d port-mode-offset not found, use default value.\n",
9240d768fc6SYisen.Zhuang\(Zhuangyuzeng\) mac_cb->mac_id);
9250d768fc6SYisen.Zhuang\(Zhuangyuzeng\) }
9260d768fc6SYisen.Zhuang\(Zhuangyuzeng\)
9278413b3beSKejian Yan ret = of_parse_phandle_with_fixed_args(
9288413b3beSKejian Yan to_of_node(mac_cb->fw_port), "cpld-syscon", 1, 0,
9298413b3beSKejian Yan &cpld_args);
9301ffdfac9SYisen.Zhuang\(Zhuangyuzeng\) if (ret) {
9311ffdfac9SYisen.Zhuang\(Zhuangyuzeng\) dev_dbg(mac_cb->dev, "mac%d no cpld-syscon found.\n",
9321ffdfac9SYisen.Zhuang\(Zhuangyuzeng\) mac_cb->mac_id);
9331ffdfac9SYisen.Zhuang\(Zhuangyuzeng\) mac_cb->cpld_ctrl = NULL;
9341ffdfac9SYisen.Zhuang\(Zhuangyuzeng\) } else {
9351ffdfac9SYisen.Zhuang\(Zhuangyuzeng\) syscon = syscon_node_to_regmap(cpld_args.np);
936*359a218cSKrzysztof Kozlowski of_node_put(cpld_args.np);
93731d4446dSYisen.Zhuang\(Zhuangyuzeng\) if (IS_ERR_OR_NULL(syscon)) {
93831d4446dSYisen.Zhuang\(Zhuangyuzeng\) dev_dbg(mac_cb->dev, "no cpld-syscon found!\n");
93931d4446dSYisen.Zhuang\(Zhuangyuzeng\) mac_cb->cpld_ctrl = NULL;
94031d4446dSYisen.Zhuang\(Zhuangyuzeng\) } else {
94131d4446dSYisen.Zhuang\(Zhuangyuzeng\) mac_cb->cpld_ctrl = syscon;
9421ffdfac9SYisen.Zhuang\(Zhuangyuzeng\) mac_cb->cpld_ctrl_reg = cpld_args.args[0];
94331d4446dSYisen.Zhuang\(Zhuangyuzeng\) }
94431d4446dSYisen.Zhuang\(Zhuangyuzeng\) }
9451d1afa2eSKejian Yan } else if (is_acpi_node(mac_cb->fw_port)) {
946804ffe5cSlipeng ret = hns_mac_register_phy(mac_cb);
947699e803eSPeng Li /* Mac can work well if there is phy or not.If the port don't
948804ffe5cSlipeng * connect with phy, the return value will be ignored. Only
949804ffe5cSlipeng * when there is phy but can't find mdio bus, the return value
950804ffe5cSlipeng * will be handled.
951804ffe5cSlipeng */
952804ffe5cSlipeng if (ret == -EPROBE_DEFER)
953804ffe5cSlipeng return ret;
9541d1afa2eSKejian Yan } else {
9551d1afa2eSKejian Yan dev_err(mac_cb->dev, "mac%d cannot find phy node\n",
9561d1afa2eSKejian Yan mac_cb->mac_id);
9578413b3beSKejian Yan }
9581ffdfac9SYisen.Zhuang\(Zhuangyuzeng\)
9595d2525f7SKejian Yan if (!fwnode_property_read_string(mac_cb->fw_port, "media-type",
9605d2525f7SKejian Yan &media_type)) {
9615d2525f7SKejian Yan for (i = 0; i < ARRAY_SIZE(media_type_defs); i++) {
9625d2525f7SKejian Yan if (!strncmp(media_type_defs[i].name, media_type,
9635d2525f7SKejian Yan MAC_MEDIA_TYPE_MAX_LEN)) {
9645d2525f7SKejian Yan mac_cb->media_type = media_type_defs[i].value;
9655d2525f7SKejian Yan break;
9665d2525f7SKejian Yan }
9675d2525f7SKejian Yan }
9685d2525f7SKejian Yan }
9695d2525f7SKejian Yan
970153b1d48SKejian Yan if (fwnode_property_read_u8_array(mac_cb->fw_port, "mc-mac-mask",
971153b1d48SKejian Yan mac_cb->mc_mask, ETH_ALEN)) {
972153b1d48SKejian Yan dev_warn(mac_cb->dev,
973153b1d48SKejian Yan "no mc-mac-mask property, set to default value.\n");
974153b1d48SKejian Yan eth_broadcast_addr(mac_cb->mc_mask);
975153b1d48SKejian Yan }
976153b1d48SKejian Yan
977831d828bSYisen.Zhuang\(Zhuangyuzeng\) return 0;
978511e6bc0Shuangdaode }
979511e6bc0Shuangdaode
980511e6bc0Shuangdaode /**
981511e6bc0Shuangdaode * hns_mac_get_mode - get mac mode
982511e6bc0Shuangdaode * @phy_if: phy interface
983d0ea5cbdSJesse Brandeburg * return 0 - gmac, 1 - xgmac , negative --fail
984511e6bc0Shuangdaode */
hns_mac_get_mode(phy_interface_t phy_if)985511e6bc0Shuangdaode static int hns_mac_get_mode(phy_interface_t phy_if)
986511e6bc0Shuangdaode {
987511e6bc0Shuangdaode switch (phy_if) {
988511e6bc0Shuangdaode case PHY_INTERFACE_MODE_SGMII:
989511e6bc0Shuangdaode return MAC_GMAC_IDX;
990511e6bc0Shuangdaode case PHY_INTERFACE_MODE_XGMII:
991511e6bc0Shuangdaode return MAC_XGMAC_IDX;
992511e6bc0Shuangdaode default:
993511e6bc0Shuangdaode return -EINVAL;
994511e6bc0Shuangdaode }
995511e6bc0Shuangdaode }
996511e6bc0Shuangdaode
997336a443bSYueHaibing static u8 __iomem *
hns_mac_get_vaddr(struct dsaf_device * dsaf_dev,struct hns_mac_cb * mac_cb,u32 mac_mode_idx)998336a443bSYueHaibing hns_mac_get_vaddr(struct dsaf_device *dsaf_dev,
999511e6bc0Shuangdaode struct hns_mac_cb *mac_cb, u32 mac_mode_idx)
1000511e6bc0Shuangdaode {
1001511e6bc0Shuangdaode u8 __iomem *base = dsaf_dev->io_base;
1002511e6bc0Shuangdaode int mac_id = mac_cb->mac_id;
1003511e6bc0Shuangdaode
1004511e6bc0Shuangdaode if (mac_cb->mac_type == HNAE_PORT_SERVICE)
1005511e6bc0Shuangdaode return base + 0x40000 + mac_id * 0x4000 -
1006511e6bc0Shuangdaode mac_mode_idx * 0x20000;
1007511e6bc0Shuangdaode else
1008831d828bSYisen.Zhuang\(Zhuangyuzeng\) return dsaf_dev->ppe_base + 0x1000;
1009511e6bc0Shuangdaode }
1010511e6bc0Shuangdaode
1011511e6bc0Shuangdaode /**
1012511e6bc0Shuangdaode * hns_mac_get_cfg - get mac cfg from dtb or acpi table
1013511e6bc0Shuangdaode * @dsaf_dev: dsa fabric device struct pointer
1014831d828bSYisen.Zhuang\(Zhuangyuzeng\) * @mac_cb: mac control block
1015831d828bSYisen.Zhuang\(Zhuangyuzeng\) * return 0 - success , negative --fail
1016511e6bc0Shuangdaode */
1017336a443bSYueHaibing static int
hns_mac_get_cfg(struct dsaf_device * dsaf_dev,struct hns_mac_cb * mac_cb)1018336a443bSYueHaibing hns_mac_get_cfg(struct dsaf_device *dsaf_dev, struct hns_mac_cb *mac_cb)
1019511e6bc0Shuangdaode {
1020511e6bc0Shuangdaode int ret;
1021511e6bc0Shuangdaode u32 mac_mode_idx;
1022511e6bc0Shuangdaode
1023511e6bc0Shuangdaode mac_cb->dsaf_dev = dsaf_dev;
1024511e6bc0Shuangdaode mac_cb->dev = dsaf_dev->dev;
1025511e6bc0Shuangdaode
1026511e6bc0Shuangdaode mac_cb->sys_ctl_vaddr = dsaf_dev->sc_base;
1027511e6bc0Shuangdaode mac_cb->serdes_vaddr = dsaf_dev->sds_base;
1028511e6bc0Shuangdaode
1029511e6bc0Shuangdaode mac_cb->sfp_prsnt = 0;
1030511e6bc0Shuangdaode mac_cb->txpkt_for_led = 0;
1031511e6bc0Shuangdaode mac_cb->rxpkt_for_led = 0;
1032511e6bc0Shuangdaode
1033831d828bSYisen.Zhuang\(Zhuangyuzeng\) if (!HNS_DSAF_IS_DEBUG(dsaf_dev))
1034511e6bc0Shuangdaode mac_cb->mac_type = HNAE_PORT_SERVICE;
1035511e6bc0Shuangdaode else
1036511e6bc0Shuangdaode mac_cb->mac_type = HNAE_PORT_DEBUG;
1037511e6bc0Shuangdaode
1038a24274aaSKejian Yan mac_cb->phy_if = dsaf_dev->misc_op->get_phy_if(mac_cb);
1039511e6bc0Shuangdaode
1040511e6bc0Shuangdaode ret = hns_mac_get_mode(mac_cb->phy_if);
1041511e6bc0Shuangdaode if (ret < 0) {
1042511e6bc0Shuangdaode dev_err(dsaf_dev->dev,
1043511e6bc0Shuangdaode "hns_mac_get_mode failed, mac%d ret = %#x!\n",
1044511e6bc0Shuangdaode mac_cb->mac_id, ret);
1045511e6bc0Shuangdaode return ret;
1046511e6bc0Shuangdaode }
1047511e6bc0Shuangdaode mac_mode_idx = (u32)ret;
1048511e6bc0Shuangdaode
1049831d828bSYisen.Zhuang\(Zhuangyuzeng\) ret = hns_mac_get_info(mac_cb);
1050831d828bSYisen.Zhuang\(Zhuangyuzeng\) if (ret)
1051831d828bSYisen.Zhuang\(Zhuangyuzeng\) return ret;
1052511e6bc0Shuangdaode
1053a24274aaSKejian Yan mac_cb->dsaf_dev->misc_op->cpld_reset_led(mac_cb);
1054511e6bc0Shuangdaode mac_cb->vaddr = hns_mac_get_vaddr(dsaf_dev, mac_cb, mac_mode_idx);
1055511e6bc0Shuangdaode
1056511e6bc0Shuangdaode return 0;
1057511e6bc0Shuangdaode }
1058511e6bc0Shuangdaode
hns_mac_get_max_port_num(struct dsaf_device * dsaf_dev)1059831d828bSYisen.Zhuang\(Zhuangyuzeng\) static int hns_mac_get_max_port_num(struct dsaf_device *dsaf_dev)
1060831d828bSYisen.Zhuang\(Zhuangyuzeng\) {
1061831d828bSYisen.Zhuang\(Zhuangyuzeng\) if (HNS_DSAF_IS_DEBUG(dsaf_dev))
1062831d828bSYisen.Zhuang\(Zhuangyuzeng\) return 1;
1063831d828bSYisen.Zhuang\(Zhuangyuzeng\) else
1064831d828bSYisen.Zhuang\(Zhuangyuzeng\) return DSAF_MAX_PORT_NUM;
1065831d828bSYisen.Zhuang\(Zhuangyuzeng\) }
1066831d828bSYisen.Zhuang\(Zhuangyuzeng\)
hns_mac_enable(struct hns_mac_cb * mac_cb,enum mac_commom_mode mode)106731fabbeeSPeng Li void hns_mac_enable(struct hns_mac_cb *mac_cb, enum mac_commom_mode mode)
106831fabbeeSPeng Li {
106931fabbeeSPeng Li struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
107031fabbeeSPeng Li
107131fabbeeSPeng Li mac_ctrl_drv->mac_enable(mac_cb->priv.mac, mode);
107231fabbeeSPeng Li }
107331fabbeeSPeng Li
hns_mac_disable(struct hns_mac_cb * mac_cb,enum mac_commom_mode mode)107431fabbeeSPeng Li void hns_mac_disable(struct hns_mac_cb *mac_cb, enum mac_commom_mode mode)
107531fabbeeSPeng Li {
107631fabbeeSPeng Li struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
107731fabbeeSPeng Li
107831fabbeeSPeng Li mac_ctrl_drv->mac_disable(mac_cb->priv.mac, mode);
107931fabbeeSPeng Li }
108031fabbeeSPeng Li
1081511e6bc0Shuangdaode /**
1082511e6bc0Shuangdaode * hns_mac_init - init mac
1083511e6bc0Shuangdaode * @dsaf_dev: dsa fabric device struct pointer
1084831d828bSYisen.Zhuang\(Zhuangyuzeng\) * return 0 - success , negative --fail
1085511e6bc0Shuangdaode */
hns_mac_init(struct dsaf_device * dsaf_dev)1086511e6bc0Shuangdaode int hns_mac_init(struct dsaf_device *dsaf_dev)
1087511e6bc0Shuangdaode {
1088831d828bSYisen.Zhuang\(Zhuangyuzeng\) bool found = false;
1089511e6bc0Shuangdaode int ret;
1090831d828bSYisen.Zhuang\(Zhuangyuzeng\) u32 port_id;
1091831d828bSYisen.Zhuang\(Zhuangyuzeng\) int max_port_num = hns_mac_get_max_port_num(dsaf_dev);
1092511e6bc0Shuangdaode struct hns_mac_cb *mac_cb;
1093831d828bSYisen.Zhuang\(Zhuangyuzeng\) struct fwnode_handle *child;
1094511e6bc0Shuangdaode
1095831d828bSYisen.Zhuang\(Zhuangyuzeng\) device_for_each_child_node(dsaf_dev->dev, child) {
10960211b8fbSYisen.Zhuang\(Zhuangyuzeng\) ret = fwnode_property_read_u32(child, "reg", &port_id);
1097831d828bSYisen.Zhuang\(Zhuangyuzeng\) if (ret) {
1098e85f8a9fSPeng Wu fwnode_handle_put(child);
1099831d828bSYisen.Zhuang\(Zhuangyuzeng\) dev_err(dsaf_dev->dev,
11000211b8fbSYisen.Zhuang\(Zhuangyuzeng\) "get reg fail, ret=%d!\n", ret);
1101831d828bSYisen.Zhuang\(Zhuangyuzeng\) return ret;
1102831d828bSYisen.Zhuang\(Zhuangyuzeng\) }
1103831d828bSYisen.Zhuang\(Zhuangyuzeng\) if (port_id >= max_port_num) {
1104e85f8a9fSPeng Wu fwnode_handle_put(child);
1105831d828bSYisen.Zhuang\(Zhuangyuzeng\) dev_err(dsaf_dev->dev,
11060211b8fbSYisen.Zhuang\(Zhuangyuzeng\) "reg(%u) out of range!\n", port_id);
1107831d828bSYisen.Zhuang\(Zhuangyuzeng\) return -EINVAL;
1108831d828bSYisen.Zhuang\(Zhuangyuzeng\) }
1109831d828bSYisen.Zhuang\(Zhuangyuzeng\) mac_cb = devm_kzalloc(dsaf_dev->dev, sizeof(*mac_cb),
1110831d828bSYisen.Zhuang\(Zhuangyuzeng\) GFP_KERNEL);
1111e85f8a9fSPeng Wu if (!mac_cb) {
1112e85f8a9fSPeng Wu fwnode_handle_put(child);
1113831d828bSYisen.Zhuang\(Zhuangyuzeng\) return -ENOMEM;
1114e85f8a9fSPeng Wu }
1115831d828bSYisen.Zhuang\(Zhuangyuzeng\) mac_cb->fw_port = child;
1116831d828bSYisen.Zhuang\(Zhuangyuzeng\) mac_cb->mac_id = (u8)port_id;
1117831d828bSYisen.Zhuang\(Zhuangyuzeng\) dsaf_dev->mac_cb[port_id] = mac_cb;
1118831d828bSYisen.Zhuang\(Zhuangyuzeng\) found = true;
1119831d828bSYisen.Zhuang\(Zhuangyuzeng\) }
1120831d828bSYisen.Zhuang\(Zhuangyuzeng\)
1121831d828bSYisen.Zhuang\(Zhuangyuzeng\) /* if don't get any port subnode from dsaf node
1122831d828bSYisen.Zhuang\(Zhuangyuzeng\) * will init all port then, this is compatible with the old dts
1123831d828bSYisen.Zhuang\(Zhuangyuzeng\) */
1124831d828bSYisen.Zhuang\(Zhuangyuzeng\) if (!found) {
1125831d828bSYisen.Zhuang\(Zhuangyuzeng\) for (port_id = 0; port_id < max_port_num; port_id++) {
1126831d828bSYisen.Zhuang\(Zhuangyuzeng\) mac_cb = devm_kzalloc(dsaf_dev->dev, sizeof(*mac_cb),
1127831d828bSYisen.Zhuang\(Zhuangyuzeng\) GFP_KERNEL);
1128831d828bSYisen.Zhuang\(Zhuangyuzeng\) if (!mac_cb)
1129511e6bc0Shuangdaode return -ENOMEM;
1130511e6bc0Shuangdaode
1131831d828bSYisen.Zhuang\(Zhuangyuzeng\) mac_cb->mac_id = port_id;
1132831d828bSYisen.Zhuang\(Zhuangyuzeng\) dsaf_dev->mac_cb[port_id] = mac_cb;
1133831d828bSYisen.Zhuang\(Zhuangyuzeng\) }
1134831d828bSYisen.Zhuang\(Zhuangyuzeng\) }
1135804ffe5cSlipeng
1136831d828bSYisen.Zhuang\(Zhuangyuzeng\) /* init mac_cb for all port */
1137831d828bSYisen.Zhuang\(Zhuangyuzeng\) for (port_id = 0; port_id < max_port_num; port_id++) {
1138831d828bSYisen.Zhuang\(Zhuangyuzeng\) mac_cb = dsaf_dev->mac_cb[port_id];
1139831d828bSYisen.Zhuang\(Zhuangyuzeng\) if (!mac_cb)
1140831d828bSYisen.Zhuang\(Zhuangyuzeng\) continue;
1141511e6bc0Shuangdaode
1142831d828bSYisen.Zhuang\(Zhuangyuzeng\) ret = hns_mac_get_cfg(dsaf_dev, mac_cb);
1143831d828bSYisen.Zhuang\(Zhuangyuzeng\) if (ret)
1144831d828bSYisen.Zhuang\(Zhuangyuzeng\) return ret;
1145804ffe5cSlipeng
1146511e6bc0Shuangdaode ret = hns_mac_init_ex(mac_cb);
1147511e6bc0Shuangdaode if (ret)
1148831d828bSYisen.Zhuang\(Zhuangyuzeng\) return ret;
1149511e6bc0Shuangdaode }
1150511e6bc0Shuangdaode
1151511e6bc0Shuangdaode return 0;
1152511e6bc0Shuangdaode }
1153511e6bc0Shuangdaode
hns_mac_uninit(struct dsaf_device * dsaf_dev)1154511e6bc0Shuangdaode void hns_mac_uninit(struct dsaf_device *dsaf_dev)
1155511e6bc0Shuangdaode {
1156831d828bSYisen.Zhuang\(Zhuangyuzeng\) int i;
1157831d828bSYisen.Zhuang\(Zhuangyuzeng\) int max_port_num = hns_mac_get_max_port_num(dsaf_dev);
1158831d828bSYisen.Zhuang\(Zhuangyuzeng\)
1159831d828bSYisen.Zhuang\(Zhuangyuzeng\) for (i = 0; i < max_port_num; i++) {
1160308c6cafSYonglong Liu if (!dsaf_dev->mac_cb[i])
1161308c6cafSYonglong Liu continue;
1162308c6cafSYonglong Liu
1163a24274aaSKejian Yan dsaf_dev->misc_op->cpld_reset_led(dsaf_dev->mac_cb[i]);
1164308c6cafSYonglong Liu hns_mac_remove_phydev(dsaf_dev->mac_cb[i]);
1165831d828bSYisen.Zhuang\(Zhuangyuzeng\) dsaf_dev->mac_cb[i] = NULL;
1166831d828bSYisen.Zhuang\(Zhuangyuzeng\) }
1167511e6bc0Shuangdaode }
1168511e6bc0Shuangdaode
hns_mac_config_mac_loopback(struct hns_mac_cb * mac_cb,enum hnae_loop loop,int en)1169511e6bc0Shuangdaode int hns_mac_config_mac_loopback(struct hns_mac_cb *mac_cb,
1170511e6bc0Shuangdaode enum hnae_loop loop, int en)
1171511e6bc0Shuangdaode {
1172511e6bc0Shuangdaode int ret;
1173511e6bc0Shuangdaode struct mac_driver *drv = hns_mac_get_drv(mac_cb);
1174511e6bc0Shuangdaode
1175511e6bc0Shuangdaode if (drv->config_loopback)
1176511e6bc0Shuangdaode ret = drv->config_loopback(drv, loop, en);
1177511e6bc0Shuangdaode else
1178511e6bc0Shuangdaode ret = -ENOTSUPP;
1179511e6bc0Shuangdaode
1180511e6bc0Shuangdaode return ret;
1181511e6bc0Shuangdaode }
1182511e6bc0Shuangdaode
hns_mac_update_stats(struct hns_mac_cb * mac_cb)1183511e6bc0Shuangdaode void hns_mac_update_stats(struct hns_mac_cb *mac_cb)
1184511e6bc0Shuangdaode {
1185511e6bc0Shuangdaode struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
1186511e6bc0Shuangdaode
1187511e6bc0Shuangdaode mac_ctrl_drv->update_stats(mac_ctrl_drv);
1188511e6bc0Shuangdaode }
1189511e6bc0Shuangdaode
hns_mac_get_stats(struct hns_mac_cb * mac_cb,u64 * data)1190511e6bc0Shuangdaode void hns_mac_get_stats(struct hns_mac_cb *mac_cb, u64 *data)
1191511e6bc0Shuangdaode {
1192511e6bc0Shuangdaode struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
1193511e6bc0Shuangdaode
1194511e6bc0Shuangdaode mac_ctrl_drv->get_ethtool_stats(mac_ctrl_drv, data);
1195511e6bc0Shuangdaode }
1196511e6bc0Shuangdaode
hns_mac_get_strings(struct hns_mac_cb * mac_cb,int stringset,u8 * data)1197511e6bc0Shuangdaode void hns_mac_get_strings(struct hns_mac_cb *mac_cb,
1198511e6bc0Shuangdaode int stringset, u8 *data)
1199511e6bc0Shuangdaode {
1200511e6bc0Shuangdaode struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
1201511e6bc0Shuangdaode
1202511e6bc0Shuangdaode mac_ctrl_drv->get_strings(stringset, data);
1203511e6bc0Shuangdaode }
1204511e6bc0Shuangdaode
hns_mac_get_sset_count(struct hns_mac_cb * mac_cb,int stringset)1205511e6bc0Shuangdaode int hns_mac_get_sset_count(struct hns_mac_cb *mac_cb, int stringset)
1206511e6bc0Shuangdaode {
1207511e6bc0Shuangdaode struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
1208511e6bc0Shuangdaode
1209511e6bc0Shuangdaode return mac_ctrl_drv->get_sset_count(stringset);
1210511e6bc0Shuangdaode }
1211511e6bc0Shuangdaode
hns_mac_set_promisc(struct hns_mac_cb * mac_cb,u8 en)1212d5679849SKejian Yan void hns_mac_set_promisc(struct hns_mac_cb *mac_cb, u8 en)
1213d5679849SKejian Yan {
1214d5679849SKejian Yan struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
1215d5679849SKejian Yan
12161f5fa2ddSKejian Yan hns_dsaf_set_promisc_tcam(mac_cb->dsaf_dev, mac_cb->mac_id, !!en);
12171f5fa2ddSKejian Yan
1218d5679849SKejian Yan if (mac_ctrl_drv->set_promiscuous)
1219d5679849SKejian Yan mac_ctrl_drv->set_promiscuous(mac_ctrl_drv, en);
1220d5679849SKejian Yan }
1221d5679849SKejian Yan
hns_mac_get_regs_count(struct hns_mac_cb * mac_cb)1222511e6bc0Shuangdaode int hns_mac_get_regs_count(struct hns_mac_cb *mac_cb)
1223511e6bc0Shuangdaode {
1224511e6bc0Shuangdaode struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
1225511e6bc0Shuangdaode
1226511e6bc0Shuangdaode return mac_ctrl_drv->get_regs_count();
1227511e6bc0Shuangdaode }
1228511e6bc0Shuangdaode
hns_mac_get_regs(struct hns_mac_cb * mac_cb,void * data)1229511e6bc0Shuangdaode void hns_mac_get_regs(struct hns_mac_cb *mac_cb, void *data)
1230511e6bc0Shuangdaode {
1231511e6bc0Shuangdaode struct mac_driver *mac_ctrl_drv = hns_mac_get_drv(mac_cb);
1232511e6bc0Shuangdaode
1233511e6bc0Shuangdaode mac_ctrl_drv->get_regs(mac_ctrl_drv, data);
1234511e6bc0Shuangdaode }
1235511e6bc0Shuangdaode
hns_set_led_opt(struct hns_mac_cb * mac_cb)1236511e6bc0Shuangdaode void hns_set_led_opt(struct hns_mac_cb *mac_cb)
1237511e6bc0Shuangdaode {
12387f8bcd91SYonglong Liu int nic_data;
1239511e6bc0Shuangdaode int txpkts, rxpkts;
1240511e6bc0Shuangdaode
1241511e6bc0Shuangdaode txpkts = mac_cb->txpkt_for_led - mac_cb->hw_stats.tx_good_pkts;
1242511e6bc0Shuangdaode rxpkts = mac_cb->rxpkt_for_led - mac_cb->hw_stats.rx_good_pkts;
1243511e6bc0Shuangdaode if (txpkts || rxpkts)
1244511e6bc0Shuangdaode nic_data = 1;
1245511e6bc0Shuangdaode else
1246511e6bc0Shuangdaode nic_data = 0;
1247511e6bc0Shuangdaode mac_cb->txpkt_for_led = mac_cb->hw_stats.tx_good_pkts;
1248511e6bc0Shuangdaode mac_cb->rxpkt_for_led = mac_cb->hw_stats.rx_good_pkts;
1249a24274aaSKejian Yan mac_cb->dsaf_dev->misc_op->cpld_set_led(mac_cb, (int)mac_cb->link,
1250511e6bc0Shuangdaode mac_cb->speed, nic_data);
1251511e6bc0Shuangdaode }
1252511e6bc0Shuangdaode
hns_cpld_led_set_id(struct hns_mac_cb * mac_cb,enum hnae_led_state status)1253511e6bc0Shuangdaode int hns_cpld_led_set_id(struct hns_mac_cb *mac_cb,
1254511e6bc0Shuangdaode enum hnae_led_state status)
1255511e6bc0Shuangdaode {
12563abbccccSJian Shen if (!mac_cb)
1257511e6bc0Shuangdaode return 0;
1258511e6bc0Shuangdaode
1259a24274aaSKejian Yan return mac_cb->dsaf_dev->misc_op->cpld_set_led_id(mac_cb, status);
1260511e6bc0Shuangdaode }
1261