2018-02-02 10:16:10 +08:00
// SPDX-License-Identifier: GPL-2.0
2018-02-26 23:48:14 +08:00
/*
* Copyright ( c ) 2015 - 2018 , Intel Corporation .
2021-06-08 20:17:47 +09:30
* Copyright ( c ) 2021 , IBM Corp .
2018-02-26 23:48:14 +08:00
*/
2018-02-02 10:16:10 +08:00
2021-06-08 20:17:48 +09:30
# include <linux/device.h>
2021-06-08 20:17:49 +09:30
# include <linux/list.h>
2018-02-02 10:16:10 +08:00
# include <linux/module.h>
2021-06-08 20:17:49 +09:30
# include <linux/mutex.h>
2018-02-02 10:16:10 +08:00
# include "kcs_bmc.h"
2021-06-08 20:17:47 +09:30
/* Implement both the device and client interfaces here */
# include "kcs_bmc_device.h"
# include "kcs_bmc_client.h"
2021-06-08 20:17:49 +09:30
/* Record registered devices and drivers */
static DEFINE_MUTEX ( kcs_bmc_lock ) ;
static LIST_HEAD ( kcs_bmc_devices ) ;
static LIST_HEAD ( kcs_bmc_drivers ) ;
2021-06-08 20:17:47 +09:30
/* Consumer data access */
2021-06-08 20:17:48 +09:30
u8 kcs_bmc_read_data ( struct kcs_bmc_device * kcs_bmc )
2018-02-02 10:16:10 +08:00
{
2021-06-08 20:17:47 +09:30
return kcs_bmc - > ops - > io_inputb ( kcs_bmc , kcs_bmc - > ioreg . idr ) ;
2018-02-02 10:16:10 +08:00
}
2021-06-08 20:17:45 +09:30
EXPORT_SYMBOL ( kcs_bmc_read_data ) ;
2018-02-02 10:16:10 +08:00
2021-06-08 20:17:48 +09:30
void kcs_bmc_write_data ( struct kcs_bmc_device * kcs_bmc , u8 data )
2018-02-02 10:16:10 +08:00
{
2021-06-08 20:17:47 +09:30
kcs_bmc - > ops - > io_outputb ( kcs_bmc , kcs_bmc - > ioreg . odr , data ) ;
2018-02-02 10:16:10 +08:00
}
2021-06-08 20:17:45 +09:30
EXPORT_SYMBOL ( kcs_bmc_write_data ) ;
2018-02-02 10:16:10 +08:00
2021-06-08 20:17:48 +09:30
u8 kcs_bmc_read_status ( struct kcs_bmc_device * kcs_bmc )
2018-02-02 10:16:10 +08:00
{
2021-06-08 20:17:47 +09:30
return kcs_bmc - > ops - > io_inputb ( kcs_bmc , kcs_bmc - > ioreg . str ) ;
2018-02-02 10:16:10 +08:00
}
2021-06-08 20:17:45 +09:30
EXPORT_SYMBOL ( kcs_bmc_read_status ) ;
2018-02-02 10:16:10 +08:00
2021-06-08 20:17:48 +09:30
void kcs_bmc_write_status ( struct kcs_bmc_device * kcs_bmc , u8 data )
2018-02-02 10:16:10 +08:00
{
2021-06-08 20:17:47 +09:30
kcs_bmc - > ops - > io_outputb ( kcs_bmc , kcs_bmc - > ioreg . str , data ) ;
2018-02-02 10:16:10 +08:00
}
2021-06-08 20:17:45 +09:30
EXPORT_SYMBOL ( kcs_bmc_write_status ) ;
2018-02-02 10:16:10 +08:00
2021-06-08 20:17:48 +09:30
void kcs_bmc_update_status ( struct kcs_bmc_device * kcs_bmc , u8 mask , u8 val )
2018-02-02 10:16:10 +08:00
{
2021-06-08 20:17:47 +09:30
kcs_bmc - > ops - > io_updateb ( kcs_bmc , kcs_bmc - > ioreg . str , mask , val ) ;
2018-02-02 10:16:10 +08:00
}
2021-06-08 20:17:45 +09:30
EXPORT_SYMBOL ( kcs_bmc_update_status ) ;
2018-02-02 10:16:10 +08:00
2021-06-08 20:17:48 +09:30
irqreturn_t kcs_bmc_handle_event ( struct kcs_bmc_device * kcs_bmc )
2018-02-02 10:16:10 +08:00
{
2021-06-08 20:17:48 +09:30
struct kcs_bmc_client * client ;
2021-06-08 20:17:51 +09:30
irqreturn_t rc = IRQ_NONE ;
2021-06-08 20:17:48 +09:30
spin_lock ( & kcs_bmc - > lock ) ;
client = kcs_bmc - > client ;
2021-06-08 20:17:51 +09:30
if ( client )
2021-06-08 20:17:48 +09:30
rc = client - > ops - > event ( client ) ;
spin_unlock ( & kcs_bmc - > lock ) ;
return rc ;
2018-02-02 10:16:10 +08:00
}
EXPORT_SYMBOL ( kcs_bmc_handle_event ) ;
2021-06-08 20:17:48 +09:30
int kcs_bmc_enable_device ( struct kcs_bmc_device * kcs_bmc , struct kcs_bmc_client * client )
{
int rc ;
spin_lock_irq ( & kcs_bmc - > lock ) ;
if ( kcs_bmc - > client ) {
rc = - EBUSY ;
} else {
2021-06-08 20:17:51 +09:30
u8 mask = KCS_BMC_EVENT_TYPE_IBF ;
2021-06-08 20:17:48 +09:30
kcs_bmc - > client = client ;
2021-06-08 20:17:51 +09:30
kcs_bmc_update_event_mask ( kcs_bmc , mask , mask ) ;
2021-06-08 20:17:48 +09:30
rc = 0 ;
}
spin_unlock_irq ( & kcs_bmc - > lock ) ;
return rc ;
}
EXPORT_SYMBOL ( kcs_bmc_enable_device ) ;
void kcs_bmc_disable_device ( struct kcs_bmc_device * kcs_bmc , struct kcs_bmc_client * client )
{
spin_lock_irq ( & kcs_bmc - > lock ) ;
2021-06-08 20:17:51 +09:30
if ( client = = kcs_bmc - > client ) {
u8 mask = KCS_BMC_EVENT_TYPE_IBF | KCS_BMC_EVENT_TYPE_OBE ;
kcs_bmc_update_event_mask ( kcs_bmc , mask , 0 ) ;
2021-06-08 20:17:48 +09:30
kcs_bmc - > client = NULL ;
2021-06-08 20:17:51 +09:30
}
2021-06-08 20:17:48 +09:30
spin_unlock_irq ( & kcs_bmc - > lock ) ;
}
EXPORT_SYMBOL ( kcs_bmc_disable_device ) ;
int kcs_bmc_add_device ( struct kcs_bmc_device * kcs_bmc )
2018-02-02 10:16:10 +08:00
{
2021-06-08 20:17:49 +09:30
struct kcs_bmc_driver * drv ;
int error = 0 ;
int rc ;
spin_lock_init ( & kcs_bmc - > lock ) ;
kcs_bmc - > client = NULL ;
mutex_lock ( & kcs_bmc_lock ) ;
list_add ( & kcs_bmc - > entry , & kcs_bmc_devices ) ;
list_for_each_entry ( drv , & kcs_bmc_drivers , entry ) {
rc = drv - > ops - > add_device ( kcs_bmc ) ;
if ( ! rc )
continue ;
dev_err ( kcs_bmc - > dev , " Failed to add chardev for KCS channel %d: %d " ,
kcs_bmc - > channel , rc ) ;
error = rc ;
}
mutex_unlock ( & kcs_bmc_lock ) ;
return error ;
2018-02-02 10:16:10 +08:00
}
2021-06-08 20:17:46 +09:30
EXPORT_SYMBOL ( kcs_bmc_add_device ) ;
2021-06-08 20:17:48 +09:30
void kcs_bmc_remove_device ( struct kcs_bmc_device * kcs_bmc )
2021-06-08 20:17:46 +09:30
{
2021-06-08 20:17:49 +09:30
struct kcs_bmc_driver * drv ;
int rc ;
mutex_lock ( & kcs_bmc_lock ) ;
list_del ( & kcs_bmc - > entry ) ;
list_for_each_entry ( drv , & kcs_bmc_drivers , entry ) {
rc = drv - > ops - > remove_device ( kcs_bmc ) ;
if ( rc )
dev_err ( kcs_bmc - > dev , " Failed to remove chardev for KCS channel %d: %d " ,
kcs_bmc - > channel , rc ) ;
}
mutex_unlock ( & kcs_bmc_lock ) ;
2021-06-08 20:17:46 +09:30
}
EXPORT_SYMBOL ( kcs_bmc_remove_device ) ;
2018-02-02 10:16:10 +08:00
2021-06-08 20:17:49 +09:30
void kcs_bmc_register_driver ( struct kcs_bmc_driver * drv )
{
struct kcs_bmc_device * kcs_bmc ;
int rc ;
mutex_lock ( & kcs_bmc_lock ) ;
list_add ( & drv - > entry , & kcs_bmc_drivers ) ;
list_for_each_entry ( kcs_bmc , & kcs_bmc_devices , entry ) {
rc = drv - > ops - > add_device ( kcs_bmc ) ;
if ( rc )
dev_err ( kcs_bmc - > dev , " Failed to add driver for KCS channel %d: %d " ,
kcs_bmc - > channel , rc ) ;
}
mutex_unlock ( & kcs_bmc_lock ) ;
}
EXPORT_SYMBOL ( kcs_bmc_register_driver ) ;
void kcs_bmc_unregister_driver ( struct kcs_bmc_driver * drv )
{
struct kcs_bmc_device * kcs_bmc ;
int rc ;
mutex_lock ( & kcs_bmc_lock ) ;
list_del ( & drv - > entry ) ;
list_for_each_entry ( kcs_bmc , & kcs_bmc_devices , entry ) {
rc = drv - > ops - > remove_device ( kcs_bmc ) ;
if ( rc )
dev_err ( kcs_bmc - > dev , " Failed to remove driver for KCS channel %d: %d " ,
kcs_bmc - > channel , rc ) ;
}
mutex_unlock ( & kcs_bmc_lock ) ;
}
EXPORT_SYMBOL ( kcs_bmc_unregister_driver ) ;
2021-06-08 20:17:50 +09:30
void kcs_bmc_update_event_mask ( struct kcs_bmc_device * kcs_bmc , u8 mask , u8 events )
{
kcs_bmc - > ops - > irq_mask_update ( kcs_bmc , mask , events ) ;
}
EXPORT_SYMBOL ( kcs_bmc_update_event_mask ) ;
2018-02-02 10:16:10 +08:00
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_AUTHOR ( " Haiyue Wang <haiyue.wang@linux.intel.com> " ) ;
2021-06-08 20:17:47 +09:30
MODULE_AUTHOR ( " Andrew Jeffery <andrew@aj.id.au> " ) ;
2018-02-02 10:16:10 +08:00
MODULE_DESCRIPTION ( " KCS BMC to handle the IPMI request from system software " ) ;