kunpeng_hccs.c (23fe8112a23106e7dfc2b73fc52a60ea3eb64c20) | kunpeng_hccs.c (e3c289c0916e2a3d7859a0cf851ea242fa23ec1e) |
---|---|
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * The Huawei Cache Coherence System (HCCS) is a multi-chip interconnection 4 * bus protocol. 5 * 6 * Copyright (c) 2023 Hisilicon Limited. 7 * Author: Huisong Li <lihuisong@huawei.com> 8 * --- 9 unchanged lines hidden (view full) --- 18 * 19 * - Retrieve the following information about all the ports on the chip or 20 * the die: 21 * - if all enabled ports are in linked 22 * - if all linked ports are in full lane 23 * - CRC error count sum 24 * 25 * - Retrieve all HCCS types used on the platform. | 1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * The Huawei Cache Coherence System (HCCS) is a multi-chip interconnection 4 * bus protocol. 5 * 6 * Copyright (c) 2023 Hisilicon Limited. 7 * Author: Huisong Li <lihuisong@huawei.com> 8 * --- 9 unchanged lines hidden (view full) --- 18 * 19 * - Retrieve the following information about all the ports on the chip or 20 * the die: 21 * - if all enabled ports are in linked 22 * - if all linked ports are in full lane 23 * - CRC error count sum 24 * 25 * - Retrieve all HCCS types used on the platform. |
26 * 27 * - Support low power feature for all specified HCCS type ports, and 28 * provide the following interface: 29 * - query HCCS types supported increasing and decreasing lane number. 30 * - decrease lane number of all specified HCCS type ports on idle state. 31 * - increase lane number of all specified HCCS type ports. |
|
26 */ 27#include <linux/acpi.h> | 32 */ 33#include <linux/acpi.h> |
34#include <linux/delay.h> |
|
28#include <linux/iopoll.h> 29#include <linux/platform_device.h> | 35#include <linux/iopoll.h> 36#include <linux/platform_device.h> |
37#include <linux/stringify.h> |
|
30#include <linux/sysfs.h> 31#include <linux/types.h> 32 33#include <acpi/pcc.h> 34 35#include "kunpeng_hccs.h" 36 37/* --- 22 unchanged lines hidden (view full) --- 60{ 61 struct device *dev = container_of(k, struct device, kobj); 62 struct platform_device *pdev = 63 container_of(dev, struct platform_device, dev); 64 65 return platform_get_drvdata(pdev); 66} 67 | 38#include <linux/sysfs.h> 39#include <linux/types.h> 40 41#include <acpi/pcc.h> 42 43#include "kunpeng_hccs.h" 44 45/* --- 22 unchanged lines hidden (view full) --- 68{ 69 struct device *dev = container_of(k, struct device, kobj); 70 struct platform_device *pdev = 71 container_of(dev, struct platform_device, dev); 72 73 return platform_get_drvdata(pdev); 74} 75 |
76static char *hccs_port_type_to_name(struct hccs_dev *hdev, u8 type) 77{ 78 u16 i; 79 80 for (i = 0; i < hdev->used_type_num; i++) { 81 if (hdev->type_name_maps[i].type == type) 82 return hdev->type_name_maps[i].name; 83 } 84 85 return NULL; 86} 87 88static int hccs_name_to_port_type(struct hccs_dev *hdev, 89 const char *name, u8 *type) 90{ 91 u16 i; 92 93 for (i = 0; i < hdev->used_type_num; i++) { 94 if (strcmp(hdev->type_name_maps[i].name, name) == 0) { 95 *type = hdev->type_name_maps[i].type; 96 return 0; 97 } 98 } 99 100 return -EINVAL; 101} 102 |
|
68struct hccs_register_ctx { 69 struct device *dev; 70 u8 chan_id; 71 int err; 72}; 73 74static acpi_status hccs_get_register_cb(struct acpi_resource *ares, 75 void *context) --- 1114 unchanged lines hidden (view full) --- 1190}; 1191ATTRIBUTE_GROUPS(hccs_chip_default); 1192 1193static const struct kobj_type hccs_chip_type = { 1194 .sysfs_ops = &hccs_comm_ops, 1195 .default_groups = hccs_chip_default_groups, 1196}; 1197 | 103struct hccs_register_ctx { 104 struct device *dev; 105 u8 chan_id; 106 int err; 107}; 108 109static acpi_status hccs_get_register_cb(struct acpi_resource *ares, 110 void *context) --- 1114 unchanged lines hidden (view full) --- 1225}; 1226ATTRIBUTE_GROUPS(hccs_chip_default); 1227 1228static const struct kobj_type hccs_chip_type = { 1229 .sysfs_ops = &hccs_comm_ops, 1230 .default_groups = hccs_chip_default_groups, 1231}; 1232 |
1233static int hccs_parse_pm_port_type(struct hccs_dev *hdev, const char *buf, 1234 u8 *port_type) 1235{ 1236 char hccs_name[HCCS_NAME_MAX_LEN + 1] = ""; 1237 u8 type; 1238 int ret; |
|
1198 | 1239 |
1240 ret = sscanf(buf, "%" __stringify(HCCS_NAME_MAX_LEN) "s", hccs_name); 1241 if (ret != 1) 1242 return -EINVAL; 1243 1244 ret = hccs_name_to_port_type(hdev, hccs_name, &type); 1245 if (ret) { 1246 dev_dbg(hdev->dev, "input invalid, please get the available types from 'used_types'.\n"); 1247 return ret; 1248 } 1249 1250 if (type == HCCS_V2 && hdev->caps & HCCS_CAPS_HCCS_V2_PM) { 1251 *port_type = type; 1252 return 0; 1253 } 1254 1255 dev_dbg(hdev->dev, "%s doesn't support for increasing and decreasing lane.\n", 1256 hccs_name); 1257 1258 return -EOPNOTSUPP; 1259} 1260 1261static int hccs_query_port_idle_status(struct hccs_dev *hdev, 1262 struct hccs_port_info *port, u8 *idle) 1263{ 1264 const struct hccs_die_info *die = port->die; 1265 const struct hccs_chip_info *chip = die->chip; 1266 struct hccs_port_comm_req_param *req_param; 1267 struct hccs_desc desc; 1268 int ret; 1269 1270 hccs_init_req_desc(&desc); 1271 req_param = (struct hccs_port_comm_req_param *)desc.req.data; 1272 req_param->chip_id = chip->chip_id; 1273 req_param->die_id = die->die_id; 1274 req_param->port_id = port->port_id; 1275 ret = hccs_pcc_cmd_send(hdev, HCCS_GET_PORT_IDLE_STATUS, &desc); 1276 if (ret) { 1277 dev_err(hdev->dev, 1278 "get port idle status failed, ret = %d.\n", ret); 1279 return ret; 1280 } 1281 1282 *idle = *((u8 *)desc.rsp.data); 1283 return 0; 1284} 1285 1286static int hccs_get_all_spec_port_idle_sta(struct hccs_dev *hdev, u8 port_type, 1287 bool *all_idle) 1288{ 1289 struct hccs_chip_info *chip; 1290 struct hccs_port_info *port; 1291 struct hccs_die_info *die; 1292 int ret = 0; 1293 u8 i, j, k; 1294 u8 idle; 1295 1296 *all_idle = false; 1297 for (i = 0; i < hdev->chip_num; i++) { 1298 chip = &hdev->chips[i]; 1299 for (j = 0; j < chip->die_num; j++) { 1300 die = &chip->dies[j]; 1301 for (k = 0; k < die->port_num; k++) { 1302 port = &die->ports[k]; 1303 if (port->port_type != port_type) 1304 continue; 1305 ret = hccs_query_port_idle_status(hdev, port, 1306 &idle); 1307 if (ret) { 1308 dev_err(hdev->dev, 1309 "hccs%u on chip%u/die%u get idle status failed, ret = %d.\n", 1310 k, i, j, ret); 1311 return ret; 1312 } else if (idle == 0) { 1313 dev_info(hdev->dev, "hccs%u on chip%u/die%u is busy.\n", 1314 k, i, j); 1315 return 0; 1316 } 1317 } 1318 } 1319 } 1320 *all_idle = true; 1321 1322 return 0; 1323} 1324 1325static int hccs_get_all_spec_port_full_lane_sta(struct hccs_dev *hdev, 1326 u8 port_type, bool *full_lane) 1327{ 1328 struct hccs_link_status status = {0}; 1329 struct hccs_chip_info *chip; 1330 struct hccs_port_info *port; 1331 struct hccs_die_info *die; 1332 u8 i, j, k; 1333 int ret; 1334 1335 *full_lane = false; 1336 for (i = 0; i < hdev->chip_num; i++) { 1337 chip = &hdev->chips[i]; 1338 for (j = 0; j < chip->die_num; j++) { 1339 die = &chip->dies[j]; 1340 for (k = 0; k < die->port_num; k++) { 1341 port = &die->ports[k]; 1342 if (port->port_type != port_type) 1343 continue; 1344 ret = hccs_query_port_link_status(hdev, port, 1345 &status); 1346 if (ret) 1347 return ret; 1348 if (status.lane_num != port->max_lane_num) 1349 return 0; 1350 } 1351 } 1352 } 1353 *full_lane = true; 1354 1355 return 0; 1356} 1357 1358static int hccs_prepare_inc_lane(struct hccs_dev *hdev, u8 type) 1359{ 1360 struct hccs_inc_lane_req_param *req_param; 1361 struct hccs_desc desc; 1362 int ret; 1363 1364 hccs_init_req_desc(&desc); 1365 req_param = (struct hccs_inc_lane_req_param *)desc.req.data; 1366 req_param->port_type = type; 1367 req_param->opt_type = HCCS_PREPARE_INC_LANE; 1368 ret = hccs_pcc_cmd_send(hdev, HCCS_PM_INC_LANE, &desc); 1369 if (ret) 1370 dev_err(hdev->dev, "prepare for increasing lane failed, ret = %d.\n", 1371 ret); 1372 1373 return ret; 1374} 1375 1376static int hccs_wait_serdes_adapt_completed(struct hccs_dev *hdev, u8 type) 1377{ 1378#define HCCS_MAX_WAIT_CNT_FOR_ADAPT 10 1379#define HCCS_QUERY_ADAPT_RES_DELAY_MS 100 1380#define HCCS_SERDES_ADAPT_OK 0 1381 1382 struct hccs_inc_lane_req_param *req_param; 1383 u8 wait_cnt = HCCS_MAX_WAIT_CNT_FOR_ADAPT; 1384 struct hccs_desc desc; 1385 u8 adapt_res; 1386 int ret; 1387 1388 do { 1389 hccs_init_req_desc(&desc); 1390 req_param = (struct hccs_inc_lane_req_param *)desc.req.data; 1391 req_param->port_type = type; 1392 req_param->opt_type = HCCS_GET_ADAPT_RES; 1393 ret = hccs_pcc_cmd_send(hdev, HCCS_PM_INC_LANE, &desc); 1394 if (ret) { 1395 dev_err(hdev->dev, "query adapting result failed, ret = %d.\n", 1396 ret); 1397 return ret; 1398 } 1399 adapt_res = *((u8 *)&desc.rsp.data); 1400 if (adapt_res == HCCS_SERDES_ADAPT_OK) 1401 return 0; 1402 1403 msleep(HCCS_QUERY_ADAPT_RES_DELAY_MS); 1404 } while (--wait_cnt); 1405 1406 dev_err(hdev->dev, "wait for adapting completed timeout.\n"); 1407 1408 return -ETIMEDOUT; 1409} 1410 1411static int hccs_start_hpcs_retraining(struct hccs_dev *hdev, u8 type) 1412{ 1413 struct hccs_inc_lane_req_param *req_param; 1414 struct hccs_desc desc; 1415 int ret; 1416 1417 hccs_init_req_desc(&desc); 1418 req_param = (struct hccs_inc_lane_req_param *)desc.req.data; 1419 req_param->port_type = type; 1420 req_param->opt_type = HCCS_START_RETRAINING; 1421 ret = hccs_pcc_cmd_send(hdev, HCCS_PM_INC_LANE, &desc); 1422 if (ret) 1423 dev_err(hdev->dev, "start hpcs retraining failed, ret = %d.\n", 1424 ret); 1425 1426 return ret; 1427} 1428 1429static int hccs_start_inc_lane(struct hccs_dev *hdev, u8 type) 1430{ 1431 int ret; 1432 1433 ret = hccs_prepare_inc_lane(hdev, type); 1434 if (ret) 1435 return ret; 1436 1437 ret = hccs_wait_serdes_adapt_completed(hdev, type); 1438 if (ret) 1439 return ret; 1440 1441 return hccs_start_hpcs_retraining(hdev, type); 1442} 1443 1444static int hccs_start_dec_lane(struct hccs_dev *hdev, u8 type) 1445{ 1446 struct hccs_desc desc; 1447 u8 *port_type; 1448 int ret; 1449 1450 hccs_init_req_desc(&desc); 1451 port_type = (u8 *)desc.req.data; 1452 *port_type = type; 1453 ret = hccs_pcc_cmd_send(hdev, HCCS_PM_DEC_LANE, &desc); 1454 if (ret) 1455 dev_err(hdev->dev, "start to decrease lane failed, ret = %d.\n", 1456 ret); 1457 1458 return ret; 1459} 1460 1461static ssize_t dec_lane_of_type_store(struct kobject *kobj, struct kobj_attribute *attr, 1462 const char *buf, size_t count) 1463{ 1464 struct hccs_dev *hdev = device_kobj_to_hccs_dev(kobj); 1465 bool all_in_idle; 1466 u8 port_type; 1467 int ret; 1468 1469 ret = hccs_parse_pm_port_type(hdev, buf, &port_type); 1470 if (ret) 1471 return ret; 1472 1473 mutex_lock(&hdev->lock); 1474 ret = hccs_get_all_spec_port_idle_sta(hdev, port_type, &all_in_idle); 1475 if (ret) 1476 goto out; 1477 if (!all_in_idle) { 1478 ret = -EBUSY; 1479 dev_err(hdev->dev, "please don't decrese lanes on high load with %s, ret = %d.\n", 1480 hccs_port_type_to_name(hdev, port_type), ret); 1481 goto out; 1482 } 1483 1484 ret = hccs_start_dec_lane(hdev, port_type); 1485out: 1486 mutex_unlock(&hdev->lock); 1487 1488 return ret == 0 ? count : ret; 1489} 1490static struct kobj_attribute dec_lane_of_type_attr = 1491 __ATTR(dec_lane_of_type, 0200, NULL, dec_lane_of_type_store); 1492 1493static ssize_t inc_lane_of_type_store(struct kobject *kobj, struct kobj_attribute *attr, 1494 const char *buf, size_t count) 1495{ 1496 struct hccs_dev *hdev = device_kobj_to_hccs_dev(kobj); 1497 bool full_lane; 1498 u8 port_type; 1499 int ret; 1500 1501 ret = hccs_parse_pm_port_type(hdev, buf, &port_type); 1502 if (ret) 1503 return ret; 1504 1505 mutex_lock(&hdev->lock); 1506 ret = hccs_get_all_spec_port_full_lane_sta(hdev, port_type, &full_lane); 1507 if (ret || full_lane) 1508 goto out; 1509 1510 ret = hccs_start_inc_lane(hdev, port_type); 1511out: 1512 mutex_unlock(&hdev->lock); 1513 return ret == 0 ? count : ret; 1514} 1515static struct kobj_attribute inc_lane_of_type_attr = 1516 __ATTR(inc_lane_of_type, 0200, NULL, inc_lane_of_type_store); 1517 1518static ssize_t available_inc_dec_lane_types_show(struct kobject *kobj, 1519 struct kobj_attribute *attr, 1520 char *buf) 1521{ 1522 struct hccs_dev *hdev = device_kobj_to_hccs_dev(kobj); 1523 1524 if (hdev->caps & HCCS_CAPS_HCCS_V2_PM) 1525 return sysfs_emit(buf, "%s\n", 1526 hccs_port_type_to_name(hdev, HCCS_V2)); 1527 1528 return -EINVAL; 1529} 1530static struct kobj_attribute available_inc_dec_lane_types_attr = 1531 __ATTR(available_inc_dec_lane_types, 0444, 1532 available_inc_dec_lane_types_show, NULL); 1533 |
|
1199static ssize_t used_types_show(struct kobject *kobj, 1200 struct kobj_attribute *attr, char *buf) 1201{ 1202 struct hccs_dev *hdev = device_kobj_to_hccs_dev(kobj); 1203 int len = 0; 1204 u16 i; 1205 1206 for (i = 0; i < hdev->used_type_num - 1; i++) 1207 len += sysfs_emit(&buf[len], "%s ", hdev->type_name_maps[i].name); 1208 len += sysfs_emit(&buf[len], "%s\n", hdev->type_name_maps[i].name); 1209 1210 return len; 1211} 1212static struct kobj_attribute used_types_attr = 1213 __ATTR(used_types, 0444, used_types_show, NULL); 1214 1215static void hccs_remove_misc_sysfs(struct hccs_dev *hdev) 1216{ 1217 sysfs_remove_file(&hdev->dev->kobj, &used_types_attr.attr); | 1534static ssize_t used_types_show(struct kobject *kobj, 1535 struct kobj_attribute *attr, char *buf) 1536{ 1537 struct hccs_dev *hdev = device_kobj_to_hccs_dev(kobj); 1538 int len = 0; 1539 u16 i; 1540 1541 for (i = 0; i < hdev->used_type_num - 1; i++) 1542 len += sysfs_emit(&buf[len], "%s ", hdev->type_name_maps[i].name); 1543 len += sysfs_emit(&buf[len], "%s\n", hdev->type_name_maps[i].name); 1544 1545 return len; 1546} 1547static struct kobj_attribute used_types_attr = 1548 __ATTR(used_types, 0444, used_types_show, NULL); 1549 1550static void hccs_remove_misc_sysfs(struct hccs_dev *hdev) 1551{ 1552 sysfs_remove_file(&hdev->dev->kobj, &used_types_attr.attr); |
1553 1554 if (!(hdev->caps & HCCS_CAPS_HCCS_V2_PM)) 1555 return; 1556 1557 sysfs_remove_file(&hdev->dev->kobj, 1558 &available_inc_dec_lane_types_attr.attr); 1559 sysfs_remove_file(&hdev->dev->kobj, &dec_lane_of_type_attr.attr); 1560 sysfs_remove_file(&hdev->dev->kobj, &inc_lane_of_type_attr.attr); |
|
1218} 1219 1220static int hccs_add_misc_sysfs(struct hccs_dev *hdev) 1221{ | 1561} 1562 1563static int hccs_add_misc_sysfs(struct hccs_dev *hdev) 1564{ |
1222 return sysfs_create_file(&hdev->dev->kobj, &used_types_attr.attr); | 1565 int ret; 1566 1567 ret = sysfs_create_file(&hdev->dev->kobj, &used_types_attr.attr); 1568 if (ret) 1569 return ret; 1570 1571 if (!(hdev->caps & HCCS_CAPS_HCCS_V2_PM)) 1572 return 0; 1573 1574 ret = sysfs_create_file(&hdev->dev->kobj, 1575 &available_inc_dec_lane_types_attr.attr); 1576 if (ret) 1577 goto used_types_remove; 1578 1579 ret = sysfs_create_file(&hdev->dev->kobj, &dec_lane_of_type_attr.attr); 1580 if (ret) 1581 goto inc_dec_lane_types_remove; 1582 1583 ret = sysfs_create_file(&hdev->dev->kobj, &inc_lane_of_type_attr.attr); 1584 if (ret) 1585 goto dec_lane_of_type_remove; 1586 1587 return 0; 1588 1589dec_lane_of_type_remove: 1590 sysfs_remove_file(&hdev->dev->kobj, &dec_lane_of_type_attr.attr); 1591inc_dec_lane_types_remove: 1592 sysfs_remove_file(&hdev->dev->kobj, 1593 &available_inc_dec_lane_types_attr.attr); 1594used_types_remove: 1595 sysfs_remove_file(&hdev->dev->kobj, &used_types_attr.attr); 1596 return ret; |
1223} 1224 1225static void hccs_remove_die_dir(struct hccs_die_info *die) 1226{ 1227 struct hccs_port_info *port; 1228 u8 i; 1229 1230 for (i = 0; i < die->port_num; i++) { --- 242 unchanged lines hidden --- | 1597} 1598 1599static void hccs_remove_die_dir(struct hccs_die_info *die) 1600{ 1601 struct hccs_port_info *port; 1602 u8 i; 1603 1604 for (i = 0; i < die->port_num; i++) { --- 242 unchanged lines hidden --- |