cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pnet.c (2497B)


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