root/drivers/misc/mei/bus-fixup.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. number_of_connections
  2. blacklist
  3. whitelist
  4. mei_fwver
  5. mei_mkhi_fix
  6. mei_wd
  7. mei_wd
  8. mei_nfc_if_version
  9. mei_nfc_radio_name
  10. mei_nfc
  11. mei_cl_bus_dev_fixup

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (c) 2013-2019, Intel Corporation. All rights reserved.
   4  * Intel Management Engine Interface (Intel MEI) Linux driver
   5  */
   6 
   7 #include <linux/kernel.h>
   8 #include <linux/sched.h>
   9 #include <linux/module.h>
  10 #include <linux/device.h>
  11 #include <linux/slab.h>
  12 #include <linux/uuid.h>
  13 
  14 #include <linux/mei_cl_bus.h>
  15 
  16 #include "mei_dev.h"
  17 #include "client.h"
  18 
  19 #define MEI_UUID_NFC_INFO UUID_LE(0xd2de1625, 0x382d, 0x417d, \
  20                         0x48, 0xa4, 0xef, 0xab, 0xba, 0x8a, 0x12, 0x06)
  21 
  22 static const uuid_le mei_nfc_info_guid = MEI_UUID_NFC_INFO;
  23 
  24 #define MEI_UUID_NFC_HCI UUID_LE(0x0bb17a78, 0x2a8e, 0x4c50, \
  25                         0x94, 0xd4, 0x50, 0x26, 0x67, 0x23, 0x77, 0x5c)
  26 
  27 #define MEI_UUID_WD UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, \
  28                             0x89, 0x9D, 0xA9, 0x15, 0x14, 0xCB, 0x32, 0xAB)
  29 
  30 #define MEI_UUID_MKHIF_FIX UUID_LE(0x55213584, 0x9a29, 0x4916, \
  31                         0xba, 0xdf, 0xf, 0xb7, 0xed, 0x68, 0x2a, 0xeb)
  32 
  33 #define MEI_UUID_HDCP UUID_LE(0xB638AB7E, 0x94E2, 0x4EA2, \
  34                               0xA5, 0x52, 0xD1, 0xC5, 0x4B, 0x62, 0x7F, 0x04)
  35 
  36 #define MEI_UUID_ANY NULL_UUID_LE
  37 
  38 /**
  39  * number_of_connections - determine whether an client be on the bus
  40  *    according number of connections
  41  *    We support only clients:
  42  *       1. with single connection
  43  *       2. and fixed clients (max_number_of_connections == 0)
  44  *
  45  * @cldev: me clients device
  46  */
  47 static void number_of_connections(struct mei_cl_device *cldev)
  48 {
  49         dev_dbg(&cldev->dev, "running hook %s\n", __func__);
  50 
  51         if (cldev->me_cl->props.max_number_of_connections > 1)
  52                 cldev->do_match = 0;
  53 }
  54 
  55 /**
  56  * blacklist - blacklist a client from the bus
  57  *
  58  * @cldev: me clients device
  59  */
  60 static void blacklist(struct mei_cl_device *cldev)
  61 {
  62         dev_dbg(&cldev->dev, "running hook %s\n", __func__);
  63 
  64         cldev->do_match = 0;
  65 }
  66 
  67 /**
  68  * whitelist - forcefully whitelist client
  69  *
  70  * @cldev: me clients device
  71  */
  72 static void whitelist(struct mei_cl_device *cldev)
  73 {
  74         dev_dbg(&cldev->dev, "running hook %s\n", __func__);
  75 
  76         cldev->do_match = 1;
  77 }
  78 
  79 #define OSTYPE_LINUX    2
  80 struct mei_os_ver {
  81         __le16 build;
  82         __le16 reserved1;
  83         u8  os_type;
  84         u8  major;
  85         u8  minor;
  86         u8  reserved2;
  87 } __packed;
  88 
  89 #define MKHI_FEATURE_PTT 0x10
  90 
  91 struct mkhi_rule_id {
  92         __le16 rule_type;
  93         u8 feature_id;
  94         u8 reserved;
  95 } __packed;
  96 
  97 struct mkhi_fwcaps {
  98         struct mkhi_rule_id id;
  99         u8 len;
 100         u8 data[0];
 101 } __packed;
 102 
 103 struct mkhi_fw_ver_block {
 104         u16 minor;
 105         u8 major;
 106         u8 platform;
 107         u16 buildno;
 108         u16 hotfix;
 109 } __packed;
 110 
 111 struct mkhi_fw_ver {
 112         struct mkhi_fw_ver_block ver[MEI_MAX_FW_VER_BLOCKS];
 113 } __packed;
 114 
 115 #define MKHI_FWCAPS_GROUP_ID 0x3
 116 #define MKHI_FWCAPS_SET_OS_VER_APP_RULE_CMD 6
 117 #define MKHI_GEN_GROUP_ID 0xFF
 118 #define MKHI_GEN_GET_FW_VERSION_CMD 0x2
 119 struct mkhi_msg_hdr {
 120         u8  group_id;
 121         u8  command;
 122         u8  reserved;
 123         u8  result;
 124 } __packed;
 125 
 126 struct mkhi_msg {
 127         struct mkhi_msg_hdr hdr;
 128         u8 data[0];
 129 } __packed;
 130 
 131 #define MKHI_OSVER_BUF_LEN (sizeof(struct mkhi_msg_hdr) + \
 132                             sizeof(struct mkhi_fwcaps) + \
 133                             sizeof(struct mei_os_ver))
 134 static int mei_osver(struct mei_cl_device *cldev)
 135 {
 136         const size_t size = MKHI_OSVER_BUF_LEN;
 137         char buf[MKHI_OSVER_BUF_LEN];
 138         struct mkhi_msg *req;
 139         struct mkhi_fwcaps *fwcaps;
 140         struct mei_os_ver *os_ver;
 141         unsigned int mode = MEI_CL_IO_TX_BLOCKING | MEI_CL_IO_TX_INTERNAL;
 142 
 143         memset(buf, 0, size);
 144 
 145         req = (struct mkhi_msg *)buf;
 146         req->hdr.group_id = MKHI_FWCAPS_GROUP_ID;
 147         req->hdr.command = MKHI_FWCAPS_SET_OS_VER_APP_RULE_CMD;
 148 
 149         fwcaps = (struct mkhi_fwcaps *)req->data;
 150 
 151         fwcaps->id.rule_type = 0x0;
 152         fwcaps->id.feature_id = MKHI_FEATURE_PTT;
 153         fwcaps->len = sizeof(*os_ver);
 154         os_ver = (struct mei_os_ver *)fwcaps->data;
 155         os_ver->os_type = OSTYPE_LINUX;
 156 
 157         return __mei_cl_send(cldev->cl, buf, size, mode);
 158 }
 159 
 160 #define MKHI_FWVER_BUF_LEN (sizeof(struct mkhi_msg_hdr) + \
 161                             sizeof(struct mkhi_fw_ver))
 162 #define MKHI_FWVER_LEN(__num) (sizeof(struct mkhi_msg_hdr) + \
 163                                sizeof(struct mkhi_fw_ver_block) * (__num))
 164 #define MKHI_RCV_TIMEOUT 500 /* receive timeout in msec */
 165 static int mei_fwver(struct mei_cl_device *cldev)
 166 {
 167         char buf[MKHI_FWVER_BUF_LEN];
 168         struct mkhi_msg *req;
 169         struct mkhi_fw_ver *fwver;
 170         int bytes_recv, ret, i;
 171 
 172         memset(buf, 0, sizeof(buf));
 173 
 174         req = (struct mkhi_msg *)buf;
 175         req->hdr.group_id = MKHI_GEN_GROUP_ID;
 176         req->hdr.command = MKHI_GEN_GET_FW_VERSION_CMD;
 177 
 178         ret = __mei_cl_send(cldev->cl, buf, sizeof(struct mkhi_msg_hdr),
 179                             MEI_CL_IO_TX_BLOCKING);
 180         if (ret < 0) {
 181                 dev_err(&cldev->dev, "Could not send ReqFWVersion cmd\n");
 182                 return ret;
 183         }
 184 
 185         ret = 0;
 186         bytes_recv = __mei_cl_recv(cldev->cl, buf, sizeof(buf), 0,
 187                                    MKHI_RCV_TIMEOUT);
 188         if (bytes_recv < 0 || (size_t)bytes_recv < MKHI_FWVER_LEN(1)) {
 189                 /*
 190                  * Should be at least one version block,
 191                  * error out if nothing found
 192                  */
 193                 dev_err(&cldev->dev, "Could not read FW version\n");
 194                 return -EIO;
 195         }
 196 
 197         fwver = (struct mkhi_fw_ver *)req->data;
 198         memset(cldev->bus->fw_ver, 0, sizeof(cldev->bus->fw_ver));
 199         for (i = 0; i < MEI_MAX_FW_VER_BLOCKS; i++) {
 200                 if ((size_t)bytes_recv < MKHI_FWVER_LEN(i + 1))
 201                         break;
 202                 dev_dbg(&cldev->dev, "FW version%d %d:%d.%d.%d.%d\n",
 203                         i, fwver->ver[i].platform,
 204                         fwver->ver[i].major, fwver->ver[i].minor,
 205                         fwver->ver[i].hotfix, fwver->ver[i].buildno);
 206 
 207                 cldev->bus->fw_ver[i].platform = fwver->ver[i].platform;
 208                 cldev->bus->fw_ver[i].major = fwver->ver[i].major;
 209                 cldev->bus->fw_ver[i].minor = fwver->ver[i].minor;
 210                 cldev->bus->fw_ver[i].hotfix = fwver->ver[i].hotfix;
 211                 cldev->bus->fw_ver[i].buildno = fwver->ver[i].buildno;
 212         }
 213 
 214         return ret;
 215 }
 216 
 217 static void mei_mkhi_fix(struct mei_cl_device *cldev)
 218 {
 219         int ret;
 220 
 221         /* No need to enable the client if nothing is needed from it */
 222         if (!cldev->bus->fw_f_fw_ver_supported &&
 223             !cldev->bus->hbm_f_os_supported)
 224                 return;
 225 
 226         ret = mei_cldev_enable(cldev);
 227         if (ret)
 228                 return;
 229 
 230         if (cldev->bus->fw_f_fw_ver_supported) {
 231                 ret = mei_fwver(cldev);
 232                 if (ret < 0)
 233                         dev_err(&cldev->dev, "FW version command failed %d\n",
 234                                 ret);
 235         }
 236 
 237         if (cldev->bus->hbm_f_os_supported) {
 238                 ret = mei_osver(cldev);
 239                 if (ret < 0)
 240                         dev_err(&cldev->dev, "OS version command failed %d\n",
 241                                 ret);
 242         }
 243         mei_cldev_disable(cldev);
 244 }
 245 
 246 /**
 247  * mei_wd - wd client on the bus, change protocol version
 248  *   as the API has changed.
 249  *
 250  * @cldev: me clients device
 251  */
 252 #if IS_ENABLED(CONFIG_INTEL_MEI_ME)
 253 #include <linux/pci.h>
 254 #include "hw-me-regs.h"
 255 static void mei_wd(struct mei_cl_device *cldev)
 256 {
 257         struct pci_dev *pdev = to_pci_dev(cldev->dev.parent);
 258 
 259         dev_dbg(&cldev->dev, "running hook %s\n", __func__);
 260         if (pdev->device == MEI_DEV_ID_WPT_LP ||
 261             pdev->device == MEI_DEV_ID_SPT ||
 262             pdev->device == MEI_DEV_ID_SPT_H)
 263                 cldev->me_cl->props.protocol_version = 0x2;
 264 
 265         cldev->do_match = 1;
 266 }
 267 #else
 268 static inline void mei_wd(struct mei_cl_device *cldev) {}
 269 #endif /* CONFIG_INTEL_MEI_ME */
 270 
 271 struct mei_nfc_cmd {
 272         u8 command;
 273         u8 status;
 274         u16 req_id;
 275         u32 reserved;
 276         u16 data_size;
 277         u8 sub_command;
 278         u8 data[];
 279 } __packed;
 280 
 281 struct mei_nfc_reply {
 282         u8 command;
 283         u8 status;
 284         u16 req_id;
 285         u32 reserved;
 286         u16 data_size;
 287         u8 sub_command;
 288         u8 reply_status;
 289         u8 data[];
 290 } __packed;
 291 
 292 struct mei_nfc_if_version {
 293         u8 radio_version_sw[3];
 294         u8 reserved[3];
 295         u8 radio_version_hw[3];
 296         u8 i2c_addr;
 297         u8 fw_ivn;
 298         u8 vendor_id;
 299         u8 radio_type;
 300 } __packed;
 301 
 302 
 303 #define MEI_NFC_CMD_MAINTENANCE 0x00
 304 #define MEI_NFC_SUBCMD_IF_VERSION 0x01
 305 
 306 /* Vendors */
 307 #define MEI_NFC_VENDOR_INSIDE 0x00
 308 #define MEI_NFC_VENDOR_NXP    0x01
 309 
 310 /* Radio types */
 311 #define MEI_NFC_VENDOR_INSIDE_UREAD 0x00
 312 #define MEI_NFC_VENDOR_NXP_PN544    0x01
 313 
 314 /**
 315  * mei_nfc_if_version - get NFC interface version
 316  *
 317  * @cl: host client (nfc info)
 318  * @ver: NFC interface version to be filled in
 319  *
 320  * Return: 0 on success; < 0 otherwise
 321  */
 322 static int mei_nfc_if_version(struct mei_cl *cl,
 323                               struct mei_nfc_if_version *ver)
 324 {
 325         struct mei_device *bus;
 326         struct mei_nfc_cmd cmd = {
 327                 .command = MEI_NFC_CMD_MAINTENANCE,
 328                 .data_size = 1,
 329                 .sub_command = MEI_NFC_SUBCMD_IF_VERSION,
 330         };
 331         struct mei_nfc_reply *reply = NULL;
 332         size_t if_version_length;
 333         int bytes_recv, ret;
 334 
 335         bus = cl->dev;
 336 
 337         WARN_ON(mutex_is_locked(&bus->device_lock));
 338 
 339         ret = __mei_cl_send(cl, (u8 *)&cmd, sizeof(struct mei_nfc_cmd),
 340                             MEI_CL_IO_TX_BLOCKING);
 341         if (ret < 0) {
 342                 dev_err(bus->dev, "Could not send IF version cmd\n");
 343                 return ret;
 344         }
 345 
 346         /* to be sure on the stack we alloc memory */
 347         if_version_length = sizeof(struct mei_nfc_reply) +
 348                 sizeof(struct mei_nfc_if_version);
 349 
 350         reply = kzalloc(if_version_length, GFP_KERNEL);
 351         if (!reply)
 352                 return -ENOMEM;
 353 
 354         ret = 0;
 355         bytes_recv = __mei_cl_recv(cl, (u8 *)reply, if_version_length, 0, 0);
 356         if (bytes_recv < 0 || (size_t)bytes_recv < if_version_length) {
 357                 dev_err(bus->dev, "Could not read IF version\n");
 358                 ret = -EIO;
 359                 goto err;
 360         }
 361 
 362         memcpy(ver, reply->data, sizeof(struct mei_nfc_if_version));
 363 
 364         dev_info(bus->dev, "NFC MEI VERSION: IVN 0x%x Vendor ID 0x%x Type 0x%x\n",
 365                 ver->fw_ivn, ver->vendor_id, ver->radio_type);
 366 
 367 err:
 368         kfree(reply);
 369         return ret;
 370 }
 371 
 372 /**
 373  * mei_nfc_radio_name - derive nfc radio name from the interface version
 374  *
 375  * @ver: NFC radio version
 376  *
 377  * Return: radio name string
 378  */
 379 static const char *mei_nfc_radio_name(struct mei_nfc_if_version *ver)
 380 {
 381 
 382         if (ver->vendor_id == MEI_NFC_VENDOR_INSIDE) {
 383                 if (ver->radio_type == MEI_NFC_VENDOR_INSIDE_UREAD)
 384                         return "microread";
 385         }
 386 
 387         if (ver->vendor_id == MEI_NFC_VENDOR_NXP) {
 388                 if (ver->radio_type == MEI_NFC_VENDOR_NXP_PN544)
 389                         return "pn544";
 390         }
 391 
 392         return NULL;
 393 }
 394 
 395 /**
 396  * mei_nfc - The nfc fixup function. The function retrieves nfc radio
 397  *    name and set is as device attribute so we can load
 398  *    the proper device driver for it
 399  *
 400  * @cldev: me client device (nfc)
 401  */
 402 static void mei_nfc(struct mei_cl_device *cldev)
 403 {
 404         struct mei_device *bus;
 405         struct mei_cl *cl;
 406         struct mei_me_client *me_cl = NULL;
 407         struct mei_nfc_if_version ver;
 408         const char *radio_name = NULL;
 409         int ret;
 410 
 411         bus = cldev->bus;
 412 
 413         dev_dbg(&cldev->dev, "running hook %s\n", __func__);
 414 
 415         mutex_lock(&bus->device_lock);
 416         /* we need to connect to INFO GUID */
 417         cl = mei_cl_alloc_linked(bus);
 418         if (IS_ERR(cl)) {
 419                 ret = PTR_ERR(cl);
 420                 cl = NULL;
 421                 dev_err(bus->dev, "nfc hook alloc failed %d\n", ret);
 422                 goto out;
 423         }
 424 
 425         me_cl = mei_me_cl_by_uuid(bus, &mei_nfc_info_guid);
 426         if (!me_cl) {
 427                 ret = -ENOTTY;
 428                 dev_err(bus->dev, "Cannot find nfc info %d\n", ret);
 429                 goto out;
 430         }
 431 
 432         ret = mei_cl_connect(cl, me_cl, NULL);
 433         if (ret < 0) {
 434                 dev_err(&cldev->dev, "Can't connect to the NFC INFO ME ret = %d\n",
 435                         ret);
 436                 goto out;
 437         }
 438 
 439         mutex_unlock(&bus->device_lock);
 440 
 441         ret = mei_nfc_if_version(cl, &ver);
 442         if (ret)
 443                 goto disconnect;
 444 
 445         radio_name = mei_nfc_radio_name(&ver);
 446 
 447         if (!radio_name) {
 448                 ret = -ENOENT;
 449                 dev_err(&cldev->dev, "Can't get the NFC interface version ret = %d\n",
 450                         ret);
 451                 goto disconnect;
 452         }
 453 
 454         dev_dbg(bus->dev, "nfc radio %s\n", radio_name);
 455         strlcpy(cldev->name, radio_name, sizeof(cldev->name));
 456 
 457 disconnect:
 458         mutex_lock(&bus->device_lock);
 459         if (mei_cl_disconnect(cl) < 0)
 460                 dev_err(bus->dev, "Can't disconnect the NFC INFO ME\n");
 461 
 462         mei_cl_flush_queues(cl, NULL);
 463 
 464 out:
 465         mei_cl_unlink(cl);
 466         mutex_unlock(&bus->device_lock);
 467         mei_me_cl_put(me_cl);
 468         kfree(cl);
 469 
 470         if (ret)
 471                 cldev->do_match = 0;
 472 
 473         dev_dbg(bus->dev, "end of fixup match = %d\n", cldev->do_match);
 474 }
 475 
 476 #define MEI_FIXUP(_uuid, _hook) { _uuid, _hook }
 477 
 478 static struct mei_fixup {
 479 
 480         const uuid_le uuid;
 481         void (*hook)(struct mei_cl_device *cldev);
 482 } mei_fixups[] = {
 483         MEI_FIXUP(MEI_UUID_ANY, number_of_connections),
 484         MEI_FIXUP(MEI_UUID_NFC_INFO, blacklist),
 485         MEI_FIXUP(MEI_UUID_NFC_HCI, mei_nfc),
 486         MEI_FIXUP(MEI_UUID_WD, mei_wd),
 487         MEI_FIXUP(MEI_UUID_MKHIF_FIX, mei_mkhi_fix),
 488         MEI_FIXUP(MEI_UUID_HDCP, whitelist),
 489 };
 490 
 491 /**
 492  * mei_cldev_fixup - run fixup handlers
 493  *
 494  * @cldev: me client device
 495  */
 496 void mei_cl_bus_dev_fixup(struct mei_cl_device *cldev)
 497 {
 498         struct mei_fixup *f;
 499         const uuid_le *uuid = mei_me_cl_uuid(cldev->me_cl);
 500         size_t i;
 501 
 502         for (i = 0; i < ARRAY_SIZE(mei_fixups); i++) {
 503 
 504                 f = &mei_fixups[i];
 505                 if (uuid_le_cmp(f->uuid, MEI_UUID_ANY) == 0 ||
 506                     uuid_le_cmp(f->uuid, *uuid) == 0)
 507                         f->hook(cldev);
 508         }
 509 }
 510 

/* [<][>][^][v][top][bottom][index][help] */