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

kcs_bmc.c (4757B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2015-2018, Intel Corporation.
      4 * Copyright (c) 2021, IBM Corp.
      5 */
      6
      7#include <linux/device.h>
      8#include <linux/list.h>
      9#include <linux/module.h>
     10#include <linux/mutex.h>
     11
     12#include "kcs_bmc.h"
     13
     14/* Implement both the device and client interfaces here */
     15#include "kcs_bmc_device.h"
     16#include "kcs_bmc_client.h"
     17
     18/* Record registered devices and drivers */
     19static DEFINE_MUTEX(kcs_bmc_lock);
     20static LIST_HEAD(kcs_bmc_devices);
     21static LIST_HEAD(kcs_bmc_drivers);
     22
     23/* Consumer data access */
     24
     25u8 kcs_bmc_read_data(struct kcs_bmc_device *kcs_bmc)
     26{
     27	return kcs_bmc->ops->io_inputb(kcs_bmc, kcs_bmc->ioreg.idr);
     28}
     29EXPORT_SYMBOL(kcs_bmc_read_data);
     30
     31void kcs_bmc_write_data(struct kcs_bmc_device *kcs_bmc, u8 data)
     32{
     33	kcs_bmc->ops->io_outputb(kcs_bmc, kcs_bmc->ioreg.odr, data);
     34}
     35EXPORT_SYMBOL(kcs_bmc_write_data);
     36
     37u8 kcs_bmc_read_status(struct kcs_bmc_device *kcs_bmc)
     38{
     39	return kcs_bmc->ops->io_inputb(kcs_bmc, kcs_bmc->ioreg.str);
     40}
     41EXPORT_SYMBOL(kcs_bmc_read_status);
     42
     43void kcs_bmc_write_status(struct kcs_bmc_device *kcs_bmc, u8 data)
     44{
     45	kcs_bmc->ops->io_outputb(kcs_bmc, kcs_bmc->ioreg.str, data);
     46}
     47EXPORT_SYMBOL(kcs_bmc_write_status);
     48
     49void kcs_bmc_update_status(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 val)
     50{
     51	kcs_bmc->ops->io_updateb(kcs_bmc, kcs_bmc->ioreg.str, mask, val);
     52}
     53EXPORT_SYMBOL(kcs_bmc_update_status);
     54
     55irqreturn_t kcs_bmc_handle_event(struct kcs_bmc_device *kcs_bmc)
     56{
     57	struct kcs_bmc_client *client;
     58	irqreturn_t rc = IRQ_NONE;
     59
     60	spin_lock(&kcs_bmc->lock);
     61	client = kcs_bmc->client;
     62	if (client)
     63		rc = client->ops->event(client);
     64	spin_unlock(&kcs_bmc->lock);
     65
     66	return rc;
     67}
     68EXPORT_SYMBOL(kcs_bmc_handle_event);
     69
     70int kcs_bmc_enable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)
     71{
     72	int rc;
     73
     74	spin_lock_irq(&kcs_bmc->lock);
     75	if (kcs_bmc->client) {
     76		rc = -EBUSY;
     77	} else {
     78		u8 mask = KCS_BMC_EVENT_TYPE_IBF;
     79
     80		kcs_bmc->client = client;
     81		kcs_bmc_update_event_mask(kcs_bmc, mask, mask);
     82		rc = 0;
     83	}
     84	spin_unlock_irq(&kcs_bmc->lock);
     85
     86	return rc;
     87}
     88EXPORT_SYMBOL(kcs_bmc_enable_device);
     89
     90void kcs_bmc_disable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)
     91{
     92	spin_lock_irq(&kcs_bmc->lock);
     93	if (client == kcs_bmc->client) {
     94		u8 mask = KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE;
     95
     96		kcs_bmc_update_event_mask(kcs_bmc, mask, 0);
     97		kcs_bmc->client = NULL;
     98	}
     99	spin_unlock_irq(&kcs_bmc->lock);
    100}
    101EXPORT_SYMBOL(kcs_bmc_disable_device);
    102
    103int kcs_bmc_add_device(struct kcs_bmc_device *kcs_bmc)
    104{
    105	struct kcs_bmc_driver *drv;
    106	int error = 0;
    107	int rc;
    108
    109	spin_lock_init(&kcs_bmc->lock);
    110	kcs_bmc->client = NULL;
    111
    112	mutex_lock(&kcs_bmc_lock);
    113	list_add(&kcs_bmc->entry, &kcs_bmc_devices);
    114	list_for_each_entry(drv, &kcs_bmc_drivers, entry) {
    115		rc = drv->ops->add_device(kcs_bmc);
    116		if (!rc)
    117			continue;
    118
    119		dev_err(kcs_bmc->dev, "Failed to add chardev for KCS channel %d: %d",
    120			kcs_bmc->channel, rc);
    121		error = rc;
    122	}
    123	mutex_unlock(&kcs_bmc_lock);
    124
    125	return error;
    126}
    127EXPORT_SYMBOL(kcs_bmc_add_device);
    128
    129void kcs_bmc_remove_device(struct kcs_bmc_device *kcs_bmc)
    130{
    131	struct kcs_bmc_driver *drv;
    132	int rc;
    133
    134	mutex_lock(&kcs_bmc_lock);
    135	list_del(&kcs_bmc->entry);
    136	list_for_each_entry(drv, &kcs_bmc_drivers, entry) {
    137		rc = drv->ops->remove_device(kcs_bmc);
    138		if (rc)
    139			dev_err(kcs_bmc->dev, "Failed to remove chardev for KCS channel %d: %d",
    140				kcs_bmc->channel, rc);
    141	}
    142	mutex_unlock(&kcs_bmc_lock);
    143}
    144EXPORT_SYMBOL(kcs_bmc_remove_device);
    145
    146void kcs_bmc_register_driver(struct kcs_bmc_driver *drv)
    147{
    148	struct kcs_bmc_device *kcs_bmc;
    149	int rc;
    150
    151	mutex_lock(&kcs_bmc_lock);
    152	list_add(&drv->entry, &kcs_bmc_drivers);
    153	list_for_each_entry(kcs_bmc, &kcs_bmc_devices, entry) {
    154		rc = drv->ops->add_device(kcs_bmc);
    155		if (rc)
    156			dev_err(kcs_bmc->dev, "Failed to add driver for KCS channel %d: %d",
    157				kcs_bmc->channel, rc);
    158	}
    159	mutex_unlock(&kcs_bmc_lock);
    160}
    161EXPORT_SYMBOL(kcs_bmc_register_driver);
    162
    163void kcs_bmc_unregister_driver(struct kcs_bmc_driver *drv)
    164{
    165	struct kcs_bmc_device *kcs_bmc;
    166	int rc;
    167
    168	mutex_lock(&kcs_bmc_lock);
    169	list_del(&drv->entry);
    170	list_for_each_entry(kcs_bmc, &kcs_bmc_devices, entry) {
    171		rc = drv->ops->remove_device(kcs_bmc);
    172		if (rc)
    173			dev_err(kcs_bmc->dev, "Failed to remove driver for KCS channel %d: %d",
    174				kcs_bmc->channel, rc);
    175	}
    176	mutex_unlock(&kcs_bmc_lock);
    177}
    178EXPORT_SYMBOL(kcs_bmc_unregister_driver);
    179
    180void kcs_bmc_update_event_mask(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 events)
    181{
    182	kcs_bmc->ops->irq_mask_update(kcs_bmc, mask, events);
    183}
    184EXPORT_SYMBOL(kcs_bmc_update_event_mask);
    185
    186MODULE_LICENSE("GPL v2");
    187MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
    188MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
    189MODULE_DESCRIPTION("KCS BMC to handle the IPMI request from system software");