.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2015 Cavium, Inc. |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or modify it |
---|
5 | | - * under the terms of version 2 of the GNU General Public License |
---|
6 | | - * as published by the Free Software Foundation. |
---|
7 | 4 | */ |
---|
8 | 5 | |
---|
9 | 6 | #include <linux/module.h> |
---|
.. | .. |
---|
57 | 54 | #define NIC_GET_BGX_FROM_VF_LMAC_MAP(map) ((map >> 4) & 0xF) |
---|
58 | 55 | #define NIC_GET_LMAC_FROM_VF_LMAC_MAP(map) (map & 0xF) |
---|
59 | 56 | u8 *vf_lmac_map; |
---|
60 | | - struct delayed_work dwork; |
---|
61 | | - struct workqueue_struct *check_link; |
---|
62 | | - u8 *link; |
---|
63 | | - u8 *duplex; |
---|
64 | | - u32 *speed; |
---|
65 | 57 | u16 cpi_base[MAX_NUM_VFS_SUPPORTED]; |
---|
66 | 58 | u16 rssi_base[MAX_NUM_VFS_SUPPORTED]; |
---|
67 | | - bool mbx_lock[MAX_NUM_VFS_SUPPORTED]; |
---|
68 | 59 | |
---|
69 | 60 | /* MSI-X */ |
---|
70 | 61 | u8 num_vec; |
---|
.. | .. |
---|
929 | 920 | nic_reg_write(nic, NIC_PF_PKIND_0_15_CFG | (pkind_idx << 3), pkind_val); |
---|
930 | 921 | } |
---|
931 | 922 | |
---|
| 923 | +/* Get BGX LMAC link status and update corresponding VF |
---|
| 924 | + * if there is a change, valid only if internal L2 switch |
---|
| 925 | + * is not present otherwise VF link is always treated as up |
---|
| 926 | + */ |
---|
| 927 | +static void nic_link_status_get(struct nicpf *nic, u8 vf) |
---|
| 928 | +{ |
---|
| 929 | + union nic_mbx mbx = {}; |
---|
| 930 | + struct bgx_link_status link; |
---|
| 931 | + u8 bgx, lmac; |
---|
| 932 | + |
---|
| 933 | + mbx.link_status.msg = NIC_MBOX_MSG_BGX_LINK_CHANGE; |
---|
| 934 | + |
---|
| 935 | + /* Get BGX, LMAC indices for the VF */ |
---|
| 936 | + bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); |
---|
| 937 | + lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); |
---|
| 938 | + |
---|
| 939 | + /* Get interface link status */ |
---|
| 940 | + bgx_get_lmac_link_state(nic->node, bgx, lmac, &link); |
---|
| 941 | + |
---|
| 942 | + /* Send a mbox message to VF with current link status */ |
---|
| 943 | + mbx.link_status.link_up = link.link_up; |
---|
| 944 | + mbx.link_status.duplex = link.duplex; |
---|
| 945 | + mbx.link_status.speed = link.speed; |
---|
| 946 | + mbx.link_status.mac_type = link.mac_type; |
---|
| 947 | + |
---|
| 948 | + /* reply with link status */ |
---|
| 949 | + nic_send_msg_to_vf(nic, vf, &mbx); |
---|
| 950 | +} |
---|
| 951 | + |
---|
932 | 952 | /* Interrupt handler to handle mailbox messages from VFs */ |
---|
933 | 953 | static void nic_handle_mbx_intr(struct nicpf *nic, int vf) |
---|
934 | 954 | { |
---|
.. | .. |
---|
940 | 960 | int bgx, lmac; |
---|
941 | 961 | int i; |
---|
942 | 962 | int ret = 0; |
---|
943 | | - |
---|
944 | | - nic->mbx_lock[vf] = true; |
---|
945 | 963 | |
---|
946 | 964 | mbx_addr = nic_get_mbx_addr(vf); |
---|
947 | 965 | mbx_data = (u64 *)&mbx; |
---|
.. | .. |
---|
957 | 975 | switch (mbx.msg.msg) { |
---|
958 | 976 | case NIC_MBOX_MSG_READY: |
---|
959 | 977 | nic_mbx_send_ready(nic, vf); |
---|
960 | | - if (vf < nic->num_vf_en) { |
---|
961 | | - nic->link[vf] = 0; |
---|
962 | | - nic->duplex[vf] = 0; |
---|
963 | | - nic->speed[vf] = 0; |
---|
964 | | - } |
---|
965 | | - goto unlock; |
---|
| 978 | + return; |
---|
966 | 979 | case NIC_MBOX_MSG_QS_CFG: |
---|
967 | 980 | reg_addr = NIC_PF_QSET_0_127_CFG | |
---|
968 | 981 | (mbx.qs.num << NIC_QS_ID_SHIFT); |
---|
.. | .. |
---|
1031 | 1044 | break; |
---|
1032 | 1045 | case NIC_MBOX_MSG_RSS_SIZE: |
---|
1033 | 1046 | nic_send_rss_size(nic, vf); |
---|
1034 | | - goto unlock; |
---|
| 1047 | + return; |
---|
1035 | 1048 | case NIC_MBOX_MSG_RSS_CFG: |
---|
1036 | 1049 | case NIC_MBOX_MSG_RSS_CFG_CONT: |
---|
1037 | 1050 | nic_config_rss(nic, &mbx.rss_cfg); |
---|
.. | .. |
---|
1049 | 1062 | break; |
---|
1050 | 1063 | case NIC_MBOX_MSG_ALLOC_SQS: |
---|
1051 | 1064 | nic_alloc_sqs(nic, &mbx.sqs_alloc); |
---|
1052 | | - goto unlock; |
---|
| 1065 | + return; |
---|
1053 | 1066 | case NIC_MBOX_MSG_NICVF_PTR: |
---|
1054 | 1067 | nic->nicvf[vf] = mbx.nicvf.nicvf; |
---|
1055 | 1068 | break; |
---|
1056 | 1069 | case NIC_MBOX_MSG_PNICVF_PTR: |
---|
1057 | 1070 | nic_send_pnicvf(nic, vf); |
---|
1058 | | - goto unlock; |
---|
| 1071 | + return; |
---|
1059 | 1072 | case NIC_MBOX_MSG_SNICVF_PTR: |
---|
1060 | 1073 | nic_send_snicvf(nic, &mbx.nicvf); |
---|
1061 | | - goto unlock; |
---|
| 1074 | + return; |
---|
1062 | 1075 | case NIC_MBOX_MSG_BGX_STATS: |
---|
1063 | 1076 | nic_get_bgx_stats(nic, &mbx.bgx_stats); |
---|
1064 | | - goto unlock; |
---|
| 1077 | + return; |
---|
1065 | 1078 | case NIC_MBOX_MSG_LOOPBACK: |
---|
1066 | 1079 | ret = nic_config_loopback(nic, &mbx.lbk); |
---|
1067 | 1080 | break; |
---|
.. | .. |
---|
1070 | 1083 | break; |
---|
1071 | 1084 | case NIC_MBOX_MSG_PFC: |
---|
1072 | 1085 | nic_pause_frame(nic, vf, &mbx.pfc); |
---|
1073 | | - goto unlock; |
---|
| 1086 | + return; |
---|
1074 | 1087 | case NIC_MBOX_MSG_PTP_CFG: |
---|
1075 | 1088 | nic_config_timestamp(nic, vf, &mbx.ptp); |
---|
1076 | 1089 | break; |
---|
.. | .. |
---|
1094 | 1107 | bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); |
---|
1095 | 1108 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); |
---|
1096 | 1109 | bgx_set_dmac_cam_filter(nic->node, bgx, lmac, |
---|
1097 | | - mbx.xcast.data.mac, |
---|
| 1110 | + mbx.xcast.mac, |
---|
1098 | 1111 | vf < NIC_VF_PER_MBX_REG ? vf : |
---|
1099 | 1112 | vf - NIC_VF_PER_MBX_REG); |
---|
1100 | 1113 | break; |
---|
.. | .. |
---|
1106 | 1119 | } |
---|
1107 | 1120 | bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); |
---|
1108 | 1121 | lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); |
---|
1109 | | - bgx_set_xcast_mode(nic->node, bgx, lmac, mbx.xcast.data.mode); |
---|
| 1122 | + bgx_set_xcast_mode(nic->node, bgx, lmac, mbx.xcast.mode); |
---|
1110 | 1123 | break; |
---|
| 1124 | + case NIC_MBOX_MSG_BGX_LINK_CHANGE: |
---|
| 1125 | + if (vf >= nic->num_vf_en) { |
---|
| 1126 | + ret = -1; /* NACK */ |
---|
| 1127 | + break; |
---|
| 1128 | + } |
---|
| 1129 | + nic_link_status_get(nic, vf); |
---|
| 1130 | + return; |
---|
1111 | 1131 | default: |
---|
1112 | 1132 | dev_err(&nic->pdev->dev, |
---|
1113 | 1133 | "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg); |
---|
.. | .. |
---|
1121 | 1141 | mbx.msg.msg, vf); |
---|
1122 | 1142 | nic_mbx_send_nack(nic, vf); |
---|
1123 | 1143 | } |
---|
1124 | | -unlock: |
---|
1125 | | - nic->mbx_lock[vf] = false; |
---|
1126 | 1144 | } |
---|
1127 | 1145 | |
---|
1128 | 1146 | static irqreturn_t nic_mbx_intr_handler(int irq, void *nic_irq) |
---|
.. | .. |
---|
1270 | 1288 | return 0; |
---|
1271 | 1289 | } |
---|
1272 | 1290 | |
---|
1273 | | -/* Poll for BGX LMAC link status and update corresponding VF |
---|
1274 | | - * if there is a change, valid only if internal L2 switch |
---|
1275 | | - * is not present otherwise VF link is always treated as up |
---|
1276 | | - */ |
---|
1277 | | -static void nic_poll_for_link(struct work_struct *work) |
---|
1278 | | -{ |
---|
1279 | | - union nic_mbx mbx = {}; |
---|
1280 | | - struct nicpf *nic; |
---|
1281 | | - struct bgx_link_status link; |
---|
1282 | | - u8 vf, bgx, lmac; |
---|
1283 | | - |
---|
1284 | | - nic = container_of(work, struct nicpf, dwork.work); |
---|
1285 | | - |
---|
1286 | | - mbx.link_status.msg = NIC_MBOX_MSG_BGX_LINK_CHANGE; |
---|
1287 | | - |
---|
1288 | | - for (vf = 0; vf < nic->num_vf_en; vf++) { |
---|
1289 | | - /* Poll only if VF is UP */ |
---|
1290 | | - if (!nic->vf_enabled[vf]) |
---|
1291 | | - continue; |
---|
1292 | | - |
---|
1293 | | - /* Get BGX, LMAC indices for the VF */ |
---|
1294 | | - bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); |
---|
1295 | | - lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); |
---|
1296 | | - /* Get interface link status */ |
---|
1297 | | - bgx_get_lmac_link_state(nic->node, bgx, lmac, &link); |
---|
1298 | | - |
---|
1299 | | - /* Inform VF only if link status changed */ |
---|
1300 | | - if (nic->link[vf] == link.link_up) |
---|
1301 | | - continue; |
---|
1302 | | - |
---|
1303 | | - if (!nic->mbx_lock[vf]) { |
---|
1304 | | - nic->link[vf] = link.link_up; |
---|
1305 | | - nic->duplex[vf] = link.duplex; |
---|
1306 | | - nic->speed[vf] = link.speed; |
---|
1307 | | - |
---|
1308 | | - /* Send a mbox message to VF with current link status */ |
---|
1309 | | - mbx.link_status.link_up = link.link_up; |
---|
1310 | | - mbx.link_status.duplex = link.duplex; |
---|
1311 | | - mbx.link_status.speed = link.speed; |
---|
1312 | | - mbx.link_status.mac_type = link.mac_type; |
---|
1313 | | - nic_send_msg_to_vf(nic, vf, &mbx); |
---|
1314 | | - } |
---|
1315 | | - } |
---|
1316 | | - queue_delayed_work(nic->check_link, &nic->dwork, HZ * 2); |
---|
1317 | | -} |
---|
1318 | | - |
---|
1319 | 1291 | static int nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
---|
1320 | 1292 | { |
---|
1321 | 1293 | struct device *dev = &pdev->dev; |
---|
.. | .. |
---|
1384 | 1356 | if (!nic->vf_lmac_map) |
---|
1385 | 1357 | goto err_release_regions; |
---|
1386 | 1358 | |
---|
1387 | | - nic->link = devm_kmalloc_array(dev, max_lmac, sizeof(u8), GFP_KERNEL); |
---|
1388 | | - if (!nic->link) |
---|
1389 | | - goto err_release_regions; |
---|
1390 | | - |
---|
1391 | | - nic->duplex = devm_kmalloc_array(dev, max_lmac, sizeof(u8), GFP_KERNEL); |
---|
1392 | | - if (!nic->duplex) |
---|
1393 | | - goto err_release_regions; |
---|
1394 | | - |
---|
1395 | | - nic->speed = devm_kmalloc_array(dev, max_lmac, sizeof(u32), GFP_KERNEL); |
---|
1396 | | - if (!nic->speed) |
---|
1397 | | - goto err_release_regions; |
---|
1398 | | - |
---|
1399 | 1359 | /* Initialize hardware */ |
---|
1400 | 1360 | nic_init_hw(nic); |
---|
1401 | 1361 | |
---|
.. | .. |
---|
1411 | 1371 | if (err) |
---|
1412 | 1372 | goto err_unregister_interrupts; |
---|
1413 | 1373 | |
---|
1414 | | - /* Register a physical link status poll fn() */ |
---|
1415 | | - nic->check_link = alloc_workqueue("check_link_status", |
---|
1416 | | - WQ_UNBOUND | WQ_MEM_RECLAIM, 1); |
---|
1417 | | - if (!nic->check_link) { |
---|
1418 | | - err = -ENOMEM; |
---|
1419 | | - goto err_disable_sriov; |
---|
1420 | | - } |
---|
1421 | | - |
---|
1422 | | - INIT_DELAYED_WORK(&nic->dwork, nic_poll_for_link); |
---|
1423 | | - queue_delayed_work(nic->check_link, &nic->dwork, 0); |
---|
1424 | | - |
---|
1425 | 1374 | return 0; |
---|
1426 | 1375 | |
---|
1427 | | -err_disable_sriov: |
---|
1428 | | - if (nic->flags & NIC_SRIOV_ENABLED) |
---|
1429 | | - pci_disable_sriov(pdev); |
---|
1430 | 1376 | err_unregister_interrupts: |
---|
1431 | 1377 | nic_unregister_interrupts(nic); |
---|
1432 | 1378 | err_release_regions: |
---|
.. | .. |
---|
1446 | 1392 | |
---|
1447 | 1393 | if (nic->flags & NIC_SRIOV_ENABLED) |
---|
1448 | 1394 | pci_disable_sriov(pdev); |
---|
1449 | | - |
---|
1450 | | - if (nic->check_link) { |
---|
1451 | | - /* Destroy work Queue */ |
---|
1452 | | - cancel_delayed_work_sync(&nic->dwork); |
---|
1453 | | - destroy_workqueue(nic->check_link); |
---|
1454 | | - } |
---|
1455 | 1395 | |
---|
1456 | 1396 | nic_unregister_interrupts(nic); |
---|
1457 | 1397 | pci_release_regions(pdev); |
---|