Merge tag 's390-6.8-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
[linux-block.git] / drivers / char / ipmi / kcs_bmc.c
CommitLineData
20d60f61 1// SPDX-License-Identifier: GPL-2.0
3b6d082f
HW
2/*
3 * Copyright (c) 2015-2018, Intel Corporation.
faae6e39 4 * Copyright (c) 2021, IBM Corp.
3b6d082f 5 */
20d60f61 6
d4e7ac68 7#include <linux/device.h>
7cafff99 8#include <linux/list.h>
20d60f61 9#include <linux/module.h>
7cafff99 10#include <linux/mutex.h>
20d60f61
HW
11
12#include "kcs_bmc.h"
13
faae6e39
AJ
14/* Implement both the device and client interfaces here */
15#include "kcs_bmc_device.h"
16#include "kcs_bmc_client.h"
17
7cafff99
AJ
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
faae6e39
AJ
23/* Consumer data access */
24
d4e7ac68 25u8 kcs_bmc_read_data(struct kcs_bmc_device *kcs_bmc)
20d60f61 26{
faae6e39 27 return kcs_bmc->ops->io_inputb(kcs_bmc, kcs_bmc->ioreg.idr);
20d60f61 28}
55ab48b4 29EXPORT_SYMBOL(kcs_bmc_read_data);
20d60f61 30
d4e7ac68 31void kcs_bmc_write_data(struct kcs_bmc_device *kcs_bmc, u8 data)
20d60f61 32{
faae6e39 33 kcs_bmc->ops->io_outputb(kcs_bmc, kcs_bmc->ioreg.odr, data);
20d60f61 34}
55ab48b4 35EXPORT_SYMBOL(kcs_bmc_write_data);
20d60f61 36
d4e7ac68 37u8 kcs_bmc_read_status(struct kcs_bmc_device *kcs_bmc)
20d60f61 38{
faae6e39 39 return kcs_bmc->ops->io_inputb(kcs_bmc, kcs_bmc->ioreg.str);
20d60f61 40}
55ab48b4 41EXPORT_SYMBOL(kcs_bmc_read_status);
20d60f61 42
d4e7ac68 43void kcs_bmc_write_status(struct kcs_bmc_device *kcs_bmc, u8 data)
20d60f61 44{
faae6e39 45 kcs_bmc->ops->io_outputb(kcs_bmc, kcs_bmc->ioreg.str, data);
20d60f61 46}
55ab48b4 47EXPORT_SYMBOL(kcs_bmc_write_status);
20d60f61 48
d4e7ac68 49void kcs_bmc_update_status(struct kcs_bmc_device *kcs_bmc, u8 mask, u8 val)
20d60f61 50{
faae6e39 51 kcs_bmc->ops->io_updateb(kcs_bmc, kcs_bmc->ioreg.str, mask, val);
20d60f61 52}
55ab48b4 53EXPORT_SYMBOL(kcs_bmc_update_status);
20d60f61 54
d4e7ac68 55irqreturn_t kcs_bmc_handle_event(struct kcs_bmc_device *kcs_bmc)
20d60f61 56{
d4e7ac68 57 struct kcs_bmc_client *client;
fb6379f5 58 irqreturn_t rc = IRQ_NONE;
b02bb79e 59 unsigned long flags;
d4e7ac68 60
b02bb79e 61 spin_lock_irqsave(&kcs_bmc->lock, flags);
d4e7ac68 62 client = kcs_bmc->client;
fb6379f5 63 if (client)
d4e7ac68 64 rc = client->ops->event(client);
b02bb79e 65 spin_unlock_irqrestore(&kcs_bmc->lock, flags);
d4e7ac68
AJ
66
67 return rc;
20d60f61
HW
68}
69EXPORT_SYMBOL(kcs_bmc_handle_event);
70
d4e7ac68
AJ
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 {
fb6379f5
AJ
79 u8 mask = KCS_BMC_EVENT_TYPE_IBF;
80
d4e7ac68 81 kcs_bmc->client = client;
fb6379f5 82 kcs_bmc_update_event_mask(kcs_bmc, mask, mask);
d4e7ac68
AJ
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);
fb6379f5
AJ
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);
d4e7ac68 98 kcs_bmc->client = NULL;
fb6379f5 99 }
d4e7ac68
AJ
100 spin_unlock_irq(&kcs_bmc->lock);
101}
102EXPORT_SYMBOL(kcs_bmc_disable_device);
103
d4e7ac68 104int kcs_bmc_add_device(struct kcs_bmc_device *kcs_bmc)
20d60f61 105{
7cafff99
AJ
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;
20d60f61 127}
d7096970
AJ
128EXPORT_SYMBOL(kcs_bmc_add_device);
129
d4e7ac68 130void kcs_bmc_remove_device(struct kcs_bmc_device *kcs_bmc)
d7096970 131{
7cafff99
AJ
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);
d7096970
AJ
144}
145EXPORT_SYMBOL(kcs_bmc_remove_device);
20d60f61 146
7cafff99
AJ
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
28651e6c
AJ
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
20d60f61
HW
187MODULE_LICENSE("GPL v2");
188MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
faae6e39 189MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
20d60f61 190MODULE_DESCRIPTION("KCS BMC to handle the IPMI request from system software");