提交 ef088b8f 编写于 作者: C Chong Qiao 提交者: Hongchen Zhang

ipmi: add ls2k500 bmc ipmi support.

LoongArch inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/I76XQZ

--------------------------------
Signed-off-by: NChong Qiao <qiaochong@loongson.cn>
Signed-off-by: NHongchen Zhang <zhanghongchen@loongson.cn>
Change-Id: Id322a9b63a19a2692639ef81af3a45f017339f9a
上级 d74f3b70
......@@ -13,6 +13,10 @@ ifdef CONFIG_PARISC
ipmi_si-y += ipmi_si_parisc.o
endif
ifdef CONFIG_LOONGARCH
ipmi_si-y += ipmi_si_ls2k500.o
endif
obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
obj-$(CONFIG_IPMI_SI) += ipmi_si.o
......
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __BTLOCK_H__
#define __BTLOCK_H__
#include <linux/delay.h>
#include <asm/timex.h>
union btlock {
char b[2];
unsigned int u;
};
/*
*wait delay us if lock failed.
*lock fail if another one get lock or both try get lock.
*c must compile b with byte access.
*/
static inline int btlock_lock(volatile union btlock *p, int n, unsigned char delay)
{
union btlock t, t1;
unsigned long flags;
if (n > 1)
return -1;
delay |= 0x80;
t1.u = 0;
t1.b[n] = delay;
while (1) {
local_irq_save(flags);
p->b[n] = delay;
t.u = p->u;
if (t.u == t1.u) {
wmb(); /* flush write out immediately */
local_irq_restore(flags);
return 0;
}
p->b[n] = 0;
t.u = p->u;
wmb(); /* flush write out immediately */
local_irq_restore(flags);
ndelay(((t.b[1 - n] & 0x7f) + (get_cycles() & 1)) * 100);
}
return 0;
}
static inline int btlock_trylock(volatile union btlock *p, int n, unsigned char delay)
{
union btlock t, t1;
unsigned long flags;
if (n > 1)
return -1;
delay |= 0x80;
t1.u = 0;
t1.b[n] = delay;
local_irq_save(flags);
p->b[n] = delay;
t.u = p->u;
if (t.u == t1.u) {
wmb(); /* flush write out immediately */
local_irq_restore(flags);
return 0;
}
p->b[n] = 0;
t.u = p->u;
wmb(); /* flush write out immediately */
local_irq_restore(flags);
ndelay(((t.b[1 - n] & 0x7f) + (get_cycles() & 1)) * 100);
return -1;
}
static inline int btlock_unlock(volatile union btlock *p, int n)
{
p->b[n] = 0;
wmb(); /* flush write out immediately */
return p->u;
}
static inline int btlock_islocked(volatile union btlock *p, int n)
{
union btlock t;
t.u = p->u;
return t.b[n] && !t.b[1 - n];
}
#endif
......@@ -99,6 +99,14 @@ static inline void ipmi_si_parisc_init(void) { }
static inline void ipmi_si_parisc_shutdown(void) { }
#endif
#ifdef CONFIG_LOONGARCH
int ipmi_si_ls2k500_init(void);
void ipmi_si_ls2k500_shutdown(void);
#else
static inline void ipmi_si_ls2k500_init(void) { }
static inline void ipmi_si_ls2k500_shutdown(void) { }
#endif
int ipmi_si_port_setup(struct si_sm_io *io);
int ipmi_si_mem_setup(struct si_sm_io *io);
......
......@@ -2106,6 +2106,8 @@ static int __init init_ipmi_si(void)
ipmi_si_platform_init();
ipmi_si_ls2k500_init();
ipmi_si_pci_init();
ipmi_si_parisc_init();
......@@ -2291,6 +2293,8 @@ static void cleanup_ipmi_si(void)
ipmi_si_parisc_shutdown();
ipmi_si_ls2k500_shutdown();
ipmi_si_platform_shutdown();
mutex_lock(&smi_infos_lock);
......
// SPDX-License-Identifier: GPL-2.0+
/*
* ipmi_si_pci.c
*
* Handling for IPMI devices on the PCI bus.
*/
#define pr_fmt(fmt) "ipmi_pci: " fmt
#include <linux/module.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/version.h>
#include "ipmi_si.h"
#include "kcs_bmc_ls2k500.h"
#define KCS_STATUS_CMD_DAT BIT(3)
static unsigned char intf_sim_inb(const struct si_sm_io *io,
unsigned int offset)
{
IPMIKCS *ik = io->addr_source_data;
uint32_t ret;
btlock_lock(&ik->lock, 0, 1);
switch (offset & 1) {
case 0:
ret = ik->data_out_reg;
IPMI_KCS_SET_OBF(ik->status_reg, 0);
break;
case 1:
ret = ik->status_reg;
break;
}
btlock_unlock(&ik->lock, 0);
return ret;
}
static void intf_sim_outb(const struct si_sm_io *io, unsigned int offset,
unsigned char val)
{
IPMIKCS *ik = io->addr_source_data;
btlock_lock(&ik->lock, 0, 1);
if (IPMI_KCS_GET_IBF(ik->status_reg))
goto out;
switch (offset & 1) {
case 0:
ik->data_in_reg = val;
ik->status_reg &= ~KCS_STATUS_CMD_DAT;
break;
case 1:
ik->cmd_reg = val;
ik->status_reg |= KCS_STATUS_CMD_DAT;
break;
}
IPMI_KCS_SET_IBF(ik->status_reg, 1);
ik->write_req++;
out:
btlock_unlock(&ik->lock, 0);
}
static void ipmi_ls2k500_cleanup(struct si_sm_io *io)
{
}
int ipmi_si_sim_setup(struct si_sm_io *io)
{
io->inputb = intf_sim_inb;
io->outputb = intf_sim_outb;
io->io_cleanup = ipmi_ls2k500_cleanup;
return 0;
}
#define platform_resource_start(dev, bar) ((dev)->resource[(bar)].start)
#define platform_resource_end(dev, bar) ((dev)->resource[(bar)].end)
static int of_ipmi_ls2k500_probe(struct platform_device *pdev)
{
int rv;
struct si_sm_io io;
memset(&io, 0, sizeof(io));
io.addr_source = SI_PLATFORM;
dev_info(&pdev->dev, "probing via ls2k500 platform");
io.si_type = SI_KCS;
io.addr_source_cleanup = ipmi_ls2k500_cleanup;
io.addr_space = IPMI_MEM_ADDR_SPACE;
io.io_setup = ipmi_si_sim_setup;
io.addr_data = pdev->resource[0].start;
io.addr_source_data = ioremap(pdev->resource[0].start,
pdev->resource[0].end -
pdev->resource[0].start + 1);
io.dev = &pdev->dev;
io.regspacing = 4;
io.regsize = DEFAULT_REGSIZE;
io.regshift = 0;
io.irq = 0;
if (io.irq)
io.irq_setup = ipmi_std_irq_setup;
dev_info(&pdev->dev, "%pR regsize %d spacing %d irq %d\n",
&pdev->resource[0], io.regsize, io.regspacing, io.irq);
rv = ipmi_si_add_smi(&io);
return rv;
}
static int ipmi_ls2k500_remove(struct platform_device *pdev)
{
return ipmi_si_remove_by_dev(&pdev->dev);
}
#define LS2K500_SI_DEVICE_NAME "ipmi_ls2k500_si"
struct platform_driver ipmi_ls2k500_platform_driver = {
.driver = {
.name = LS2K500_SI_DEVICE_NAME,
},
.probe = of_ipmi_ls2k500_probe,
.remove = ipmi_ls2k500_remove,
};
static bool platform_registered;
int ipmi_si_ls2k500_init(void)
{
int rv;
rv = platform_driver_register(&ipmi_ls2k500_platform_driver);
if (rv)
pr_err("Unable to register driver: %d\n", rv);
else
platform_registered = true;
return rv;
}
void ipmi_si_ls2k500_shutdown(void)
{
if (platform_registered)
platform_driver_unregister(&ipmi_ls2k500_platform_driver);
}
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __KCS_BMC_LS2K500__
#define __KCS_BMC_LS2K500__ 1
#include <linux/list.h>
#include "btlock.h"
#define IPMI_KCS_OBF_BIT 0
#define IPMI_KCS_IBF_BIT 1
#define IPMI_KCS_SMS_ATN_BIT 2
#define IPMI_KCS_CD_BIT 3
#define IPMI_KCS_OBF_MASK (1 << IPMI_KCS_OBF_BIT)
#define IPMI_KCS_GET_OBF(d) (((d) >> IPMI_KCS_OBF_BIT) & 0x1)
#define IPMI_KCS_SET_OBF(d, v) ((d) = (((d) & ~IPMI_KCS_OBF_MASK) | \
(((v) & 1) << IPMI_KCS_OBF_BIT)))
#define IPMI_KCS_IBF_MASK (1 << IPMI_KCS_IBF_BIT)
#define IPMI_KCS_GET_IBF(d) (((d) >> IPMI_KCS_IBF_BIT) & 0x1)
#define IPMI_KCS_SET_IBF(d, v) ((d) = (((d) & ~IPMI_KCS_IBF_MASK) | \
(((v) & 1) << IPMI_KCS_IBF_BIT)))
#define IPMI_KCS_SMS_ATN_MASK (1 << IPMI_KCS_SMS_ATN_BIT)
#define IPMI_KCS_GET_SMS_ATN(d) (((d) >> IPMI_KCS_SMS_ATN_BIT) & 0x1)
#define IPMI_KCS_SET_SMS_ATN(d, v) ((d) = (((d) & ~IPMI_KCS_SMS_ATN_MASK) | \
((v) & 1) << IPMI_KCS_SMS_ATN_BIT))
#define IPMI_KCS_CD_MASK (1 << IPMI_KCS_CD_BIT)
#define IPMI_KCS_GET_CD(d) (((d) >> IPMI_KCS_CD_BIT) & 0x1)
#define IPMI_KCS_SET_CD(d, v) ((d) = (((d) & ~IPMI_KCS_CD_MASK) | \
(((v) & 1) << IPMI_KCS_CD_BIT)))
#define IPMI_KCS_IDLE_STATE 0
#define IPMI_KCS_READ_STATE 1
#define IPMI_KCS_WRITE_STATE 2
#define IPMI_KCS_ERROR_STATE 3
#define IPMI_KCS_GET_STATE(d) (((d) >> 6) & 0x3)
#define IPMI_KCS_SET_STATE(d, v) ((d) = ((d) & ~0xc0) | (((v) & 0x3) << 6))
#define IPMI_KCS_ABORT_STATUS_CMD 0x60
#define IPMI_KCS_WRITE_START_CMD 0x61
#define IPMI_KCS_WRITE_END_CMD 0x62
#define IPMI_KCS_READ_CMD 0x68
#define IPMI_KCS_STATUS_NO_ERR 0x00
#define IPMI_KCS_STATUS_ABORTED_ERR 0x01
#define IPMI_KCS_STATUS_BAD_CC_ERR 0x02
#define IPMI_KCS_STATUS_LENGTH_ERR 0x06
#define KCS_STATUS_CMD_DAT BIT(3)
typedef struct IPMIKCS {
union btlock lock;
uint8_t status_reg;
uint8_t data_out_reg;
int16_t data_in_reg;
int16_t cmd_reg;
int16_t reserved2;
uint32_t write_req;
uint32_t write_ack;
uint32_t reserved3;
uint32_t reserved4;
} IPMIKCS;
struct loongson_kcs_bmc {
struct list_head next;
IPMIKCS *kcs;
struct kcs_bmc *bmc;
};
#endif
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册