Path: blob/master/drivers/fpga/intel-m10-bmc-sec-update.c
26381 views
// SPDX-License-Identifier: GPL-2.01/*2* Intel MAX10 Board Management Controller Secure Update Driver3*4* Copyright (C) 2019-2022 Intel Corporation. All rights reserved.5*6*/7#include <linux/bitfield.h>8#include <linux/device.h>9#include <linux/firmware.h>10#include <linux/mfd/intel-m10-bmc.h>11#include <linux/mod_devicetable.h>12#include <linux/module.h>13#include <linux/platform_device.h>14#include <linux/slab.h>1516struct m10bmc_sec;1718struct m10bmc_sec_ops {19int (*rsu_status)(struct m10bmc_sec *sec);20};2122struct m10bmc_sec {23struct device *dev;24struct intel_m10bmc *m10bmc;25struct fw_upload *fwl;26char *fw_name;27u32 fw_name_id;28bool cancel_request;29const struct m10bmc_sec_ops *ops;30};3132static DEFINE_XARRAY_ALLOC(fw_upload_xa);3334/* Root Entry Hash (REH) support */35#define REH_SHA256_SIZE 3236#define REH_SHA384_SIZE 4837#define REH_MAGIC GENMASK(15, 0)38#define REH_SHA_NUM_BYTES GENMASK(31, 16)3940static int m10bmc_sec_write(struct m10bmc_sec *sec, const u8 *buf, u32 offset, u32 size)41{42struct intel_m10bmc *m10bmc = sec->m10bmc;43unsigned int stride = regmap_get_reg_stride(m10bmc->regmap);44u32 write_count = size / stride;45u32 leftover_offset = write_count * stride;46u32 leftover_size = size - leftover_offset;47u32 leftover_tmp = 0;48int ret;4950if (sec->m10bmc->flash_bulk_ops)51return sec->m10bmc->flash_bulk_ops->write(m10bmc, buf, offset, size);5253if (WARN_ON_ONCE(stride > sizeof(leftover_tmp)))54return -EINVAL;5556ret = regmap_bulk_write(m10bmc->regmap, M10BMC_STAGING_BASE + offset,57buf + offset, write_count);58if (ret)59return ret;6061/* If size is not aligned to stride, handle the remainder bytes with regmap_write() */62if (leftover_size) {63memcpy(&leftover_tmp, buf + leftover_offset, leftover_size);64ret = regmap_write(m10bmc->regmap, M10BMC_STAGING_BASE + offset + leftover_offset,65leftover_tmp);66if (ret)67return ret;68}6970return 0;71}7273static int m10bmc_sec_read(struct m10bmc_sec *sec, u8 *buf, u32 addr, u32 size)74{75struct intel_m10bmc *m10bmc = sec->m10bmc;76unsigned int stride = regmap_get_reg_stride(m10bmc->regmap);77u32 read_count = size / stride;78u32 leftover_offset = read_count * stride;79u32 leftover_size = size - leftover_offset;80u32 leftover_tmp;81int ret;8283if (sec->m10bmc->flash_bulk_ops)84return sec->m10bmc->flash_bulk_ops->read(m10bmc, buf, addr, size);8586if (WARN_ON_ONCE(stride > sizeof(leftover_tmp)))87return -EINVAL;8889ret = regmap_bulk_read(m10bmc->regmap, addr, buf, read_count);90if (ret)91return ret;9293/* If size is not aligned to stride, handle the remainder bytes with regmap_read() */94if (leftover_size) {95ret = regmap_read(m10bmc->regmap, addr + leftover_offset, &leftover_tmp);96if (ret)97return ret;98memcpy(buf + leftover_offset, &leftover_tmp, leftover_size);99}100101return 0;102}103104105static ssize_t106show_root_entry_hash(struct device *dev, u32 exp_magic,107u32 prog_addr, u32 reh_addr, char *buf)108{109struct m10bmc_sec *sec = dev_get_drvdata(dev);110int sha_num_bytes, i, ret, cnt = 0;111u8 hash[REH_SHA384_SIZE];112u32 magic;113114ret = m10bmc_sec_read(sec, (u8 *)&magic, prog_addr, sizeof(magic));115if (ret)116return ret;117118if (FIELD_GET(REH_MAGIC, magic) != exp_magic)119return sysfs_emit(buf, "hash not programmed\n");120121sha_num_bytes = FIELD_GET(REH_SHA_NUM_BYTES, magic) / 8;122if (sha_num_bytes != REH_SHA256_SIZE &&123sha_num_bytes != REH_SHA384_SIZE) {124dev_err(sec->dev, "%s bad sha num bytes %d\n", __func__,125sha_num_bytes);126return -EINVAL;127}128129ret = m10bmc_sec_read(sec, hash, reh_addr, sha_num_bytes);130if (ret) {131dev_err(dev, "failed to read root entry hash\n");132return ret;133}134135for (i = 0; i < sha_num_bytes; i++)136cnt += sprintf(buf + cnt, "%02x", hash[i]);137cnt += sprintf(buf + cnt, "\n");138139return cnt;140}141142#define DEVICE_ATTR_SEC_REH_RO(_name) \143static ssize_t _name##_root_entry_hash_show(struct device *dev, \144struct device_attribute *attr, \145char *buf) \146{ \147struct m10bmc_sec *sec = dev_get_drvdata(dev); \148const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; \149\150return show_root_entry_hash(dev, csr_map->_name##_magic, \151csr_map->_name##_prog_addr, \152csr_map->_name##_reh_addr, \153buf); \154} \155static DEVICE_ATTR_RO(_name##_root_entry_hash)156157DEVICE_ATTR_SEC_REH_RO(bmc);158DEVICE_ATTR_SEC_REH_RO(sr);159DEVICE_ATTR_SEC_REH_RO(pr);160161#define CSK_BIT_LEN 128U162#define CSK_32ARRAY_SIZE DIV_ROUND_UP(CSK_BIT_LEN, 32)163164static ssize_t165show_canceled_csk(struct device *dev, u32 addr, char *buf)166{167unsigned int i, size = CSK_32ARRAY_SIZE * sizeof(u32);168struct m10bmc_sec *sec = dev_get_drvdata(dev);169DECLARE_BITMAP(csk_map, CSK_BIT_LEN);170__le32 csk_le32[CSK_32ARRAY_SIZE];171u32 csk32[CSK_32ARRAY_SIZE];172int ret;173174ret = m10bmc_sec_read(sec, (u8 *)&csk_le32, addr, size);175if (ret) {176dev_err(sec->dev, "failed to read CSK vector\n");177return ret;178}179180for (i = 0; i < CSK_32ARRAY_SIZE; i++)181csk32[i] = le32_to_cpu(((csk_le32[i])));182183bitmap_from_arr32(csk_map, csk32, CSK_BIT_LEN);184bitmap_complement(csk_map, csk_map, CSK_BIT_LEN);185return bitmap_print_to_pagebuf(1, buf, csk_map, CSK_BIT_LEN);186}187188#define DEVICE_ATTR_SEC_CSK_RO(_name) \189static ssize_t _name##_canceled_csks_show(struct device *dev, \190struct device_attribute *attr, \191char *buf) \192{ \193struct m10bmc_sec *sec = dev_get_drvdata(dev); \194const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map; \195\196return show_canceled_csk(dev, \197csr_map->_name##_prog_addr + CSK_VEC_OFFSET, \198buf); \199} \200static DEVICE_ATTR_RO(_name##_canceled_csks)201202#define CSK_VEC_OFFSET 0x34203204DEVICE_ATTR_SEC_CSK_RO(bmc);205DEVICE_ATTR_SEC_CSK_RO(sr);206DEVICE_ATTR_SEC_CSK_RO(pr);207208#define FLASH_COUNT_SIZE 4096 /* count stored as inverted bit vector */209210static ssize_t flash_count_show(struct device *dev,211struct device_attribute *attr, char *buf)212{213struct m10bmc_sec *sec = dev_get_drvdata(dev);214const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;215unsigned int num_bits;216u8 *flash_buf;217int cnt, ret;218219num_bits = FLASH_COUNT_SIZE * 8;220221flash_buf = kmalloc(FLASH_COUNT_SIZE, GFP_KERNEL);222if (!flash_buf)223return -ENOMEM;224225ret = m10bmc_sec_read(sec, flash_buf, csr_map->rsu_update_counter,226FLASH_COUNT_SIZE);227if (ret) {228dev_err(sec->dev, "failed to read flash count\n");229goto exit_free;230}231cnt = num_bits - bitmap_weight((unsigned long *)flash_buf, num_bits);232233exit_free:234kfree(flash_buf);235236return ret ? : sysfs_emit(buf, "%u\n", cnt);237}238static DEVICE_ATTR_RO(flash_count);239240static struct attribute *m10bmc_security_attrs[] = {241&dev_attr_flash_count.attr,242&dev_attr_bmc_root_entry_hash.attr,243&dev_attr_sr_root_entry_hash.attr,244&dev_attr_pr_root_entry_hash.attr,245&dev_attr_sr_canceled_csks.attr,246&dev_attr_pr_canceled_csks.attr,247&dev_attr_bmc_canceled_csks.attr,248NULL,249};250251static struct attribute_group m10bmc_security_attr_group = {252.name = "security",253.attrs = m10bmc_security_attrs,254};255256static const struct attribute_group *m10bmc_sec_attr_groups[] = {257&m10bmc_security_attr_group,258NULL,259};260261static void log_error_regs(struct m10bmc_sec *sec, u32 doorbell)262{263const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;264u32 auth_result;265266dev_err(sec->dev, "Doorbell: 0x%08x\n", doorbell);267268if (!m10bmc_sys_read(sec->m10bmc, csr_map->auth_result, &auth_result))269dev_err(sec->dev, "RSU auth result: 0x%08x\n", auth_result);270}271272static int m10bmc_sec_n3000_rsu_status(struct m10bmc_sec *sec)273{274const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;275u32 doorbell;276int ret;277278ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell);279if (ret)280return ret;281282return FIELD_GET(DRBL_RSU_STATUS, doorbell);283}284285static int m10bmc_sec_n6000_rsu_status(struct m10bmc_sec *sec)286{287const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;288u32 auth_result;289int ret;290291ret = m10bmc_sys_read(sec->m10bmc, csr_map->auth_result, &auth_result);292if (ret)293return ret;294295return FIELD_GET(AUTH_RESULT_RSU_STATUS, auth_result);296}297298static bool rsu_status_ok(u32 status)299{300return (status == RSU_STAT_NORMAL ||301status == RSU_STAT_NIOS_OK ||302status == RSU_STAT_USER_OK ||303status == RSU_STAT_FACTORY_OK);304}305306static bool rsu_progress_done(u32 progress)307{308return (progress == RSU_PROG_IDLE ||309progress == RSU_PROG_RSU_DONE);310}311312static bool rsu_progress_busy(u32 progress)313{314return (progress == RSU_PROG_AUTHENTICATING ||315progress == RSU_PROG_COPYING ||316progress == RSU_PROG_UPDATE_CANCEL ||317progress == RSU_PROG_PROGRAM_KEY_HASH);318}319320static int m10bmc_sec_progress_status(struct m10bmc_sec *sec, u32 *doorbell_reg,321u32 *progress, u32 *status)322{323const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;324int ret;325326ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, doorbell_reg);327if (ret)328return ret;329330ret = sec->ops->rsu_status(sec);331if (ret < 0)332return ret;333334*status = ret;335*progress = rsu_prog(*doorbell_reg);336337return 0;338}339340static enum fw_upload_err rsu_check_idle(struct m10bmc_sec *sec)341{342const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;343u32 doorbell;344int ret;345346ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell);347if (ret)348return FW_UPLOAD_ERR_RW_ERROR;349350if (!rsu_progress_done(rsu_prog(doorbell))) {351log_error_regs(sec, doorbell);352return FW_UPLOAD_ERR_BUSY;353}354355return FW_UPLOAD_ERR_NONE;356}357358static inline bool rsu_start_done(u32 doorbell_reg, u32 progress, u32 status)359{360if (doorbell_reg & DRBL_RSU_REQUEST)361return false;362363if (status == RSU_STAT_ERASE_FAIL || status == RSU_STAT_WEAROUT)364return true;365366if (!rsu_progress_done(progress))367return true;368369return false;370}371372static enum fw_upload_err rsu_update_init(struct m10bmc_sec *sec)373{374const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;375u32 doorbell_reg, progress, status;376int ret, err;377378ret = m10bmc_sys_update_bits(sec->m10bmc, csr_map->doorbell,379DRBL_RSU_REQUEST | DRBL_HOST_STATUS,380DRBL_RSU_REQUEST |381FIELD_PREP(DRBL_HOST_STATUS,382HOST_STATUS_IDLE));383if (ret)384return FW_UPLOAD_ERR_RW_ERROR;385386ret = read_poll_timeout(m10bmc_sec_progress_status, err,387err < 0 || rsu_start_done(doorbell_reg, progress, status),388NIOS_HANDSHAKE_INTERVAL_US,389NIOS_HANDSHAKE_TIMEOUT_US,390false,391sec, &doorbell_reg, &progress, &status);392393if (ret == -ETIMEDOUT) {394log_error_regs(sec, doorbell_reg);395return FW_UPLOAD_ERR_TIMEOUT;396} else if (err) {397return FW_UPLOAD_ERR_RW_ERROR;398}399400if (status == RSU_STAT_WEAROUT) {401dev_warn(sec->dev, "Excessive flash update count detected\n");402return FW_UPLOAD_ERR_WEAROUT;403} else if (status == RSU_STAT_ERASE_FAIL) {404log_error_regs(sec, doorbell_reg);405return FW_UPLOAD_ERR_HW_ERROR;406}407408return FW_UPLOAD_ERR_NONE;409}410411static enum fw_upload_err rsu_prog_ready(struct m10bmc_sec *sec)412{413const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;414unsigned long poll_timeout;415u32 doorbell, progress;416int ret;417418ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell);419if (ret)420return FW_UPLOAD_ERR_RW_ERROR;421422poll_timeout = jiffies + msecs_to_jiffies(RSU_PREP_TIMEOUT_MS);423while (rsu_prog(doorbell) == RSU_PROG_PREPARE) {424msleep(RSU_PREP_INTERVAL_MS);425if (time_after(jiffies, poll_timeout))426break;427428ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell);429if (ret)430return FW_UPLOAD_ERR_RW_ERROR;431}432433progress = rsu_prog(doorbell);434if (progress == RSU_PROG_PREPARE) {435log_error_regs(sec, doorbell);436return FW_UPLOAD_ERR_TIMEOUT;437} else if (progress != RSU_PROG_READY) {438log_error_regs(sec, doorbell);439return FW_UPLOAD_ERR_HW_ERROR;440}441442return FW_UPLOAD_ERR_NONE;443}444445static enum fw_upload_err rsu_send_data(struct m10bmc_sec *sec)446{447const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;448u32 doorbell_reg, status;449int ret;450451ret = m10bmc_sys_update_bits(sec->m10bmc, csr_map->doorbell,452DRBL_HOST_STATUS,453FIELD_PREP(DRBL_HOST_STATUS,454HOST_STATUS_WRITE_DONE));455if (ret)456return FW_UPLOAD_ERR_RW_ERROR;457458ret = regmap_read_poll_timeout(sec->m10bmc->regmap,459csr_map->base + csr_map->doorbell,460doorbell_reg,461rsu_prog(doorbell_reg) != RSU_PROG_READY,462NIOS_HANDSHAKE_INTERVAL_US,463NIOS_HANDSHAKE_TIMEOUT_US);464465if (ret == -ETIMEDOUT) {466log_error_regs(sec, doorbell_reg);467return FW_UPLOAD_ERR_TIMEOUT;468} else if (ret) {469return FW_UPLOAD_ERR_RW_ERROR;470}471472ret = sec->ops->rsu_status(sec);473if (ret < 0)474return FW_UPLOAD_ERR_HW_ERROR;475status = ret;476477if (!rsu_status_ok(status)) {478log_error_regs(sec, doorbell_reg);479return FW_UPLOAD_ERR_HW_ERROR;480}481482return FW_UPLOAD_ERR_NONE;483}484485static int rsu_check_complete(struct m10bmc_sec *sec, u32 *doorbell_reg)486{487u32 progress, status;488489if (m10bmc_sec_progress_status(sec, doorbell_reg, &progress, &status))490return -EIO;491492if (!rsu_status_ok(status))493return -EINVAL;494495if (rsu_progress_done(progress))496return 0;497498if (rsu_progress_busy(progress))499return -EAGAIN;500501return -EINVAL;502}503504static enum fw_upload_err rsu_cancel(struct m10bmc_sec *sec)505{506const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;507u32 doorbell;508int ret;509510ret = m10bmc_sys_read(sec->m10bmc, csr_map->doorbell, &doorbell);511if (ret)512return FW_UPLOAD_ERR_RW_ERROR;513514if (rsu_prog(doorbell) != RSU_PROG_READY)515return FW_UPLOAD_ERR_BUSY;516517ret = m10bmc_sys_update_bits(sec->m10bmc, csr_map->doorbell,518DRBL_HOST_STATUS,519FIELD_PREP(DRBL_HOST_STATUS,520HOST_STATUS_ABORT_RSU));521if (ret)522return FW_UPLOAD_ERR_RW_ERROR;523524return FW_UPLOAD_ERR_CANCELED;525}526527static enum fw_upload_err m10bmc_sec_prepare(struct fw_upload *fwl,528const u8 *data, u32 size)529{530struct m10bmc_sec *sec = fwl->dd_handle;531const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;532u32 ret;533534sec->cancel_request = false;535536if (!size || size > csr_map->staging_size)537return FW_UPLOAD_ERR_INVALID_SIZE;538539if (sec->m10bmc->flash_bulk_ops)540if (sec->m10bmc->flash_bulk_ops->lock_write(sec->m10bmc))541return FW_UPLOAD_ERR_BUSY;542543ret = rsu_check_idle(sec);544if (ret != FW_UPLOAD_ERR_NONE)545goto unlock_flash;546547m10bmc_fw_state_set(sec->m10bmc, M10BMC_FW_STATE_SEC_UPDATE_PREPARE);548549ret = rsu_update_init(sec);550if (ret != FW_UPLOAD_ERR_NONE)551goto fw_state_exit;552553ret = rsu_prog_ready(sec);554if (ret != FW_UPLOAD_ERR_NONE)555goto fw_state_exit;556557if (sec->cancel_request) {558ret = rsu_cancel(sec);559goto fw_state_exit;560}561562m10bmc_fw_state_set(sec->m10bmc, M10BMC_FW_STATE_SEC_UPDATE_WRITE);563564return FW_UPLOAD_ERR_NONE;565566fw_state_exit:567m10bmc_fw_state_set(sec->m10bmc, M10BMC_FW_STATE_NORMAL);568569unlock_flash:570if (sec->m10bmc->flash_bulk_ops)571sec->m10bmc->flash_bulk_ops->unlock_write(sec->m10bmc);572return ret;573}574575#define WRITE_BLOCK_SIZE 0x4000 /* Default write-block size is 0x4000 bytes */576577static enum fw_upload_err m10bmc_sec_fw_write(struct fw_upload *fwl, const u8 *data,578u32 offset, u32 size, u32 *written)579{580struct m10bmc_sec *sec = fwl->dd_handle;581const struct m10bmc_csr_map *csr_map = sec->m10bmc->info->csr_map;582struct intel_m10bmc *m10bmc = sec->m10bmc;583u32 blk_size, doorbell;584int ret;585586if (sec->cancel_request)587return rsu_cancel(sec);588589ret = m10bmc_sys_read(m10bmc, csr_map->doorbell, &doorbell);590if (ret) {591return FW_UPLOAD_ERR_RW_ERROR;592} else if (rsu_prog(doorbell) != RSU_PROG_READY) {593log_error_regs(sec, doorbell);594return FW_UPLOAD_ERR_HW_ERROR;595}596597WARN_ON_ONCE(WRITE_BLOCK_SIZE % regmap_get_reg_stride(m10bmc->regmap));598blk_size = min_t(u32, WRITE_BLOCK_SIZE, size);599ret = m10bmc_sec_write(sec, data, offset, blk_size);600if (ret)601return FW_UPLOAD_ERR_RW_ERROR;602603*written = blk_size;604return FW_UPLOAD_ERR_NONE;605}606607static enum fw_upload_err m10bmc_sec_poll_complete(struct fw_upload *fwl)608{609struct m10bmc_sec *sec = fwl->dd_handle;610unsigned long poll_timeout;611u32 doorbell, result;612int ret;613614if (sec->cancel_request)615return rsu_cancel(sec);616617m10bmc_fw_state_set(sec->m10bmc, M10BMC_FW_STATE_SEC_UPDATE_PROGRAM);618619result = rsu_send_data(sec);620if (result != FW_UPLOAD_ERR_NONE)621return result;622623poll_timeout = jiffies + msecs_to_jiffies(RSU_COMPLETE_TIMEOUT_MS);624do {625msleep(RSU_COMPLETE_INTERVAL_MS);626ret = rsu_check_complete(sec, &doorbell);627} while (ret == -EAGAIN && !time_after(jiffies, poll_timeout));628629if (ret == -EAGAIN) {630log_error_regs(sec, doorbell);631return FW_UPLOAD_ERR_TIMEOUT;632} else if (ret == -EIO) {633return FW_UPLOAD_ERR_RW_ERROR;634} else if (ret) {635log_error_regs(sec, doorbell);636return FW_UPLOAD_ERR_HW_ERROR;637}638639return FW_UPLOAD_ERR_NONE;640}641642/*643* m10bmc_sec_cancel() may be called asynchronously with an on-going update.644* All other functions are called sequentially in a single thread. To avoid645* contention on register accesses, m10bmc_sec_cancel() must only update646* the cancel_request flag. Other functions will check this flag and handle647* the cancel request synchronously.648*/649static void m10bmc_sec_cancel(struct fw_upload *fwl)650{651struct m10bmc_sec *sec = fwl->dd_handle;652653sec->cancel_request = true;654}655656static void m10bmc_sec_cleanup(struct fw_upload *fwl)657{658struct m10bmc_sec *sec = fwl->dd_handle;659660(void)rsu_cancel(sec);661662m10bmc_fw_state_set(sec->m10bmc, M10BMC_FW_STATE_NORMAL);663664if (sec->m10bmc->flash_bulk_ops)665sec->m10bmc->flash_bulk_ops->unlock_write(sec->m10bmc);666}667668static const struct fw_upload_ops m10bmc_ops = {669.prepare = m10bmc_sec_prepare,670.write = m10bmc_sec_fw_write,671.poll_complete = m10bmc_sec_poll_complete,672.cancel = m10bmc_sec_cancel,673.cleanup = m10bmc_sec_cleanup,674};675676static const struct m10bmc_sec_ops m10sec_n3000_ops = {677.rsu_status = m10bmc_sec_n3000_rsu_status,678};679680static const struct m10bmc_sec_ops m10sec_n6000_ops = {681.rsu_status = m10bmc_sec_n6000_rsu_status,682};683684#define SEC_UPDATE_LEN_MAX 32685static int m10bmc_sec_probe(struct platform_device *pdev)686{687char buf[SEC_UPDATE_LEN_MAX];688struct m10bmc_sec *sec;689struct fw_upload *fwl;690unsigned int len;691int ret;692693sec = devm_kzalloc(&pdev->dev, sizeof(*sec), GFP_KERNEL);694if (!sec)695return -ENOMEM;696697sec->dev = &pdev->dev;698sec->m10bmc = dev_get_drvdata(pdev->dev.parent);699sec->ops = (struct m10bmc_sec_ops *)platform_get_device_id(pdev)->driver_data;700dev_set_drvdata(&pdev->dev, sec);701702ret = xa_alloc(&fw_upload_xa, &sec->fw_name_id, sec,703xa_limit_32b, GFP_KERNEL);704if (ret)705return ret;706707len = scnprintf(buf, SEC_UPDATE_LEN_MAX, "secure-update%d",708sec->fw_name_id);709sec->fw_name = kmemdup_nul(buf, len, GFP_KERNEL);710if (!sec->fw_name) {711ret = -ENOMEM;712goto fw_name_fail;713}714715fwl = firmware_upload_register(THIS_MODULE, sec->dev, sec->fw_name,716&m10bmc_ops, sec);717if (IS_ERR(fwl)) {718dev_err(sec->dev, "Firmware Upload driver failed to start\n");719ret = PTR_ERR(fwl);720goto fw_uploader_fail;721}722723sec->fwl = fwl;724return 0;725726fw_uploader_fail:727kfree(sec->fw_name);728fw_name_fail:729xa_erase(&fw_upload_xa, sec->fw_name_id);730return ret;731}732733static void m10bmc_sec_remove(struct platform_device *pdev)734{735struct m10bmc_sec *sec = dev_get_drvdata(&pdev->dev);736737firmware_upload_unregister(sec->fwl);738kfree(sec->fw_name);739xa_erase(&fw_upload_xa, sec->fw_name_id);740}741742static const struct platform_device_id intel_m10bmc_sec_ids[] = {743{744.name = "n3000bmc-sec-update",745.driver_data = (kernel_ulong_t)&m10sec_n3000_ops,746},747{748.name = "d5005bmc-sec-update",749.driver_data = (kernel_ulong_t)&m10sec_n3000_ops,750},751{752.name = "n6000bmc-sec-update",753.driver_data = (kernel_ulong_t)&m10sec_n6000_ops,754},755{ }756};757MODULE_DEVICE_TABLE(platform, intel_m10bmc_sec_ids);758759static struct platform_driver intel_m10bmc_sec_driver = {760.probe = m10bmc_sec_probe,761.remove = m10bmc_sec_remove,762.driver = {763.name = "intel-m10bmc-sec-update",764.dev_groups = m10bmc_sec_attr_groups,765},766.id_table = intel_m10bmc_sec_ids,767};768module_platform_driver(intel_m10bmc_sec_driver);769770MODULE_AUTHOR("Intel Corporation");771MODULE_DESCRIPTION("Intel MAX10 BMC Secure Update");772MODULE_LICENSE("GPL");773MODULE_IMPORT_NS("INTEL_M10_BMC_CORE");774775776