pnet.c 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * IBM System z PNET ID Support
  4. *
  5. * Copyright IBM Corp. 2018
  6. */
  7. #include <linux/device.h>
  8. #include <linux/module.h>
  9. #include <linux/pci.h>
  10. #include <linux/types.h>
  11. #include <asm/ccwgroup.h>
  12. #include <asm/ccwdev.h>
  13. #include <asm/pnet.h>
  14. #include <asm/ebcdic.h>
  15. #define PNETIDS_LEN 64 /* Total utility string length in bytes
  16. * to cover up to 4 PNETIDs of 16 bytes
  17. * for up to 4 device ports
  18. */
  19. #define MAX_PNETID_LEN 16 /* Max.length of a single port PNETID */
  20. #define MAX_PNETID_PORTS (PNETIDS_LEN / MAX_PNETID_LEN)
  21. /* Max. # of ports with a PNETID */
  22. /*
  23. * Get the PNETIDs from a device.
  24. * s390 hardware supports the definition of a so-called Physical Network
  25. * Identifier (short PNETID) per network device port. These PNETIDs can be
  26. * used to identify network devices that are attached to the same physical
  27. * network (broadcast domain).
  28. *
  29. * The device can be
  30. * - a ccwgroup device with all bundled subchannels having the same PNETID
  31. * - a PCI attached network device
  32. *
  33. * Returns:
  34. * 0: PNETIDs extracted from device.
  35. * -ENOMEM: No memory to extract utility string.
  36. * -EOPNOTSUPP: Device type without utility string support
  37. */
  38. static int pnet_ids_by_device(struct device *dev, u8 *pnetids)
  39. {
  40. memset(pnetids, 0, PNETIDS_LEN);
  41. if (dev_is_ccwgroup(dev)) {
  42. struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
  43. u8 *util_str;
  44. util_str = ccw_device_get_util_str(gdev->cdev[0], 0);
  45. if (!util_str)
  46. return -ENOMEM;
  47. memcpy(pnetids, util_str, PNETIDS_LEN);
  48. EBCASC(pnetids, PNETIDS_LEN);
  49. kfree(util_str);
  50. return 0;
  51. }
  52. if (dev_is_pci(dev)) {
  53. struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
  54. memcpy(pnetids, zdev->util_str, sizeof(zdev->util_str));
  55. EBCASC(pnetids, sizeof(zdev->util_str));
  56. return 0;
  57. }
  58. return -EOPNOTSUPP;
  59. }
  60. /*
  61. * Extract the pnetid for a device port.
  62. *
  63. * Return 0 if a pnetid is found and -ENOENT otherwise.
  64. */
  65. int pnet_id_by_dev_port(struct device *dev, unsigned short port, u8 *pnetid)
  66. {
  67. u8 pnetids[MAX_PNETID_PORTS][MAX_PNETID_LEN];
  68. static const u8 zero[MAX_PNETID_LEN] = { 0 };
  69. int rc = 0;
  70. if (!dev || port >= MAX_PNETID_PORTS)
  71. return -ENOENT;
  72. if (!pnet_ids_by_device(dev, (u8 *)pnetids) &&
  73. memcmp(pnetids[port], zero, MAX_PNETID_LEN))
  74. memcpy(pnetid, pnetids[port], MAX_PNETID_LEN);
  75. else
  76. rc = -ENOENT;
  77. return rc;
  78. }
  79. EXPORT_SYMBOL_GPL(pnet_id_by_dev_port);
  80. MODULE_DESCRIPTION("pnetid determination from utility strings");
  81. MODULE_LICENSE("GPL");