Skip to content

Commit 76415c7

Browse files
author
Willy Liu
committed
[ACCTON][AS9947-72XKB] Modularize IPMI-Related functions
1. Add ipmi interface common code 2. Remove the ipmi codebase from each device driver 3. Remove ipmi PSU device index 4. Fix the each device functions because there is no PSU index 5. Fix functions of psu status and string accessing 6. Fix function of psu hwmon index accessing Signed-off-by: Willy Liu <willy@accton.com>
1 parent 6e2262b commit 76415c7

File tree

14 files changed

+388
-939
lines changed

14 files changed

+388
-939
lines changed

packages/platforms/accton/x86-64/as9947-72xkb/modules/builds/src/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
obj-m += accton_ipmi_intf.o
12
obj-m += x86-64-accton-as9947-72xkb-i2c-ocores.o
23
obj-m += x86-64-accton-as9947-72xkb-fpga.o
34
obj-m += x86-64-accton-as9947-72xkb-fan.o
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2+
/*
3+
* Copyright 2024 Accton Technology Corporation.
4+
*
5+
* This program is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation; either version 2 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
*
16+
* Description:
17+
* IPMI driver related interface implementation
18+
*/
19+
#include <linux/module.h>
20+
#include <linux/init.h>
21+
#include <linux/string_helpers.h>
22+
#include "accton_ipmi_intf.h"
23+
24+
#define ACCTON_IPMI_NETFN 0x34
25+
#define IPMI_TIMEOUT (5 * HZ)
26+
#define IPMI_ERR_RETRY_TIMES 1
27+
#define RAW_CMD_BUF_SIZE 32
28+
29+
static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data);
30+
31+
/* Functions to talk to the IPMI layer */
32+
33+
/* Initialize IPMI data structure and create a user interface for communication */
34+
int init_ipmi_data(struct ipmi_data *ipmi, int iface, struct device *dev)
35+
{
36+
int err;
37+
38+
if (!ipmi || !dev)
39+
return -EINVAL;
40+
41+
init_completion(&ipmi->read_complete);
42+
43+
// Initialize IPMI address
44+
ipmi->address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
45+
ipmi->address.channel = IPMI_BMC_CHANNEL;
46+
ipmi->address.data[0] = 0;
47+
ipmi->interface = iface;
48+
ipmi->dev = dev; // Storing the device for future reference
49+
50+
// Initialize message buffers
51+
ipmi->tx_msgid = 0;
52+
ipmi->tx_message.netfn = ACCTON_IPMI_NETFN;
53+
54+
// Assign the message handler
55+
ipmi->ipmi_hndlrs.ipmi_recv_hndl = ipmi_msg_handler;
56+
57+
// Create IPMI messaging interface user
58+
err = ipmi_create_user(ipmi->interface, &ipmi->ipmi_hndlrs,
59+
ipmi, &ipmi->user);
60+
if (err < 0) {
61+
dev_err(dev,
62+
"Unable to register user with IPMI interface %d, err: %d\n",
63+
ipmi->interface, err);
64+
return err;
65+
}
66+
67+
return 0;
68+
}
69+
EXPORT_SYMBOL(init_ipmi_data);
70+
71+
/* Handler function for receiving IPMI messages */
72+
static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data)
73+
{
74+
unsigned short rx_len;
75+
struct ipmi_data *ipmi = user_msg_data;
76+
77+
// Check for message ID mismatch
78+
if (msg->msgid != ipmi->tx_msgid) {
79+
dev_err(ipmi->dev, "Mismatch between received msgid "
80+
"(%02x) and transmitted msgid (%02x)!\n",
81+
(int)msg->msgid, (int)ipmi->tx_msgid);
82+
ipmi_free_recv_msg(msg);
83+
return;
84+
}
85+
86+
// Handle received message type
87+
ipmi->rx_recv_type = msg->recv_type;
88+
89+
// Parse message data
90+
if (msg->msg.data_len > 0)
91+
ipmi->rx_result = msg->msg.data[0];
92+
else
93+
ipmi->rx_result = IPMI_UNKNOWN_ERR_COMPLETION_CODE;
94+
95+
// Copy remaining message data if available
96+
if (msg->msg.data_len > 1) {
97+
rx_len = msg->msg.data_len - 1;
98+
if (ipmi->rx_msg_len < rx_len)
99+
rx_len = ipmi->rx_msg_len;
100+
101+
ipmi->rx_msg_len = rx_len;
102+
memcpy(ipmi->rx_msg_data, msg->msg.data + 1, ipmi->rx_msg_len);
103+
} else {
104+
ipmi->rx_msg_len = 0;
105+
}
106+
107+
// Free the received message and signal completion
108+
ipmi_free_recv_msg(msg);
109+
complete(&ipmi->read_complete);
110+
}
111+
112+
static void _ipmi_log_error(struct ipmi_data *ipmi, unsigned char cmd,
113+
unsigned char *tx_data, unsigned short tx_len,
114+
int status, int retry)
115+
{
116+
int i, pos;
117+
char *cmdline = NULL;
118+
char raw_cmd[RAW_CMD_BUF_SIZE] = { 0 };
119+
120+
// Format the command and data into a raw command string
121+
pos = snprintf(raw_cmd, sizeof(raw_cmd), "0x%02x", cmd);
122+
for (i = 0; i < tx_len && pos < sizeof(raw_cmd); i++) {
123+
pos += snprintf(raw_cmd + pos, sizeof(raw_cmd) - pos,
124+
" 0x%02x", tx_data[i]);
125+
}
126+
127+
// Log the error message
128+
cmdline = kstrdup_quotable_cmdline(current, GFP_KERNEL);
129+
dev_err(ipmi->dev,
130+
"ipmi_send_message: retry(%d), error(%d), cmd(%s) raw_cmd=[%s]\r\n",
131+
retry, status, cmdline ? cmdline : "", raw_cmd);
132+
133+
if (cmdline) {
134+
kfree(cmdline);
135+
}
136+
}
137+
138+
/* Send an IPMI command */
139+
static int _ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd,
140+
unsigned char *tx_data, unsigned short tx_len,
141+
unsigned char *rx_data, unsigned short rx_len)
142+
{
143+
int err;
144+
145+
// Validate the input parameters
146+
if ((tx_len && !tx_data) || (rx_len && !rx_data)) {
147+
return -EINVAL;
148+
}
149+
150+
// Initialize IPMI message
151+
ipmi->tx_message.cmd = cmd;
152+
ipmi->tx_message.data = tx_len ? tx_data : NULL;
153+
ipmi->tx_message.data_len = tx_len;
154+
ipmi->rx_msg_data = rx_len ? rx_data : NULL;
155+
ipmi->rx_msg_len = rx_len;
156+
157+
// Validate the IPMI address
158+
err = ipmi_validate_addr(&ipmi->address, sizeof(ipmi->address));
159+
if (err) {
160+
dev_err(ipmi->dev, "Invalid IPMI address: %x\n", err);
161+
return err;
162+
}
163+
164+
// Increment message ID and send the request
165+
ipmi->tx_msgid++;
166+
err = ipmi_request_settime(ipmi->user, &ipmi->address, ipmi->tx_msgid,
167+
&ipmi->tx_message, ipmi, 0, 0, 0);
168+
if (err) {
169+
dev_err(ipmi->dev, "IPMI request_settime failed: %x\n", err);
170+
return err;
171+
}
172+
173+
// Wait for the message to complete
174+
err = wait_for_completion_timeout(&ipmi->read_complete, IPMI_TIMEOUT);
175+
if (!err) {
176+
dev_err(ipmi->dev, "IPMI command timeout\n");
177+
return -ETIMEDOUT;
178+
}
179+
180+
return 0;
181+
}
182+
183+
/* Send an IPMI command to the IPMI device and receive the response */
184+
int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd,
185+
unsigned char *tx_data, unsigned short tx_len,
186+
unsigned char *rx_data, unsigned short rx_len)
187+
{
188+
int status = 0, retry = 0;
189+
190+
// Validate the input parameters
191+
if ((tx_len && !tx_data) || (rx_len && !rx_data)) {
192+
return -EINVAL;
193+
}
194+
195+
for (retry = 0; retry <= IPMI_ERR_RETRY_TIMES; retry++) {
196+
status = _ipmi_send_message(ipmi, cmd, tx_data, tx_len, rx_data, rx_len);
197+
if (unlikely(status != 0)) {
198+
_ipmi_log_error(ipmi, cmd, tx_data, tx_len, status, retry);
199+
continue;
200+
}
201+
202+
if (unlikely(ipmi->rx_result != 0)) {
203+
_ipmi_log_error(ipmi, cmd, tx_data, tx_len, status, retry);
204+
continue;
205+
}
206+
207+
// Success, exit the retry loop
208+
break;
209+
}
210+
211+
return status;
212+
}
213+
214+
EXPORT_SYMBOL(ipmi_send_message);
215+
216+
static int __init ipmi_module_init(void)
217+
{
218+
printk(KERN_INFO "Accton IPMI Module loaded\n");
219+
return 0;
220+
}
221+
222+
static void __exit ipmi_module_exit(void)
223+
{
224+
printk(KERN_INFO "Accton IPMI Module unloaded\n");
225+
}
226+
227+
module_init(ipmi_module_init);
228+
module_exit(ipmi_module_exit);
229+
230+
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
231+
MODULE_DESCRIPTION("Accton IPMI messaging module");
232+
MODULE_LICENSE("GPL");
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2+
/*
3+
* Copyright 2024 Accton Technology Corporation.
4+
*
5+
* This program is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation; either version 2 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
*
16+
* Description:
17+
* IPMI driver related interface declarations
18+
*/
19+
20+
#ifndef ACCTON_IPMI_INTF_H
21+
#define ACCTON_IPMI_INTF_H
22+
23+
#include <linux/ipmi.h>
24+
#include <linux/ipmi_smi.h>
25+
26+
/* Structure to hold IPMI (Intelligent Platform Management Interface) data */
27+
struct ipmi_data {
28+
struct completion read_complete; // Synchronization primitive for signaling message read completion
29+
struct ipmi_addr address; // Structure to store the IPMI system interface address
30+
struct ipmi_user *user; // Pointer to IPMI user created by the kernel
31+
int interface; // Interface identifier for the IPMI system
32+
33+
struct kernel_ipmi_msg tx_message; // Message structure for sending IPMI commands
34+
long tx_msgid; // Message ID for tracking IPMI message transactions
35+
36+
void *rx_msg_data; // Pointer to buffer for storing received IPMI message data
37+
unsigned short rx_msg_len; // Length of the received IPMI message
38+
unsigned char rx_result; // Result code from the received IPMI message
39+
int rx_recv_type; // Type of the received message (e.g., system interface, LAN, etc.)
40+
41+
struct ipmi_user_hndl ipmi_hndlrs; // IPMI handler structure for handling incoming IPMI messages
42+
struct device *dev; // Device structure for logging errors
43+
};
44+
45+
/* Function declarations */
46+
47+
/*
48+
* Initialize IPMI data structure and create a user interface for communication.
49+
*
50+
* @param ipmi: Pointer to ipmi_data structure to be initialized.
51+
* @param iface: IPMI interface identifier.
52+
* @param dev: Device structure for logging errors.
53+
* @return 0 on success, or an error code on failure.
54+
*/
55+
extern int init_ipmi_data(struct ipmi_data *ipmi, int iface, struct device *dev);
56+
57+
/*
58+
* Send an IPMI command to the IPMI device and receive the response.
59+
*
60+
* @param ipmi: Pointer to ipmi_data structure containing IPMI communication information.
61+
* @param cmd: IPMI command byte.
62+
* @param tx_data: Pointer to data buffer for the command payload.
63+
* @param tx_len: Length of the command payload data.
64+
* @param rx_data: Pointer to buffer for storing the response data.
65+
* @param rx_len: Length of the response data buffer.
66+
* @return 0 on success, or an error code on failure.
67+
*/
68+
extern int ipmi_send_message(struct ipmi_data *ipmi, unsigned char cmd,
69+
unsigned char *tx_data, unsigned short tx_len,
70+
unsigned char *rx_data, unsigned short rx_len);
71+
72+
#endif /* ACCTON_IPMI_INTF_H */

0 commit comments

Comments
 (0)