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