brintos

brintos / linux-shallow public Read only

0
0
Text · 4.7 KiB · 8b1161d Raw
191 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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	unsigned long flags;60 61	spin_lock_irqsave(&kcs_bmc->lock, flags);62	client = kcs_bmc->client;63	if (client)64		rc = client->ops->event(client);65	spin_unlock_irqrestore(&kcs_bmc->lock, flags);66 67	return rc;68}69EXPORT_SYMBOL(kcs_bmc_handle_event);70 71int kcs_bmc_enable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)72{73	int rc;74 75	spin_lock_irq(&kcs_bmc->lock);76	if (kcs_bmc->client) {77		rc = -EBUSY;78	} else {79		u8 mask = KCS_BMC_EVENT_TYPE_IBF;80 81		kcs_bmc->client = client;82		kcs_bmc_update_event_mask(kcs_bmc, mask, mask);83		rc = 0;84	}85	spin_unlock_irq(&kcs_bmc->lock);86 87	return rc;88}89EXPORT_SYMBOL(kcs_bmc_enable_device);90 91void kcs_bmc_disable_device(struct kcs_bmc_device *kcs_bmc, struct kcs_bmc_client *client)92{93	spin_lock_irq(&kcs_bmc->lock);94	if (client == kcs_bmc->client) {95		u8 mask = KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE;96 97		kcs_bmc_update_event_mask(kcs_bmc, mask, 0);98		kcs_bmc->client = NULL;99	}100	spin_unlock_irq(&kcs_bmc->lock);101}102EXPORT_SYMBOL(kcs_bmc_disable_device);103 104int kcs_bmc_add_device(struct kcs_bmc_device *kcs_bmc)105{106	struct kcs_bmc_driver *drv;107	int error = 0;108	int rc;109 110	spin_lock_init(&kcs_bmc->lock);111	kcs_bmc->client = NULL;112 113	mutex_lock(&kcs_bmc_lock);114	list_add(&kcs_bmc->entry, &kcs_bmc_devices);115	list_for_each_entry(drv, &kcs_bmc_drivers, entry) {116		rc = drv->ops->add_device(kcs_bmc);117		if (!rc)118			continue;119 120		dev_err(kcs_bmc->dev, "Failed to add chardev for KCS channel %d: %d",121			kcs_bmc->channel, rc);122		error = rc;123	}124	mutex_unlock(&kcs_bmc_lock);125 126	return error;127}128EXPORT_SYMBOL(kcs_bmc_add_device);129 130void kcs_bmc_remove_device(struct kcs_bmc_device *kcs_bmc)131{132	struct kcs_bmc_driver *drv;133	int rc;134 135	mutex_lock(&kcs_bmc_lock);136	list_del(&kcs_bmc->entry);137	list_for_each_entry(drv, &kcs_bmc_drivers, entry) {138		rc = drv->ops->remove_device(kcs_bmc);139		if (rc)140			dev_err(kcs_bmc->dev, "Failed to remove chardev for KCS channel %d: %d",141				kcs_bmc->channel, rc);142	}143	mutex_unlock(&kcs_bmc_lock);144}145EXPORT_SYMBOL(kcs_bmc_remove_device);146 147void kcs_bmc_register_driver(struct kcs_bmc_driver *drv)148{149	struct kcs_bmc_device *kcs_bmc;150	int rc;151 152	mutex_lock(&kcs_bmc_lock);153	list_add(&drv->entry, &kcs_bmc_drivers);154	list_for_each_entry(kcs_bmc, &kcs_bmc_devices, entry) {155		rc = drv->ops->add_device(kcs_bmc);156		if (rc)157			dev_err(kcs_bmc->dev, "Failed to add driver for KCS channel %d: %d",158				kcs_bmc->channel, rc);159	}160	mutex_unlock(&kcs_bmc_lock);161}162EXPORT_SYMBOL(kcs_bmc_register_driver);163 164void kcs_bmc_unregister_driver(struct kcs_bmc_driver *drv)165{166	struct kcs_bmc_device *kcs_bmc;167	int rc;168 169	mutex_lock(&kcs_bmc_lock);170	list_del(&drv->entry);171	list_for_each_entry(kcs_bmc, &kcs_bmc_devices, entry) {172		rc = drv->ops->remove_device(kcs_bmc);173		if (rc)174			dev_err(kcs_bmc->dev, "Failed to remove driver for KCS channel %d: %d",175				kcs_bmc->channel, rc);176	}177	mutex_unlock(&kcs_bmc_lock);178}179EXPORT_SYMBOL(kcs_bmc_unregister_driver);180 181void kcs_bmc_update_event_mask(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 events)182{183	kcs_bmc->ops->irq_mask_update(kcs_bmc, mask, events);184}185EXPORT_SYMBOL(kcs_bmc_update_event_mask);186 187MODULE_LICENSE("GPL v2");188MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");189MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");190MODULE_DESCRIPTION("KCS BMC to handle the IPMI request from system software");191