pnet.c 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  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. /*
  15. * Get the PNETIDs from a device.
  16. * s390 hardware supports the definition of a so-called Physical Network
  17. * Identifier (short PNETID) per network device port. These PNETIDs can be
  18. * used to identify network devices that are attached to the same physical
  19. * network (broadcast domain).
  20. *
  21. * The device can be
  22. * - a ccwgroup device with all bundled subchannels having the same PNETID
  23. * - a PCI attached network device
  24. *
  25. * Returns:
  26. * 0: PNETIDs extracted from device.
  27. * -ENOMEM: No memory to extract utility string.
  28. * -EOPNOTSUPP: Device type without utility string support
  29. */
  30. static int pnet_ids_by_device(struct device *dev, u8 *pnetids)
  31. {
  32. memset(pnetids, 0, PNETIDS_LEN);
  33. if (dev_is_ccwgroup(dev)) {
  34. struct ccwgroup_device *gdev = to_ccwgroupdev(dev);
  35. u8 *util_str;
  36. util_str = ccw_device_get_util_str(gdev->cdev[0], 0);
  37. if (!util_str)
  38. return -ENOMEM;
  39. memcpy(pnetids, util_str, PNETIDS_LEN);
  40. kfree(util_str);
  41. return 0;
  42. }
  43. if (dev_is_pci(dev)) {
  44. struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
  45. memcpy(pnetids, zdev->util_str, sizeof(zdev->util_str));
  46. return 0;
  47. }
  48. return -EOPNOTSUPP;
  49. }
  50. /*
  51. * Extract the pnetid for a device port.
  52. *
  53. * Return 0 if a pnetid is found and -ENOENT otherwise.
  54. */
  55. int pnet_id_by_dev_port(struct device *dev, unsigned short port, u8 *pnetid)
  56. {
  57. u8 pnetids[MAX_PNETID_PORTS][MAX_PNETID_LEN];
  58. static const u8 zero[MAX_PNETID_LEN] = { 0 };
  59. int rc = 0;
  60. if (!dev || port >= MAX_PNETID_PORTS)
  61. return -ENOENT;
  62. if (!pnet_ids_by_device(dev, (u8 *)pnetids) &&
  63. memcmp(pnetids[port], zero, MAX_PNETID_LEN))
  64. memcpy(pnetid, pnetids[port], MAX_PNETID_LEN);
  65. else
  66. rc = -ENOENT;
  67. return rc;
  68. }
  69. EXPORT_SYMBOL_GPL(pnet_id_by_dev_port);
  70. MODULE_DESCRIPTION("pnetid determination from utility strings");
  71. MODULE_LICENSE("GPL");