| .. | .. |
|---|
| 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); |
|---|