Unverified Commit e1c4614e authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!1083 LoongArch: fix system hang caused by 2k500 bmc driver

Merge Pull Request from: @Hongchen_Zhang 
 
when we test the 2k500 bmc,the system hang when send the following command:
[loongson@localhost ~]# ipmi mc reset cold

After apply this PR,the problem disappeared. 
 
Link:https://gitee.com/openeuler/kernel/pulls/1083

 

Reviewed-by: default avatarGuo Dongtai <guodongtai@kylinos.cn>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parents d8a73976 b140ebe3
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ static inline int btlock_lock(volatile union btlock *p, int n, unsigned char del
{
	union btlock t, t1;
	unsigned long flags;
	unsigned long c0 = get_cycles(), c1;

	if (n > 1)
		return -1;
@@ -39,7 +40,10 @@ static inline int btlock_lock(volatile union btlock *p, int n, unsigned char del
		t.u = p->u;
		wmb(); /* flush write out immediately */
		local_irq_restore(flags);
		ndelay(((t.b[1 - n] & 0x7f) + (get_cycles() & 1)) * 100);
		c1 = get_cycles();
		if (c1 - c0 > *mscycles * 1000)
			return -1;
		ndelay(((t.b[1 - n] & 0x7f) + (c1 & 1)) * 100);
	}
	return 0;
}
+25 −3
Original line number Diff line number Diff line
@@ -18,17 +18,31 @@
#include <linux/ioport.h>
#include <linux/version.h>
#include "ipmi_si.h"
static unsigned long *mscycles;
static unsigned long *event_jiffies;
#include "kcs_bmc_ls2k500.h"
static int resetbootwait = 60;
module_param(resetbootwait, int, 0664);

#define KCS_STATUS_CMD_DAT      BIT(3)

static int pcie_busy(void)
{
	if (time_before(jiffies, *event_jiffies + resetbootwait*HZ))
		return -1;
	return 0;
}

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);
	if (pcie_busy())
		return 0;
	if (btlock_lock(&ik->lock, 0, 1) < 0)
		return 0;
	switch (offset & 1) {
	case 0:
		ret = ik->data_out_reg;
@@ -47,7 +61,10 @@ static void intf_sim_outb(const struct si_sm_io *io, unsigned int offset,
{
	IPMIKCS *ik = io->addr_source_data;

	btlock_lock(&ik->lock, 0, 1);
	if (pcie_busy())
		return;
	if (btlock_lock(&ik->lock, 0, 1) < 0)
		return;
	if (IPMI_KCS_GET_IBF(ik->status_reg))
		goto out;

@@ -86,7 +103,7 @@ static int of_ipmi_ls2k500_probe(struct platform_device *pdev)
{
	int rv;
	struct si_sm_io io;

	void **kcs_data;
	memset(&io, 0, sizeof(io));
	io.addr_source = SI_PLATFORM;
	dev_info(&pdev->dev, "probing via ls2k500 platform");
@@ -100,6 +117,9 @@ static int of_ipmi_ls2k500_probe(struct platform_device *pdev)
	io.addr_source_data = ioremap(pdev->resource[0].start,
					pdev->resource[0].end -
					pdev->resource[0].start + 1);
	kcs_data = dev_get_platdata(&pdev->dev);
	event_jiffies = kcs_data[0];
	mscycles = kcs_data[1];
	io.dev = &pdev->dev;
	io.regspacing = 4;
	io.regsize = DEFAULT_REGSIZE;
@@ -112,6 +132,8 @@ static int of_ipmi_ls2k500_probe(struct platform_device *pdev)
		&pdev->resource[0], io.regsize, io.regspacing, io.irq);

	rv = ipmi_si_add_smi(&io);
	if (rv)
		ipmi_si_remove_by_dev(&pdev->dev);

	return rv;
}
+5 −1
Original line number Diff line number Diff line
@@ -108,6 +108,7 @@ static void ls2k500sfb_redraw_fn(struct work_struct *work)
	switch_console(saved_console);
}

static unsigned long event_jiffies;
static void ls2k500sfb_events_fn(struct work_struct *work)
{
	struct ls2k500sfb_struct *priv = container_of(work, struct ls2k500sfb_struct, work);
@@ -148,6 +149,7 @@ static void ls2k500sfb_events_fn(struct work_struct *work)
	pci_write_config_dword(ppdev, 0x18, 0);
	pci_write_config_dword(ppdev, 0x1c, 0);
	pci_write_config_dword(ppdev, 0x20, 0);
	event_jiffies = jiffies;
	atomic_set(&waiting_for_pciebreak_ipi, 0);
	wmb(); /* flush all write after change pcie window */
	local_bh_enable();
@@ -645,6 +647,7 @@ static struct platform_driver simplefb_driver = {
	.remove = simplefb_remove,
};

static void *kcs_data[2] = {&event_jiffies, &mscycles};
static int ls2k500sfb_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	struct simplefb_platform_data mode;
@@ -737,7 +740,8 @@ static int ls2k500sfb_probe(struct pci_dev *dev, const struct pci_device_id *id)
	for (i = 0; i < 5; i++) {
		res[0].start = phybase + 0x00f00000 + 0x1c*i;
		res[0].end = phybase + 0x00f00000 + 0x1c*(i+1) - 1;
		platform_device_register_simple("ipmi_ls2k500_si", i, res, 1);
		platform_device_register_resndata(NULL, "ipmi_ls2k500_si", i, res, 1,
						kcs_data, sizeof(kcs_data));
	}

	return PTR_ERR_OR_ZERO(pd);