summaryrefslogtreecommitdiff
path: root/src/drivers/ipmi/ocp/ipmi_ocp.c
blob: f96ce24cddff7c091166f0e295d4714fc14a3b2e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Place in devicetree.cb:
 *
 * chip drivers/ipmi/ocp # OCP specific IPMI porting
	device pnp ca2.1 on end
 * end
 */

#include <console/console.h>
#include <device/device.h>
#include <device/pnp.h>
#include <string.h>
#include <intelblocks/cpulib.h>
#include <arch/cpu.h>
#include "chip.h"
#include "drivers/ipmi/ipmi_kcs.h"
#include "ipmi_ocp.h"

static int ipmi_set_processor_information_param1(struct device *dev)
{
	int ret;
	struct ipmi_processor_info_param1_req req1 = {0};
	struct ipmi_rsp rsp;
	int mfid = CONFIG_IPMI_OCP_MANU_ID;

	memcpy(&req1.data.manufacturer_id, &mfid, 3);
	printk(BIOS_DEBUG, "IPMI BMC manufacturer id: %02x%02x%02x\n",
		req1.data.manufacturer_id[2], req1.data.manufacturer_id[1],
		req1.data.manufacturer_id[0]);

	req1.data.index = 0;
	req1.data.parameter_selector = 1;

	/* Get processor name. */
	fill_processor_name(req1.product_name);
	printk(BIOS_DEBUG, "IPMI BMC CPU NAME: %s.\n", req1.product_name);

	ret = ipmi_kcs_message(dev->path.pnp.port, IPMI_NETFN_OEM_COMMON, 0,
				 IPMI_BMC_SET_PROCESSOR_INFORMATION, (u8 *) &req1,
				 sizeof(req1), (u8 *) &rsp, sizeof(rsp));

	if (ret < sizeof(struct ipmi_rsp) || rsp.completion_code) {
		printk(BIOS_ERR, "IPMI BMC: %s command failed (ret=%d rsp=0x%x)\n",
		       __func__, ret, rsp.completion_code);
		return CB_ERR;
	}
	return CB_SUCCESS;
}

static int ipmi_set_processor_information_param2(struct device *dev)
{
	int ret;
	struct ipmi_processor_info_param2_req req2 = {0};
	struct ipmi_rsp rsp;
	uint8_t stepping_id;
	int mfid = CONFIG_IPMI_OCP_MANU_ID;
	unsigned int core_count, thread_count;
	struct cpuinfo_x86 c;

	memcpy(&req2.data.manufacturer_id, &mfid, 3);
	printk(BIOS_DEBUG, "IPMI BMC manufacturer id: %02x%02x%02x\n",
		req2.data.manufacturer_id[2], req2.data.manufacturer_id[1],
		req2.data.manufacturer_id[0]);

	req2.data.index = 0;
	req2.data.parameter_selector = 2;

	/* Get core number and thread number. */
	cpu_read_topology(&core_count, &thread_count);
	req2.core_number = core_count;
	req2.thread_number = thread_count;
	printk(BIOS_DEBUG, "IPMI BMC CPU has %u cores, %u threads enabled.\n",
	       req2.core_number, req2.thread_number);

	/* Get processor frequency. */
	req2.processor_freq = 100 * cpu_get_max_ratio();
	printk(BIOS_DEBUG, "IPMI BMC CPU frequency is %u MHz.\n",
	       req2.processor_freq);

	/* Get revision. */
	get_fms(&c, cpuid_eax(1));
	stepping_id = c.x86_mask;
	printk(BIOS_DEBUG, "IPMI BMC CPU stepping id is %x.\n", stepping_id);
	switch (stepping_id) {
	/* TBD */
	case 0x0a:
		req2.revision[0] = 'A';
		req2.revision[1] = '0';
		break;
	default:
		req2.revision[0] = 'X';
		req2.revision[1] = 'X';
	}

	ret = ipmi_kcs_message(dev->path.pnp.port, IPMI_NETFN_OEM_COMMON, 0,
				 IPMI_BMC_SET_PROCESSOR_INFORMATION, (u8 *) &req2,
				 sizeof(req2), (u8 *) &rsp, sizeof(rsp));

	if (ret < sizeof(struct ipmi_rsp) || rsp.completion_code) {
		printk(BIOS_ERR, "IPMI: %s command failed (ret=%d rsp=0x%x)\n",
		       __func__, ret, rsp.completion_code);
		return CB_ERR;
	}
	return CB_SUCCESS;
}

static void ipmi_set_processor_information(struct device *dev)
{
	if (ipmi_set_processor_information_param1(dev))
		printk(BIOS_ERR, "IPMI BMC set param 1 processor info failed\n");

	if (ipmi_set_processor_information_param2(dev))
		printk(BIOS_ERR, "IPMI BMC set param 2 processor info failed\n");
}

static void ipmi_ocp_init(struct device *dev)
{
	/* Add OCP specific IPMI command */
}

static void ipmi_ocp_final(struct device *dev)
{
	/* Add OCP specific IPMI command */

	/* Send processor information */
	ipmi_set_processor_information(dev);
}

static void ipmi_set_resources(struct device *dev)
{
	struct resource *res;

	for (res = dev->resource_list; res; res = res->next) {
		if (!(res->flags & IORESOURCE_ASSIGNED))
			continue;

		res->flags |= IORESOURCE_STORED;
		report_resource_stored(dev, res, "");
	}
}

static void ipmi_read_resources(struct device *dev)
{
	struct resource *res = new_resource(dev, 0);
	res->base = dev->path.pnp.port;
	res->size = 2;
	res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED | IORESOURCE_FIXED;
}

static struct device_operations ops = {
	.read_resources   = ipmi_read_resources,
	.set_resources    = ipmi_set_resources,
	.init             = ipmi_ocp_init,
	.final            = ipmi_ocp_final,
};

static void enable_dev(struct device *dev)
{
	if (dev->path.type != DEVICE_PATH_PNP)
		printk(BIOS_ERR, "%s: Unsupported device type\n",
		       dev_path(dev));
	else if (dev->path.pnp.port & 1)
		printk(BIOS_ERR, "%s: Base address needs to be aligned to 2\n",
		       dev_path(dev));
	else
		dev->ops = &ops;
}

struct chip_operations drivers_ipmi_ocp_ops = {
	CHIP_NAME("IPMI OCP")
	.enable_dev = enable_dev,
};