diff options
author | Saeed Mahameed <saeedm@mellanox.com> | 2014-10-27 05:37:35 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-10-28 17:17:59 -0400 |
commit | 32a173c7f9e9ec2b87142f67e1478cd20084a45b (patch) | |
tree | 3464627af9e7001470aff187ecc9155ccf2e18a9 | |
parent | 941d8ebcf773fd5da5c79e1c86e1afaae7032a0b (diff) |
net/mlx4_core: Introduce mlx4_get_module_info for cable module info reading
Added new MAD_IFC command to read cable module info with attribute id (0xFF60).
Update include/linux/mlx4/device.h with function declaration (mlx4_get_module_info)
and the needed defines/enums for future use.
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
Signed-off-by: Amir Vadai <amirv@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/port.c | 156 | ||||
-rw-r--r-- | include/linux/mlx4/device.h | 30 |
2 files changed, 186 insertions, 0 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index 94eeb2c7d7e4..30eb1ead0fe6 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c | |||
@@ -1311,3 +1311,159 @@ int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, | |||
1311 | return 0; | 1311 | return 0; |
1312 | } | 1312 | } |
1313 | EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); | 1313 | EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); |
1314 | |||
1315 | /* Cable Module Info */ | ||
1316 | #define MODULE_INFO_MAX_READ 48 | ||
1317 | |||
1318 | #define I2C_ADDR_LOW 0x50 | ||
1319 | #define I2C_ADDR_HIGH 0x51 | ||
1320 | #define I2C_PAGE_SIZE 256 | ||
1321 | |||
1322 | /* Module Info Data */ | ||
1323 | struct mlx4_cable_info { | ||
1324 | u8 i2c_addr; | ||
1325 | u8 page_num; | ||
1326 | __be16 dev_mem_address; | ||
1327 | __be16 reserved1; | ||
1328 | __be16 size; | ||
1329 | __be32 reserved2[2]; | ||
1330 | u8 data[MODULE_INFO_MAX_READ]; | ||
1331 | }; | ||
1332 | |||
1333 | enum cable_info_err { | ||
1334 | CABLE_INF_INV_PORT = 0x1, | ||
1335 | CABLE_INF_OP_NOSUP = 0x2, | ||
1336 | CABLE_INF_NOT_CONN = 0x3, | ||
1337 | CABLE_INF_NO_EEPRM = 0x4, | ||
1338 | CABLE_INF_PAGE_ERR = 0x5, | ||
1339 | CABLE_INF_INV_ADDR = 0x6, | ||
1340 | CABLE_INF_I2C_ADDR = 0x7, | ||
1341 | CABLE_INF_QSFP_VIO = 0x8, | ||
1342 | CABLE_INF_I2C_BUSY = 0x9, | ||
1343 | }; | ||
1344 | |||
1345 | #define MAD_STATUS_2_CABLE_ERR(mad_status) ((mad_status >> 8) & 0xFF) | ||
1346 | |||
1347 | static inline const char *cable_info_mad_err_str(u16 mad_status) | ||
1348 | { | ||
1349 | u8 err = MAD_STATUS_2_CABLE_ERR(mad_status); | ||
1350 | |||
1351 | switch (err) { | ||
1352 | case CABLE_INF_INV_PORT: | ||
1353 | return "invalid port selected"; | ||
1354 | case CABLE_INF_OP_NOSUP: | ||
1355 | return "operation not supported for this port (the port is of type CX4 or internal)"; | ||
1356 | case CABLE_INF_NOT_CONN: | ||
1357 | return "cable is not connected"; | ||
1358 | case CABLE_INF_NO_EEPRM: | ||
1359 | return "the connected cable has no EPROM (passive copper cable)"; | ||
1360 | case CABLE_INF_PAGE_ERR: | ||
1361 | return "page number is greater than 15"; | ||
1362 | case CABLE_INF_INV_ADDR: | ||
1363 | return "invalid device_address or size (that is, size equals 0 or address+size is greater than 256)"; | ||
1364 | case CABLE_INF_I2C_ADDR: | ||
1365 | return "invalid I2C slave address"; | ||
1366 | case CABLE_INF_QSFP_VIO: | ||
1367 | return "at least one cable violates the QSFP specification and ignores the modsel signal"; | ||
1368 | case CABLE_INF_I2C_BUSY: | ||
1369 | return "I2C bus is constantly busy"; | ||
1370 | } | ||
1371 | return "Unknown Error"; | ||
1372 | } | ||
1373 | |||
1374 | /** | ||
1375 | * mlx4_get_module_info - Read cable module eeprom data | ||
1376 | * @dev: mlx4_dev. | ||
1377 | * @port: port number. | ||
1378 | * @offset: byte offset in eeprom to start reading data from. | ||
1379 | * @size: num of bytes to read. | ||
1380 | * @data: output buffer to put the requested data into. | ||
1381 | * | ||
1382 | * Reads cable module eeprom data, puts the outcome data into | ||
1383 | * data pointer paramer. | ||
1384 | * Returns num of read bytes on success or a negative error | ||
1385 | * code. | ||
1386 | */ | ||
1387 | int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, | ||
1388 | u16 offset, u16 size, u8 *data) | ||
1389 | { | ||
1390 | struct mlx4_cmd_mailbox *inbox, *outbox; | ||
1391 | struct mlx4_mad_ifc *inmad, *outmad; | ||
1392 | struct mlx4_cable_info *cable_info; | ||
1393 | u16 i2c_addr; | ||
1394 | int ret; | ||
1395 | |||
1396 | if (size > MODULE_INFO_MAX_READ) | ||
1397 | size = MODULE_INFO_MAX_READ; | ||
1398 | |||
1399 | inbox = mlx4_alloc_cmd_mailbox(dev); | ||
1400 | if (IS_ERR(inbox)) | ||
1401 | return PTR_ERR(inbox); | ||
1402 | |||
1403 | outbox = mlx4_alloc_cmd_mailbox(dev); | ||
1404 | if (IS_ERR(outbox)) { | ||
1405 | mlx4_free_cmd_mailbox(dev, inbox); | ||
1406 | return PTR_ERR(outbox); | ||
1407 | } | ||
1408 | |||
1409 | inmad = (struct mlx4_mad_ifc *)(inbox->buf); | ||
1410 | outmad = (struct mlx4_mad_ifc *)(outbox->buf); | ||
1411 | |||
1412 | inmad->method = 0x1; /* Get */ | ||
1413 | inmad->class_version = 0x1; | ||
1414 | inmad->mgmt_class = 0x1; | ||
1415 | inmad->base_version = 0x1; | ||
1416 | inmad->attr_id = cpu_to_be16(0xFF60); /* Module Info */ | ||
1417 | |||
1418 | if (offset < I2C_PAGE_SIZE && offset + size > I2C_PAGE_SIZE) | ||
1419 | /* Cross pages reads are not allowed | ||
1420 | * read until offset 256 in low page | ||
1421 | */ | ||
1422 | size -= offset + size - I2C_PAGE_SIZE; | ||
1423 | |||
1424 | i2c_addr = I2C_ADDR_LOW; | ||
1425 | if (offset >= I2C_PAGE_SIZE) { | ||
1426 | /* Reset offset to high page */ | ||
1427 | i2c_addr = I2C_ADDR_HIGH; | ||
1428 | offset -= I2C_PAGE_SIZE; | ||
1429 | } | ||
1430 | |||
1431 | cable_info = (struct mlx4_cable_info *)inmad->data; | ||
1432 | cable_info->dev_mem_address = cpu_to_be16(offset); | ||
1433 | cable_info->page_num = 0; | ||
1434 | cable_info->i2c_addr = i2c_addr; | ||
1435 | cable_info->size = cpu_to_be16(size); | ||
1436 | |||
1437 | ret = mlx4_cmd_box(dev, inbox->dma, outbox->dma, port, 3, | ||
1438 | MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C, | ||
1439 | MLX4_CMD_NATIVE); | ||
1440 | if (ret) | ||
1441 | goto out; | ||
1442 | |||
1443 | if (be16_to_cpu(outmad->status)) { | ||
1444 | /* Mad returned with bad status */ | ||
1445 | ret = be16_to_cpu(outmad->status); | ||
1446 | mlx4_warn(dev, | ||
1447 | "MLX4_CMD_MAD_IFC Get Module info attr(%x) port(%d) i2c_addr(%x) offset(%d) size(%d): Response Mad Status(%x) - %s\n", | ||
1448 | 0xFF60, port, i2c_addr, offset, size, | ||
1449 | ret, cable_info_mad_err_str(ret)); | ||
1450 | |||
1451 | if (i2c_addr == I2C_ADDR_HIGH && | ||
1452 | MAD_STATUS_2_CABLE_ERR(ret) == CABLE_INF_I2C_ADDR) | ||
1453 | /* Some SFP cables do not support i2c slave | ||
1454 | * address 0x51 (high page), abort silently. | ||
1455 | */ | ||
1456 | ret = 0; | ||
1457 | else | ||
1458 | ret = -ret; | ||
1459 | goto out; | ||
1460 | } | ||
1461 | cable_info = (struct mlx4_cable_info *)outmad->data; | ||
1462 | memcpy(data, cable_info->data, size); | ||
1463 | ret = size; | ||
1464 | out: | ||
1465 | mlx4_free_cmd_mailbox(dev, inbox); | ||
1466 | mlx4_free_cmd_mailbox(dev, outbox); | ||
1467 | return ret; | ||
1468 | } | ||
1469 | EXPORT_SYMBOL(mlx4_get_module_info); | ||
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 37e4404d0227..73910daec317 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h | |||
@@ -379,6 +379,13 @@ enum { | |||
379 | #define MSTR_SM_CHANGE_MASK (MLX4_EQ_PORT_INFO_MSTR_SM_SL_CHANGE_MASK | \ | 379 | #define MSTR_SM_CHANGE_MASK (MLX4_EQ_PORT_INFO_MSTR_SM_SL_CHANGE_MASK | \ |
380 | MLX4_EQ_PORT_INFO_MSTR_SM_LID_CHANGE_MASK) | 380 | MLX4_EQ_PORT_INFO_MSTR_SM_LID_CHANGE_MASK) |
381 | 381 | ||
382 | enum mlx4_module_id { | ||
383 | MLX4_MODULE_ID_SFP = 0x3, | ||
384 | MLX4_MODULE_ID_QSFP = 0xC, | ||
385 | MLX4_MODULE_ID_QSFP_PLUS = 0xD, | ||
386 | MLX4_MODULE_ID_QSFP28 = 0x11, | ||
387 | }; | ||
388 | |||
382 | static inline u64 mlx4_fw_ver(u64 major, u64 minor, u64 subminor) | 389 | static inline u64 mlx4_fw_ver(u64 major, u64 minor, u64 subminor) |
383 | { | 390 | { |
384 | return (major << 32) | (minor << 16) | subminor; | 391 | return (major << 32) | (minor << 16) | subminor; |
@@ -799,6 +806,26 @@ struct mlx4_init_port_param { | |||
799 | u64 si_guid; | 806 | u64 si_guid; |
800 | }; | 807 | }; |
801 | 808 | ||
809 | #define MAD_IFC_DATA_SZ 192 | ||
810 | /* MAD IFC Mailbox */ | ||
811 | struct mlx4_mad_ifc { | ||
812 | u8 base_version; | ||
813 | u8 mgmt_class; | ||
814 | u8 class_version; | ||
815 | u8 method; | ||
816 | __be16 status; | ||
817 | __be16 class_specific; | ||
818 | __be64 tid; | ||
819 | __be16 attr_id; | ||
820 | __be16 resv; | ||
821 | __be32 attr_mod; | ||
822 | __be64 mkey; | ||
823 | __be16 dr_slid; | ||
824 | __be16 dr_dlid; | ||
825 | u8 reserved[28]; | ||
826 | u8 data[MAD_IFC_DATA_SZ]; | ||
827 | } __packed; | ||
828 | |||
802 | #define mlx4_foreach_port(port, dev, type) \ | 829 | #define mlx4_foreach_port(port, dev, type) \ |
803 | for ((port) = 1; (port) <= (dev)->caps.num_ports; (port)++) \ | 830 | for ((port) = 1; (port) <= (dev)->caps.num_ports; (port)++) \ |
804 | if ((type) == (dev)->caps.port_mask[(port)]) | 831 | if ((type) == (dev)->caps.port_mask[(port)]) |
@@ -1283,6 +1310,9 @@ int mlx4_mr_rereg_mem_write(struct mlx4_dev *dev, struct mlx4_mr *mr, | |||
1283 | u64 iova, u64 size, int npages, | 1310 | u64 iova, u64 size, int npages, |
1284 | int page_shift, struct mlx4_mpt_entry *mpt_entry); | 1311 | int page_shift, struct mlx4_mpt_entry *mpt_entry); |
1285 | 1312 | ||
1313 | int mlx4_get_module_info(struct mlx4_dev *dev, u8 port, | ||
1314 | u16 offset, u16 size, u8 *data); | ||
1315 | |||
1286 | /* Returns true if running in low memory profile (kdump kernel) */ | 1316 | /* Returns true if running in low memory profile (kdump kernel) */ |
1287 | static inline bool mlx4_low_memory_profile(void) | 1317 | static inline bool mlx4_low_memory_profile(void) |
1288 | { | 1318 | { |