1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2015-2018, Intel Corporation.
4 * Copyright (c) 2021, IBM Corp.
7 #include <linux/device.h>
8 #include <linux/list.h>
9 #include <linux/module.h>
10 #include <linux/mutex.h>
14 /* Implement both the device and client interfaces here */
15 #include "kcs_bmc_device.h"
16 #include "kcs_bmc_client.h"
18 /* Record registered devices and drivers */
19 static DEFINE_MUTEX(kcs_bmc_lock
);
20 static LIST_HEAD(kcs_bmc_devices
);
21 static LIST_HEAD(kcs_bmc_drivers
);
23 /* Consumer data access */
25 u8
kcs_bmc_read_data(struct kcs_bmc_device
*kcs_bmc
)
27 return kcs_bmc
->ops
->io_inputb(kcs_bmc
, kcs_bmc
->ioreg
.idr
);
29 EXPORT_SYMBOL(kcs_bmc_read_data
);
31 void kcs_bmc_write_data(struct kcs_bmc_device
*kcs_bmc
, u8 data
)
33 kcs_bmc
->ops
->io_outputb(kcs_bmc
, kcs_bmc
->ioreg
.odr
, data
);
35 EXPORT_SYMBOL(kcs_bmc_write_data
);
37 u8
kcs_bmc_read_status(struct kcs_bmc_device
*kcs_bmc
)
39 return kcs_bmc
->ops
->io_inputb(kcs_bmc
, kcs_bmc
->ioreg
.str
);
41 EXPORT_SYMBOL(kcs_bmc_read_status
);
43 void kcs_bmc_write_status(struct kcs_bmc_device
*kcs_bmc
, u8 data
)
45 kcs_bmc
->ops
->io_outputb(kcs_bmc
, kcs_bmc
->ioreg
.str
, data
);
47 EXPORT_SYMBOL(kcs_bmc_write_status
);
49 void kcs_bmc_update_status(struct kcs_bmc_device
*kcs_bmc
, u8 mask
, u8 val
)
51 kcs_bmc
->ops
->io_updateb(kcs_bmc
, kcs_bmc
->ioreg
.str
, mask
, val
);
53 EXPORT_SYMBOL(kcs_bmc_update_status
);
55 irqreturn_t
kcs_bmc_handle_event(struct kcs_bmc_device
*kcs_bmc
)
57 struct kcs_bmc_client
*client
;
58 irqreturn_t rc
= IRQ_NONE
;
61 spin_lock_irqsave(&kcs_bmc
->lock
, flags
);
62 client
= kcs_bmc
->client
;
64 rc
= client
->ops
->event(client
);
65 spin_unlock_irqrestore(&kcs_bmc
->lock
, flags
);
69 EXPORT_SYMBOL(kcs_bmc_handle_event
);
71 int kcs_bmc_enable_device(struct kcs_bmc_device
*kcs_bmc
, struct kcs_bmc_client
*client
)
75 spin_lock_irq(&kcs_bmc
->lock
);
76 if (kcs_bmc
->client
) {
79 u8 mask
= KCS_BMC_EVENT_TYPE_IBF
;
81 kcs_bmc
->client
= client
;
82 kcs_bmc_update_event_mask(kcs_bmc
, mask
, mask
);
85 spin_unlock_irq(&kcs_bmc
->lock
);
89 EXPORT_SYMBOL(kcs_bmc_enable_device
);
91 void kcs_bmc_disable_device(struct kcs_bmc_device
*kcs_bmc
, struct kcs_bmc_client
*client
)
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
;
97 kcs_bmc_update_event_mask(kcs_bmc
, mask
, 0);
98 kcs_bmc
->client
= NULL
;
100 spin_unlock_irq(&kcs_bmc
->lock
);
102 EXPORT_SYMBOL(kcs_bmc_disable_device
);
104 int kcs_bmc_add_device(struct kcs_bmc_device
*kcs_bmc
)
106 struct kcs_bmc_driver
*drv
;
110 spin_lock_init(&kcs_bmc
->lock
);
111 kcs_bmc
->client
= NULL
;
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
);
120 dev_err(kcs_bmc
->dev
, "Failed to add chardev for KCS channel %d: %d",
121 kcs_bmc
->channel
, rc
);
124 mutex_unlock(&kcs_bmc_lock
);
128 EXPORT_SYMBOL(kcs_bmc_add_device
);
130 void kcs_bmc_remove_device(struct kcs_bmc_device
*kcs_bmc
)
132 struct kcs_bmc_driver
*drv
;
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
);
140 dev_err(kcs_bmc
->dev
, "Failed to remove chardev for KCS channel %d: %d",
141 kcs_bmc
->channel
, rc
);
143 mutex_unlock(&kcs_bmc_lock
);
145 EXPORT_SYMBOL(kcs_bmc_remove_device
);
147 void kcs_bmc_register_driver(struct kcs_bmc_driver
*drv
)
149 struct kcs_bmc_device
*kcs_bmc
;
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
);
157 dev_err(kcs_bmc
->dev
, "Failed to add driver for KCS channel %d: %d",
158 kcs_bmc
->channel
, rc
);
160 mutex_unlock(&kcs_bmc_lock
);
162 EXPORT_SYMBOL(kcs_bmc_register_driver
);
164 void kcs_bmc_unregister_driver(struct kcs_bmc_driver
*drv
)
166 struct kcs_bmc_device
*kcs_bmc
;
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
);
174 dev_err(kcs_bmc
->dev
, "Failed to remove driver for KCS channel %d: %d",
175 kcs_bmc
->channel
, rc
);
177 mutex_unlock(&kcs_bmc_lock
);
179 EXPORT_SYMBOL(kcs_bmc_unregister_driver
);
181 void kcs_bmc_update_event_mask(struct kcs_bmc_device
*kcs_bmc
, u8 mask
, u8 events
)
183 kcs_bmc
->ops
->irq_mask_update(kcs_bmc
, mask
, events
);
185 EXPORT_SYMBOL(kcs_bmc_update_event_mask
);
187 MODULE_LICENSE("GPL v2");
188 MODULE_AUTHOR("Haiyue Wang <haiyue.wang@linux.intel.com>");
189 MODULE_AUTHOR("Andrew Jeffery <andrew@aj.id.au>");
190 MODULE_DESCRIPTION("KCS BMC to handle the IPMI request from system software");