Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Add support for IPMB driver

Support receiving IPMB requests on a Satellite MC from the BMC.
Once a response is ready, this driver will send back a response
to the BMC via the IPMB channel.

Signed-off-by: Asmaa Mnebhi <Asmaa@mellanox.com>
Acked-by: vadimp@mellanox.com
Message-Id: <319690553a0da2a1e80b400941341081b383e5f1.1560192707.git.Asmaa@mellanox.com>
[Move the config option to outside the ipmi msghandler, as it's not
dependent on that. Fixed one small whitespace issue.]
Signed-off-by: Corey Minyard <cminyard@mvista.com>

authored by

Asmaa Mnebhi and committed by
Corey Minyard
51bd6f29 3559c327

+476
+103
Documentation/IPMB.txt
··· 1 + ============================== 2 + IPMB Driver for a Satellite MC 3 + ============================== 4 + 5 + The Intelligent Platform Management Bus or IPMB, is an 6 + I2C bus that provides a standardized interconnection between 7 + different boards within a chassis. This interconnection is 8 + between the baseboard management (BMC) and chassis electronics. 9 + IPMB is also associated with the messaging protocol through the 10 + IPMB bus. 11 + 12 + The devices using the IPMB are usually management 13 + controllers that perform management functions such as servicing 14 + the front panel interface, monitoring the baseboard, 15 + hot-swapping disk drivers in the system chassis, etc... 16 + 17 + When an IPMB is implemented in the system, the BMC serves as 18 + a controller to give system software access to the IPMB. The BMC 19 + sends IPMI requests to a device (usually a Satellite Management 20 + Controller or Satellite MC) via IPMB and the device 21 + sends a response back to the BMC. 22 + 23 + For more information on IPMB and the format of an IPMB message, 24 + refer to the IPMB and IPMI specifications. 25 + 26 + IPMB driver for Satellite MC 27 + ---------------------------- 28 + 29 + ipmb-dev-int - This is the driver needed on a Satellite MC to 30 + receive IPMB messages from a BMC and send a response back. 31 + This driver works with the I2C driver and a userspace 32 + program such as OpenIPMI: 33 + 34 + 1) It is an I2C slave backend driver. So, it defines a callback 35 + function to set the Satellite MC as an I2C slave. 36 + This callback function handles the received IPMI requests. 37 + 38 + 2) It defines the read and write functions to enable a user 39 + space program (such as OpenIPMI) to communicate with the kernel. 40 + 41 + 42 + Load the IPMB driver 43 + -------------------- 44 + 45 + The driver needs to be loaded at boot time or manually first. 46 + First, make sure you have the following in your config file: 47 + CONFIG_IPMB_DEVICE_INTERFACE=y 48 + 49 + 1) If you want the driver to be loaded at boot time: 50 + 51 + a) Add this entry to your ACPI table, under the appropriate SMBus: 52 + 53 + Device (SMB0) // Example SMBus host controller 54 + { 55 + Name (_HID, "<Vendor-Specific HID>") // Vendor-Specific HID 56 + Name (_UID, 0) // Unique ID of particular host controller 57 + : 58 + : 59 + Device (IPMB) 60 + { 61 + Name (_HID, "IPMB0001") // IPMB device interface 62 + Name (_UID, 0) // Unique device identifier 63 + } 64 + } 65 + 66 + b) Example for device tree: 67 + 68 + &i2c2 { 69 + status = "okay"; 70 + 71 + ipmb@10 { 72 + compatible = "ipmb-dev"; 73 + reg = <0x10>; 74 + }; 75 + }; 76 + 77 + 2) Manually from Linux: 78 + modprobe ipmb-dev-int 79 + 80 + 81 + Instantiate the device 82 + ---------------------- 83 + 84 + After loading the driver, you can instantiate the device as 85 + described in 'Documentation/i2c/instantiating-devices'. 86 + If you have multiple BMCs, each connected to your Satellite MC via 87 + a different I2C bus, you can instantiate a device for each of 88 + those BMCs. 89 + The name of the instantiated device contains the I2C bus number 90 + associated with it as follows: 91 + 92 + BMC1 ------ IPMB/I2C bus 1 ---------| /dev/ipmb-1 93 + Satellite MC 94 + BMC1 ------ IPMB/I2C bus 2 ---------| /dev/ipmb-2 95 + 96 + For instance, you can instantiate the ipmb-dev-int device from 97 + user space at the 7 bit address 0x10 on bus 2: 98 + 99 + # echo ipmb-dev 0x1010 > /sys/bus/i2c/devices/i2c-2/new_device 100 + 101 + This will create the device file /dev/ipmb-2, which can be accessed 102 + by the user space program. The device needs to be instantiated 103 + before running the user space program.
+8
drivers/char/ipmi/Kconfig
··· 131 131 Provides a driver for the BT (Block Transfer) IPMI interface 132 132 found on Aspeed SOCs (AST2400 and AST2500). The driver 133 133 implements the BMC side of the BT interface. 134 + 135 + config IPMB_DEVICE_INTERFACE 136 + tristate 'IPMB Interface handler' 137 + depends on I2C_SLAVE 138 + help 139 + Provides a driver for a device (Satellite MC) to 140 + receive requests and send responses back to the BMC via 141 + the IPMB interface. This module requires I2C support.
+1
drivers/char/ipmi/Makefile
··· 26 26 obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += bt-bmc.o 27 27 obj-$(CONFIG_ASPEED_KCS_IPMI_BMC) += kcs_bmc_aspeed.o 28 28 obj-$(CONFIG_NPCM7XX_KCS_IPMI_BMC) += kcs_bmc_npcm7xx.o 29 + obj-$(CONFIG_IPMB_DEVICE_INTERFACE) += ipmb_dev_int.o
+364
drivers/char/ipmi/ipmb_dev_int.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + /* 4 + * IPMB driver to receive a request and send a response 5 + * 6 + * Copyright (C) 2019 Mellanox Techologies, Ltd. 7 + * 8 + * This was inspired by Brendan Higgins' ipmi-bmc-bt-i2c driver. 9 + */ 10 + 11 + #include <linux/acpi.h> 12 + #include <linux/errno.h> 13 + #include <linux/i2c.h> 14 + #include <linux/miscdevice.h> 15 + #include <linux/module.h> 16 + #include <linux/mutex.h> 17 + #include <linux/poll.h> 18 + #include <linux/slab.h> 19 + #include <linux/spinlock.h> 20 + #include <linux/wait.h> 21 + 22 + #define MAX_MSG_LEN 128 23 + #define IPMB_REQUEST_LEN_MIN 7 24 + #define NETFN_RSP_BIT_MASK 0x4 25 + #define REQUEST_QUEUE_MAX_LEN 256 26 + 27 + #define IPMB_MSG_LEN_IDX 0 28 + #define RQ_SA_8BIT_IDX 1 29 + #define NETFN_LUN_IDX 2 30 + 31 + #define GET_7BIT_ADDR(addr_8bit) (addr_8bit >> 1) 32 + #define GET_8BIT_ADDR(addr_7bit) ((addr_7bit << 1) & 0xff) 33 + 34 + #define IPMB_MSG_PAYLOAD_LEN_MAX (MAX_MSG_LEN - IPMB_REQUEST_LEN_MIN - 1) 35 + 36 + #define SMBUS_MSG_HEADER_LENGTH 2 37 + #define SMBUS_MSG_IDX_OFFSET (SMBUS_MSG_HEADER_LENGTH + 1) 38 + 39 + struct ipmb_msg { 40 + u8 len; 41 + u8 rs_sa; 42 + u8 netfn_rs_lun; 43 + u8 checksum1; 44 + u8 rq_sa; 45 + u8 rq_seq_rq_lun; 46 + u8 cmd; 47 + u8 payload[IPMB_MSG_PAYLOAD_LEN_MAX]; 48 + /* checksum2 is included in payload */ 49 + } __packed; 50 + 51 + struct ipmb_request_elem { 52 + struct list_head list; 53 + struct ipmb_msg request; 54 + }; 55 + 56 + struct ipmb_dev { 57 + struct i2c_client *client; 58 + struct miscdevice miscdev; 59 + struct ipmb_msg request; 60 + struct list_head request_queue; 61 + atomic_t request_queue_len; 62 + size_t msg_idx; 63 + spinlock_t lock; 64 + wait_queue_head_t wait_queue; 65 + struct mutex file_mutex; 66 + }; 67 + 68 + static inline struct ipmb_dev *to_ipmb_dev(struct file *file) 69 + { 70 + return container_of(file->private_data, struct ipmb_dev, miscdev); 71 + } 72 + 73 + static ssize_t ipmb_read(struct file *file, char __user *buf, size_t count, 74 + loff_t *ppos) 75 + { 76 + struct ipmb_dev *ipmb_dev = to_ipmb_dev(file); 77 + struct ipmb_request_elem *queue_elem; 78 + struct ipmb_msg msg; 79 + ssize_t ret; 80 + 81 + memset(&msg, 0, sizeof(msg)); 82 + 83 + spin_lock_irq(&ipmb_dev->lock); 84 + 85 + while (list_empty(&ipmb_dev->request_queue)) { 86 + spin_unlock_irq(&ipmb_dev->lock); 87 + 88 + if (file->f_flags & O_NONBLOCK) 89 + return -EAGAIN; 90 + 91 + ret = wait_event_interruptible(ipmb_dev->wait_queue, 92 + !list_empty(&ipmb_dev->request_queue)); 93 + if (ret) 94 + return ret; 95 + 96 + spin_lock_irq(&ipmb_dev->lock); 97 + } 98 + 99 + queue_elem = list_first_entry(&ipmb_dev->request_queue, 100 + struct ipmb_request_elem, list); 101 + memcpy(&msg, &queue_elem->request, sizeof(msg)); 102 + list_del(&queue_elem->list); 103 + kfree(queue_elem); 104 + atomic_dec(&ipmb_dev->request_queue_len); 105 + 106 + spin_unlock_irq(&ipmb_dev->lock); 107 + 108 + count = min_t(size_t, count, msg.len + 1); 109 + if (copy_to_user(buf, &msg, count)) 110 + ret = -EFAULT; 111 + 112 + return ret < 0 ? ret : count; 113 + } 114 + 115 + static ssize_t ipmb_write(struct file *file, const char __user *buf, 116 + size_t count, loff_t *ppos) 117 + { 118 + struct ipmb_dev *ipmb_dev = to_ipmb_dev(file); 119 + u8 rq_sa, netf_rq_lun, msg_len; 120 + struct i2c_client rq_client; 121 + u8 msg[MAX_MSG_LEN]; 122 + ssize_t ret; 123 + 124 + if (count > sizeof(msg)) 125 + return -EINVAL; 126 + 127 + if (copy_from_user(&msg, buf, count)) 128 + return -EFAULT; 129 + 130 + if (count < msg[0]) 131 + return -EINVAL; 132 + 133 + rq_sa = GET_7BIT_ADDR(msg[RQ_SA_8BIT_IDX]); 134 + netf_rq_lun = msg[NETFN_LUN_IDX]; 135 + 136 + if (!(netf_rq_lun & NETFN_RSP_BIT_MASK)) 137 + return -EINVAL; 138 + 139 + /* 140 + * subtract rq_sa and netf_rq_lun from the length of the msg passed to 141 + * i2c_smbus_write_block_data_local 142 + */ 143 + msg_len = msg[IPMB_MSG_LEN_IDX] - SMBUS_MSG_HEADER_LENGTH; 144 + 145 + strcpy(rq_client.name, "ipmb_requester"); 146 + rq_client.adapter = ipmb_dev->client->adapter; 147 + rq_client.flags = ipmb_dev->client->flags; 148 + rq_client.addr = rq_sa; 149 + 150 + ret = i2c_smbus_write_block_data(&rq_client, netf_rq_lun, msg_len, 151 + msg + SMBUS_MSG_IDX_OFFSET); 152 + 153 + return ret ? : count; 154 + } 155 + 156 + static unsigned int ipmb_poll(struct file *file, poll_table *wait) 157 + { 158 + struct ipmb_dev *ipmb_dev = to_ipmb_dev(file); 159 + unsigned int mask = POLLOUT; 160 + 161 + mutex_lock(&ipmb_dev->file_mutex); 162 + poll_wait(file, &ipmb_dev->wait_queue, wait); 163 + 164 + if (atomic_read(&ipmb_dev->request_queue_len)) 165 + mask |= POLLIN; 166 + mutex_unlock(&ipmb_dev->file_mutex); 167 + 168 + return mask; 169 + } 170 + 171 + static const struct file_operations ipmb_fops = { 172 + .owner = THIS_MODULE, 173 + .read = ipmb_read, 174 + .write = ipmb_write, 175 + .poll = ipmb_poll, 176 + }; 177 + 178 + /* Called with ipmb_dev->lock held. */ 179 + static void ipmb_handle_request(struct ipmb_dev *ipmb_dev) 180 + { 181 + struct ipmb_request_elem *queue_elem; 182 + 183 + if (atomic_read(&ipmb_dev->request_queue_len) >= 184 + REQUEST_QUEUE_MAX_LEN) 185 + return; 186 + 187 + queue_elem = kmalloc(sizeof(*queue_elem), GFP_ATOMIC); 188 + if (!queue_elem) 189 + return; 190 + 191 + memcpy(&queue_elem->request, &ipmb_dev->request, 192 + sizeof(struct ipmb_msg)); 193 + list_add(&queue_elem->list, &ipmb_dev->request_queue); 194 + atomic_inc(&ipmb_dev->request_queue_len); 195 + wake_up_all(&ipmb_dev->wait_queue); 196 + } 197 + 198 + static u8 ipmb_verify_checksum1(struct ipmb_dev *ipmb_dev, u8 rs_sa) 199 + { 200 + /* The 8 lsb of the sum is 0 when the checksum is valid */ 201 + return (rs_sa + ipmb_dev->request.netfn_rs_lun + 202 + ipmb_dev->request.checksum1); 203 + } 204 + 205 + static bool is_ipmb_request(struct ipmb_dev *ipmb_dev, u8 rs_sa) 206 + { 207 + if (ipmb_dev->msg_idx >= IPMB_REQUEST_LEN_MIN) { 208 + if (ipmb_verify_checksum1(ipmb_dev, rs_sa)) 209 + return false; 210 + 211 + /* 212 + * Check whether this is an IPMB request or 213 + * response. 214 + * The 6 MSB of netfn_rs_lun are dedicated to the netfn 215 + * while the remaining bits are dedicated to the lun. 216 + * If the LSB of the netfn is cleared, it is associated 217 + * with an IPMB request. 218 + * If the LSB of the netfn is set, it is associated with 219 + * an IPMB response. 220 + */ 221 + if (!(ipmb_dev->request.netfn_rs_lun & NETFN_RSP_BIT_MASK)) 222 + return true; 223 + } 224 + return false; 225 + } 226 + 227 + /* 228 + * The IPMB protocol only supports I2C Writes so there is no need 229 + * to support I2C_SLAVE_READ* events. 230 + * This i2c callback function only monitors IPMB request messages 231 + * and adds them in a queue, so that they can be handled by 232 + * receive_ipmb_request. 233 + */ 234 + static int ipmb_slave_cb(struct i2c_client *client, 235 + enum i2c_slave_event event, u8 *val) 236 + { 237 + struct ipmb_dev *ipmb_dev = i2c_get_clientdata(client); 238 + u8 *buf = (u8 *)&ipmb_dev->request; 239 + unsigned long flags; 240 + 241 + spin_lock_irqsave(&ipmb_dev->lock, flags); 242 + switch (event) { 243 + case I2C_SLAVE_WRITE_REQUESTED: 244 + memset(&ipmb_dev->request, 0, sizeof(ipmb_dev->request)); 245 + ipmb_dev->msg_idx = 0; 246 + 247 + /* 248 + * At index 0, ipmb_msg stores the length of msg, 249 + * skip it for now. 250 + * The len will be populated once the whole 251 + * buf is populated. 252 + * 253 + * The I2C bus driver's responsibility is to pass the 254 + * data bytes to the backend driver; it does not 255 + * forward the i2c slave address. 256 + * Since the first byte in the IPMB message is the 257 + * address of the responder, it is the responsibility 258 + * of the IPMB driver to format the message properly. 259 + * So this driver prepends the address of the responder 260 + * to the received i2c data before the request message 261 + * is handled in userland. 262 + */ 263 + buf[++ipmb_dev->msg_idx] = GET_8BIT_ADDR(client->addr); 264 + break; 265 + 266 + case I2C_SLAVE_WRITE_RECEIVED: 267 + if (ipmb_dev->msg_idx >= sizeof(struct ipmb_msg)) 268 + break; 269 + 270 + buf[++ipmb_dev->msg_idx] = *val; 271 + break; 272 + 273 + case I2C_SLAVE_STOP: 274 + ipmb_dev->request.len = ipmb_dev->msg_idx; 275 + 276 + if (is_ipmb_request(ipmb_dev, GET_8BIT_ADDR(client->addr))) 277 + ipmb_handle_request(ipmb_dev); 278 + break; 279 + 280 + default: 281 + break; 282 + } 283 + spin_unlock_irqrestore(&ipmb_dev->lock, flags); 284 + 285 + return 0; 286 + } 287 + 288 + static int ipmb_probe(struct i2c_client *client, 289 + const struct i2c_device_id *id) 290 + { 291 + struct ipmb_dev *ipmb_dev; 292 + int ret; 293 + 294 + ipmb_dev = devm_kzalloc(&client->dev, sizeof(*ipmb_dev), 295 + GFP_KERNEL); 296 + if (!ipmb_dev) 297 + return -ENOMEM; 298 + 299 + spin_lock_init(&ipmb_dev->lock); 300 + init_waitqueue_head(&ipmb_dev->wait_queue); 301 + atomic_set(&ipmb_dev->request_queue_len, 0); 302 + INIT_LIST_HEAD(&ipmb_dev->request_queue); 303 + 304 + mutex_init(&ipmb_dev->file_mutex); 305 + 306 + ipmb_dev->miscdev.minor = MISC_DYNAMIC_MINOR; 307 + 308 + ipmb_dev->miscdev.name = devm_kasprintf(&client->dev, GFP_KERNEL, 309 + "%s%d", "ipmb-", 310 + client->adapter->nr); 311 + ipmb_dev->miscdev.fops = &ipmb_fops; 312 + ipmb_dev->miscdev.parent = &client->dev; 313 + ret = misc_register(&ipmb_dev->miscdev); 314 + if (ret) 315 + return ret; 316 + 317 + ipmb_dev->client = client; 318 + i2c_set_clientdata(client, ipmb_dev); 319 + ret = i2c_slave_register(client, ipmb_slave_cb); 320 + if (ret) { 321 + misc_deregister(&ipmb_dev->miscdev); 322 + return ret; 323 + } 324 + 325 + return 0; 326 + } 327 + 328 + static int ipmb_remove(struct i2c_client *client) 329 + { 330 + struct ipmb_dev *ipmb_dev = i2c_get_clientdata(client); 331 + 332 + i2c_slave_unregister(client); 333 + misc_deregister(&ipmb_dev->miscdev); 334 + 335 + return 0; 336 + } 337 + 338 + static const struct i2c_device_id ipmb_id[] = { 339 + { "ipmb-dev", 0 }, 340 + {}, 341 + }; 342 + MODULE_DEVICE_TABLE(i2c, ipmb_id); 343 + 344 + static const struct acpi_device_id acpi_ipmb_id[] = { 345 + { "IPMB0001", 0 }, 346 + {}, 347 + }; 348 + MODULE_DEVICE_TABLE(acpi, acpi_ipmb_id); 349 + 350 + static struct i2c_driver ipmb_driver = { 351 + .driver = { 352 + .owner = THIS_MODULE, 353 + .name = "ipmb-dev", 354 + .acpi_match_table = ACPI_PTR(acpi_ipmb_id), 355 + }, 356 + .probe = ipmb_probe, 357 + .remove = ipmb_remove, 358 + .id_table = ipmb_id, 359 + }; 360 + module_i2c_driver(ipmb_driver); 361 + 362 + MODULE_AUTHOR("Mellanox Technologies"); 363 + MODULE_DESCRIPTION("IPMB driver"); 364 + MODULE_LICENSE("GPL v2");