^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Intel Wireless WiMAX Connection 2400m
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Firmware uploader
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Redistribution and use in source and binary forms, with or without
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * modification, are permitted provided that the following conditions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * are met:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * * Redistributions of source code must retain the above copyright
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * notice, this list of conditions and the following disclaimer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * * Redistributions in binary form must reproduce the above copyright
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * notice, this list of conditions and the following disclaimer in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * the documentation and/or other materials provided with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * distribution.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * * Neither the name of Intel Corporation nor the names of its
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * contributors may be used to endorse or promote products derived
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * from this software without specific prior written permission.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * Intel Corporation <linux-wimax@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) * Yanir Lubetkin <yanirx.lubetkin@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * - Initial implementation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * THE PROCEDURE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * The 2400m and derived devices work in two modes: boot-mode or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * normal mode. In boot mode we can execute only a handful of commands
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * targeted at uploading the firmware and launching it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * The 2400m enters boot mode when it is first connected to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * system, when it crashes and when you ask it to reboot. There are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * two submodes of the boot mode: signed and non-signed. Signed takes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * firmwares signed with a certain private key, non-signed takes any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * firmware. Normal hardware takes only signed firmware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * On boot mode, in USB, we write to the device using the bulk out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * endpoint and read from it in the notification endpoint.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * Upon entrance to boot mode, the device sends (preceded with a few
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * zero length packets (ZLPs) on the notification endpoint in USB) a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * reboot barker (4 le32 words with the same value). We ack it by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * sending the same barker to the device. The device acks with a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * reboot ack barker (4 le32 words with value I2400M_ACK_BARKER) and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * then is fully booted. At this point we can upload the firmware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * Note that different iterations of the device and EEPROM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * configurations will send different [re]boot barkers; these are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * collected in i2400m_barker_db along with the firmware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) * characteristics they require.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * This process is accomplished by the i2400m_bootrom_init()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * function. All the device interaction happens through the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * i2400m_bm_cmd() [boot mode command]. Special return values will
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * indicate if the device did reset during the process.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * After this, we read the MAC address and then (if needed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * reinitialize the device. We need to read it ahead of time because
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * in the future, we might not upload the firmware until userspace
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * 'ifconfig up's the device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * We can then upload the firmware file. The file is composed of a BCF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * header (basic data, keys and signatures) and a list of write
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * commands and payloads. Optionally more BCF headers might follow the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * main payload. We first upload the header [i2400m_dnload_init()] and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * then pass the commands and payloads verbatim to the i2400m_bm_cmd()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * function [i2400m_dnload_bcf()]. Then we tell the device to jump to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * the new firmware [i2400m_dnload_finalize()].
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * Once firmware is uploaded, we are good to go :)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * When we don't know in which mode we are, we first try by sending a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * warm reset request that will take us to boot-mode. If we time out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * waiting for a reboot barker, that means maybe we are already in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * boot mode, so we send a reboot barker.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * COMMAND EXECUTION
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * This code (and process) is single threaded; for executing commands,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * we post a URB to the notification endpoint, post the command, wait
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * for data on the notification buffer. We don't need to worry about
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * others as we know we are the only ones in there.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * BACKEND IMPLEMENTATION
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * This code is bus-generic; the bus-specific driver provides back end
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * implementations to send a boot mode command to the device and to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * read an acknolwedgement from it (or an asynchronous notification)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * from it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * FIRMWARE LOADING
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * Note that in some cases, we can't just load a firmware file (for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) * example, when resuming). For that, we might cache the firmware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * file. Thus, when doing the bootstrap, if there is a cache firmware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * file, it is used; if not, loading from disk is attempted.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) * ROADMAP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) * i2400m_barker_db_init Called by i2400m_driver_init()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * i2400m_barker_db_add
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * i2400m_barker_db_exit Called by i2400m_driver_exit()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) * i2400m_dev_bootstrap Called by __i2400m_dev_start()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * request_firmware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * i2400m_fw_bootstrap
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) * i2400m_fw_check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * i2400m_fw_hdr_check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * i2400m_fw_dnload
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * release_firmware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * i2400m_fw_dnload
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * i2400m_bootrom_init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) * i2400m_bm_cmd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * i2400m_reset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * i2400m_dnload_init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * i2400m_dnload_init_signed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) * i2400m_dnload_init_nonsigned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) * i2400m_download_chunk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * i2400m_bm_cmd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * i2400m_dnload_bcf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * i2400m_bm_cmd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) * i2400m_dnload_finalize
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) * i2400m_bm_cmd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) * i2400m_bm_cmd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * i2400m->bus_bm_cmd_send()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * i2400m->bus_bm_wait_for_ack
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) * __i2400m_bm_ack_verify
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * i2400m_is_boot_barker
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * i2400m_bm_cmd_prepare Used by bus-drivers to prep
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * commands before sending
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * i2400m_pm_notifier Called on Power Management events
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * i2400m_fw_cache
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * i2400m_fw_uncache
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) #include <linux/firmware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) #include <linux/usb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) #include "i2400m.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) #define D_SUBMODULE fw
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) #include "debug-levels.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) static const __le32 i2400m_ACK_BARKER[4] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) cpu_to_le32(I2400M_ACK_BARKER),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) cpu_to_le32(I2400M_ACK_BARKER),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) cpu_to_le32(I2400M_ACK_BARKER),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) cpu_to_le32(I2400M_ACK_BARKER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) * Prepare a boot-mode command for delivery
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * @cmd: pointer to bootrom header to prepare
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * Computes checksum if so needed. After calling this function, DO NOT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * modify the command or header as the checksum won't work anymore.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * We do it from here because some times we cannot do it in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * original context the command was sent (it is a const), so when we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * copy it to our staging buffer, we add the checksum there.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) void i2400m_bm_cmd_prepare(struct i2400m_bootrom_header *cmd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (i2400m_brh_get_use_checksum(cmd)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) u32 checksum = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) const u32 *checksum_ptr = (void *) cmd->payload;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) for (i = 0; i < cmd->data_size / 4; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) checksum += cpu_to_le32(*checksum_ptr++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) checksum += cmd->command + cmd->target_addr + cmd->data_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) cmd->block_checksum = cpu_to_le32(checksum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) EXPORT_SYMBOL_GPL(i2400m_bm_cmd_prepare);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * Database of known barkers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) * A barker is what the device sends indicating he is ready to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * bootloaded. Different versions of the device will send different
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) * barkers. Depending on the barker, it might mean the device wants
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * some kind of firmware or the other.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) static struct i2400m_barker_db {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) __le32 data[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) } *i2400m_barker_db;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) static size_t i2400m_barker_db_used, i2400m_barker_db_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) int i2400m_zrealloc_2x(void **ptr, size_t *_count, size_t el_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) gfp_t gfp_flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) size_t old_count = *_count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) new_count = old_count ? 2 * old_count : 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) old_size = el_size * old_count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) new_size = el_size * new_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) void *nptr = krealloc(*ptr, new_size, gfp_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (nptr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) /* zero the other half or the whole thing if old_count
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * was zero */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (old_size == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) memset(nptr, 0, new_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) memset(nptr + old_size, 0, old_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) *_count = new_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) *ptr = nptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) * Add a barker to the database
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) * This cannot used outside of this module and only at at module_init
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) * time. This is to avoid the need to do locking.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) int i2400m_barker_db_add(u32 barker_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) struct i2400m_barker_db *barker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (i2400m_barker_db_used >= i2400m_barker_db_size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) result = i2400m_zrealloc_2x(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) (void **) &i2400m_barker_db, &i2400m_barker_db_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) sizeof(i2400m_barker_db[0]), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) barker = i2400m_barker_db + i2400m_barker_db_used++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) barker->data[0] = le32_to_cpu(barker_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) barker->data[1] = le32_to_cpu(barker_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) barker->data[2] = le32_to_cpu(barker_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) barker->data[3] = le32_to_cpu(barker_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) void i2400m_barker_db_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) kfree(i2400m_barker_db);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) i2400m_barker_db = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) i2400m_barker_db_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) i2400m_barker_db_used = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) * Helper function to add all the known stable barkers to the barker
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) * database.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) int i2400m_barker_db_known_barkers(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) result = i2400m_barker_db_add(I2400M_NBOOT_BARKER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) goto error_add;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) result = i2400m_barker_db_add(I2400M_SBOOT_BARKER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) goto error_add;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) result = i2400m_barker_db_add(I2400M_SBOOT_BARKER_6050);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) goto error_add;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) error_add:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) * Initialize the barker database
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) * This can only be used from the module_init function for this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) * module; this is to avoid the need to do locking.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) * @options: command line argument with extra barkers to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) * recognize. This is a comma-separated list of 32-bit hex
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) * numbers. They are appended to the existing list. Setting 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) * cleans the existing list and starts a new one.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) int i2400m_barker_db_init(const char *_options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) char *options = NULL, *options_orig, *token;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) i2400m_barker_db = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) i2400m_barker_db_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) i2400m_barker_db_used = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) result = i2400m_barker_db_known_barkers();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) goto error_add;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) /* parse command line options from i2400m.barkers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (_options != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) unsigned barker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) options_orig = kstrdup(_options, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) if (options_orig == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) result = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) goto error_parse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) options = options_orig;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) while ((token = strsep(&options, ",")) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) if (*token == '\0') /* eat joint commas */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (sscanf(token, "%x", &barker) != 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) || barker > 0xffffffff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) printk(KERN_ERR "%s: can't recognize "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) "i2400m.barkers value '%s' as "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) "a 32-bit number\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) __func__, token);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) result = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) goto error_parse;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) if (barker == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) /* clean list and start new */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) i2400m_barker_db_exit();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) result = i2400m_barker_db_add(barker);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) goto error_parse_add;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) kfree(options_orig);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) error_parse_add:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) error_parse:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) kfree(options_orig);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) error_add:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) kfree(i2400m_barker_db);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) * Recognize a boot barker
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) * @buf: buffer where the boot barker.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) * @buf_size: size of the buffer (has to be 16 bytes). It is passed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) * here so the function can check it for the caller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) * Note that as a side effect, upon identifying the obtained boot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) * barker, this function will set i2400m->barker to point to the right
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) * barker database entry. Subsequent calls to the function will result
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) * in verifying that the same type of boot barker is returned when the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) * device [re]boots (as long as the same device instance is used).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) * Return: 0 if @buf matches a known boot barker. -ENOENT if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) * buffer in @buf doesn't match any boot barker in the database or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) * -EILSEQ if the buffer doesn't have the right size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) int i2400m_is_boot_barker(struct i2400m *i2400m,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) const void *buf, size_t buf_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) struct i2400m_barker_db *barker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) result = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) if (buf_size != sizeof(i2400m_barker_db[i].data))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) /* Short circuit if we have already discovered the barker
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) * associated with the device. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) if (i2400m->barker &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) !memcmp(buf, i2400m->barker, sizeof(i2400m->barker->data)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) for (i = 0; i < i2400m_barker_db_used; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) barker = &i2400m_barker_db[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) BUILD_BUG_ON(sizeof(barker->data) != 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) if (memcmp(buf, barker->data, sizeof(barker->data)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) if (i2400m->barker == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) i2400m->barker = barker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) d_printf(1, dev, "boot barker set to #%u/%08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) i, le32_to_cpu(barker->data[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) if (barker->data[0] == le32_to_cpu(I2400M_NBOOT_BARKER))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) i2400m->sboot = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) i2400m->sboot = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) } else if (i2400m->barker != barker) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) dev_err(dev, "HW inconsistency: device "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) "reports a different boot barker "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) "than set (from %08x to %08x)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) le32_to_cpu(i2400m->barker->data[0]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) le32_to_cpu(barker->data[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) result = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) d_printf(2, dev, "boot barker confirmed #%u/%08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) i, le32_to_cpu(barker->data[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) EXPORT_SYMBOL_GPL(i2400m_is_boot_barker);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) * Verify the ack data received
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) * Given a reply to a boot mode command, chew it and verify everything
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) * is ok.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) * @opcode: opcode which generated this ack. For error messages.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) * @ack: pointer to ack data we received
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) * @ack_size: size of that data buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) * @flags: I2400M_BM_CMD_* flags we called the command with.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) * Way too long function -- maybe it should be further split
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) ssize_t __i2400m_bm_ack_verify(struct i2400m *i2400m, int opcode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) struct i2400m_bootrom_header *ack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) size_t ack_size, int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) ssize_t result = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) d_fnstart(8, dev, "(i2400m %p opcode %d ack %p size %zu)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) i2400m, opcode, ack, ack_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) if (ack_size < sizeof(*ack)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) result = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) dev_err(dev, "boot-mode cmd %d: HW BUG? notification didn't "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) "return enough data (%zu bytes vs %zu expected)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) opcode, ack_size, sizeof(*ack));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) goto error_ack_short;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) result = i2400m_is_boot_barker(i2400m, ack, ack_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) if (result >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) result = -ERESTARTSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) d_printf(6, dev, "boot-mode cmd %d: HW boot barker\n", opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) goto error_reboot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) if (ack_size == sizeof(i2400m_ACK_BARKER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) && memcmp(ack, i2400m_ACK_BARKER, sizeof(*ack)) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) result = -EISCONN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) d_printf(3, dev, "boot-mode cmd %d: HW reboot ack barker\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) goto error_reboot_ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) if (flags & I2400M_BM_CMD_RAW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) goto out_raw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) ack->data_size = le32_to_cpu(ack->data_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) ack->target_addr = le32_to_cpu(ack->target_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) ack->block_checksum = le32_to_cpu(ack->block_checksum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) d_printf(5, dev, "boot-mode cmd %d: notification for opcode %u "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) "response %u csum %u rr %u da %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) opcode, i2400m_brh_get_opcode(ack),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) i2400m_brh_get_response(ack),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) i2400m_brh_get_use_checksum(ack),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) i2400m_brh_get_response_required(ack),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) i2400m_brh_get_direct_access(ack));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) result = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) if (i2400m_brh_get_signature(ack) != 0xcbbc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) dev_err(dev, "boot-mode cmd %d: HW BUG? wrong signature "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) "0x%04x\n", opcode, i2400m_brh_get_signature(ack));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) goto error_ack_signature;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) if (opcode != -1 && opcode != i2400m_brh_get_opcode(ack)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) dev_err(dev, "boot-mode cmd %d: HW BUG? "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) "received response for opcode %u, expected %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) opcode, i2400m_brh_get_opcode(ack), opcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) goto error_ack_opcode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) if (i2400m_brh_get_response(ack) != 0) { /* failed? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) dev_err(dev, "boot-mode cmd %d: error; hw response %u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) opcode, i2400m_brh_get_response(ack));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) goto error_ack_failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) if (ack_size < ack->data_size + sizeof(*ack)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) dev_err(dev, "boot-mode cmd %d: SW BUG "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) "driver provided only %zu bytes for %zu bytes "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) "of data\n", opcode, ack_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) (size_t) le32_to_cpu(ack->data_size) + sizeof(*ack));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) goto error_ack_short_buffer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) result = ack_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) /* Don't you love this stack of empty targets? Well, I don't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) * either, but it helps track exactly who comes in here and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) * why :) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) error_ack_short_buffer:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) error_ack_failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) error_ack_opcode:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) error_ack_signature:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) out_raw:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) error_reboot_ack:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) error_reboot:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) error_ack_short:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) d_fnend(8, dev, "(i2400m %p opcode %d ack %p size %zu) = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) i2400m, opcode, ack, ack_size, (int) result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) * i2400m_bm_cmd - Execute a boot mode command
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) * @cmd: buffer containing the command data (pointing at the header).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) * This data can be ANYWHERE (for USB, we will copy it to an
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) * specific buffer). Make sure everything is in proper little
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) * endian.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) * A raw buffer can be also sent, just cast it and set flags to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) * I2400M_BM_CMD_RAW.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) * This function will generate a checksum for you if the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) * checksum bit in the command is set (unless I2400M_BM_CMD_RAW
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) * is set).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) * You can use the i2400m->bm_cmd_buf to stage your commands and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) * send them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) * If NULL, no command is sent (we just wait for an ack).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) * @cmd_size: size of the command. Will be auto padded to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) * bus-specific drivers padding requirements.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) * @ack: buffer where to place the acknowledgement. If it is a regular
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) * command response, all fields will be returned with the right,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) * native endianess.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) * You *cannot* use i2400m->bm_ack_buf for this buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) * @ack_size: size of @ack, 16 aligned; you need to provide at least
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) * sizeof(*ack) bytes and then enough to contain the return data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) * from the command
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) * @flags: see I2400M_BM_CMD_* above.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) * @returns: bytes received by the notification; if < 0, an errno code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) * denoting an error or:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) * -ERESTARTSYS The device has rebooted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) * Executes a boot-mode command and waits for a response, doing basic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) * validation on it; if a zero length response is received, it retries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) * waiting for a response until a non-zero one is received (timing out
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) * after %I2400M_BOOT_RETRIES retries).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) ssize_t i2400m_bm_cmd(struct i2400m *i2400m,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) const struct i2400m_bootrom_header *cmd, size_t cmd_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) struct i2400m_bootrom_header *ack, size_t ack_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) ssize_t result = -ENOMEM, rx_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) int opcode = cmd == NULL ? -1 : i2400m_brh_get_opcode(cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) d_fnstart(6, dev, "(i2400m %p cmd %p size %zu ack %p size %zu)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) i2400m, cmd, cmd_size, ack, ack_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) BUG_ON(ack_size < sizeof(*ack));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) BUG_ON(i2400m->boot_mode == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) if (cmd != NULL) { /* send the command */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) result = i2400m->bus_bm_cmd_send(i2400m, cmd, cmd_size, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) goto error_cmd_send;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) if ((flags & I2400M_BM_CMD_RAW) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) d_printf(5, dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) "boot-mode cmd %d csum %u rr %u da %u: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) "addr 0x%04x size %u block csum 0x%04x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) opcode, i2400m_brh_get_use_checksum(cmd),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) i2400m_brh_get_response_required(cmd),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) i2400m_brh_get_direct_access(cmd),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) cmd->target_addr, cmd->data_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) cmd->block_checksum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) result = i2400m->bus_bm_wait_for_ack(i2400m, ack, ack_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (result < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) dev_err(dev, "boot-mode cmd %d: error waiting for an ack: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) opcode, (int) result); /* bah, %zd doesn't work */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) goto error_wait_for_ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) rx_bytes = result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) /* verify the ack and read more if necessary [result is the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) * final amount of bytes we get in the ack] */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) result = __i2400m_bm_ack_verify(i2400m, opcode, ack, ack_size, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) goto error_bad_ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) /* Don't you love this stack of empty targets? Well, I don't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) * either, but it helps track exactly who comes in here and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) * why :) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) result = rx_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) error_bad_ack:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) error_wait_for_ack:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) error_cmd_send:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) d_fnend(6, dev, "(i2400m %p cmd %p size %zu ack %p size %zu) = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) i2400m, cmd, cmd_size, ack, ack_size, (int) result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) * i2400m_download_chunk - write a single chunk of data to the device's memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) * @i2400m: device descriptor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) * @buf: the buffer to write
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) * @buf_len: length of the buffer to write
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) * @addr: address in the device memory space
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) * @direct: bootrom write mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) * @do_csum: should a checksum validation be performed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) size_t __chunk_len, unsigned long addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) unsigned int direct, unsigned int do_csum)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) size_t chunk_len = ALIGN(__chunk_len, I2400M_PL_ALIGN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) struct i2400m_bootrom_header cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) u8 cmd_payload[];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) } __packed *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) struct i2400m_bootrom_header ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) d_fnstart(5, dev, "(i2400m %p chunk %p __chunk_len %zu addr 0x%08lx "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) "direct %u do_csum %u)\n", i2400m, chunk, __chunk_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) addr, direct, do_csum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) buf = i2400m->bm_cmd_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) memcpy(buf->cmd_payload, chunk, __chunk_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) memset(buf->cmd_payload + __chunk_len, 0xad, chunk_len - __chunk_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) buf->cmd.command = i2400m_brh_command(I2400M_BRH_WRITE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) __chunk_len & 0x3 ? 0 : do_csum,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) __chunk_len & 0xf ? 0 : direct);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) buf->cmd.target_addr = cpu_to_le32(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) buf->cmd.data_size = cpu_to_le32(__chunk_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) ret = i2400m_bm_cmd(i2400m, &buf->cmd, sizeof(buf->cmd) + chunk_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) &ack, sizeof(ack), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) if (ret >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) d_fnend(5, dev, "(i2400m %p chunk %p __chunk_len %zu addr 0x%08lx "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) "direct %u do_csum %u) = %d\n", i2400m, chunk, __chunk_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) addr, direct, do_csum, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) * Download a BCF file's sections to the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) * @i2400m: device descriptor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) * @bcf: pointer to firmware data (first header followed by the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) * payloads). Assumed verified and consistent.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) * @bcf_len: length (in bytes) of the @bcf buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) * Returns: < 0 errno code on error or the offset to the jump instruction.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) * Given a BCF file, downloads each section (a command and a payload)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) * to the device's address space. Actually, it just executes each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) * command i the BCF file.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) * The section size has to be aligned to 4 bytes AND the padding has
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) * to be taken from the firmware file, as the signature takes it into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) * account.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) ssize_t i2400m_dnload_bcf(struct i2400m *i2400m,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) const struct i2400m_bcf_hdr *bcf, size_t bcf_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) ssize_t ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) size_t offset, /* iterator offset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) data_size, /* Size of the data payload */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) section_size, /* Size of the whole section (cmd + payload) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) section = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) const struct i2400m_bootrom_header *bh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) struct i2400m_bootrom_header ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) d_fnstart(3, dev, "(i2400m %p bcf %p bcf_len %zu)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) i2400m, bcf, bcf_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) /* Iterate over the command blocks in the BCF file that start
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) * after the header */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) offset = le32_to_cpu(bcf->header_len) * sizeof(u32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) while (1) { /* start sending the file */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) bh = (void *) bcf + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) data_size = le32_to_cpu(bh->data_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) section_size = ALIGN(sizeof(*bh) + data_size, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) d_printf(7, dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) "downloading section #%zu (@%zu %zu B) to 0x%08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) section, offset, sizeof(*bh) + data_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) le32_to_cpu(bh->target_addr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) * We look for JUMP cmd from the bootmode header,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) * either I2400M_BRH_SIGNED_JUMP for secure boot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) * or I2400M_BRH_JUMP for unsecure boot, the last chunk
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) * should be the bootmode header with JUMP cmd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) if (i2400m_brh_get_opcode(bh) == I2400M_BRH_SIGNED_JUMP ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) i2400m_brh_get_opcode(bh) == I2400M_BRH_JUMP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) d_printf(5, dev, "jump found @%zu\n", offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) if (offset + section_size > bcf_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) dev_err(dev, "fw %s: bad section #%zu, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) "end (@%zu) beyond EOF (@%zu)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) i2400m->fw_name, section,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) offset + section_size, bcf_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) goto error_section_beyond_eof;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) __i2400m_msleep(20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) ret = i2400m_bm_cmd(i2400m, bh, section_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) &ack, sizeof(ack), I2400M_BM_CMD_RAW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) dev_err(dev, "fw %s: section #%zu (@%zu %zu B) "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) "failed %d\n", i2400m->fw_name, section,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) offset, sizeof(*bh) + data_size, (int) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) goto error_send;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) offset += section_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) section++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) ret = offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) error_section_beyond_eof:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) error_send:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) d_fnend(3, dev, "(i2400m %p bcf %p bcf_len %zu) = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) i2400m, bcf, bcf_len, (int) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) * Indicate if the device emitted a reboot barker that indicates
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) * "signed boot"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) unsigned i2400m_boot_is_signed(struct i2400m *i2400m)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) return likely(i2400m->sboot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) * Do the final steps of uploading firmware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) * @bcf_hdr: BCF header we are actually using
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) * @bcf: pointer to the firmware image (which matches the first header
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) * that is followed by the actual payloads).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) * @offset: [byte] offset into @bcf for the command we need to send.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) * Depending on the boot mode (signed vs non-signed), different
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) * actions need to be taken.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) int i2400m_dnload_finalize(struct i2400m *i2400m,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) const struct i2400m_bcf_hdr *bcf_hdr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) const struct i2400m_bcf_hdr *bcf, size_t offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) struct i2400m_bootrom_header *cmd, ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) struct i2400m_bootrom_header cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) u8 cmd_pl[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) } __packed *cmd_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) size_t signature_block_offset, signature_block_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) d_fnstart(3, dev, "offset %zu\n", offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) cmd = (void *) bcf + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) if (i2400m_boot_is_signed(i2400m) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) struct i2400m_bootrom_header jump_ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) d_printf(1, dev, "unsecure boot, jumping to 0x%08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) le32_to_cpu(cmd->target_addr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) cmd_buf = i2400m->bm_cmd_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) cmd = &cmd_buf->cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) /* now cmd points to the actual bootrom_header in cmd_buf */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) i2400m_brh_set_opcode(cmd, I2400M_BRH_JUMP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) cmd->data_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) ret = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) &jump_ack, sizeof(jump_ack), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) d_printf(1, dev, "secure boot, jumping to 0x%08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) le32_to_cpu(cmd->target_addr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) cmd_buf = i2400m->bm_cmd_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) memcpy(&cmd_buf->cmd, cmd, sizeof(*cmd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) signature_block_offset =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) sizeof(*bcf_hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) + le32_to_cpu(bcf_hdr->key_size) * sizeof(u32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) + le32_to_cpu(bcf_hdr->exponent_size) * sizeof(u32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) signature_block_size =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) le32_to_cpu(bcf_hdr->modulus_size) * sizeof(u32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) memcpy(cmd_buf->cmd_pl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) (void *) bcf_hdr + signature_block_offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) signature_block_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) ret = i2400m_bm_cmd(i2400m, &cmd_buf->cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) sizeof(cmd_buf->cmd) + signature_block_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) &ack, sizeof(ack), I2400M_BM_CMD_RAW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) d_fnend(3, dev, "returning %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) * i2400m_bootrom_init - Reboots a powered device into boot mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) * @i2400m: device descriptor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) * @flags:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) * I2400M_BRI_SOFT: a reboot barker has been seen
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) * already, so don't wait for it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) * I2400M_BRI_NO_REBOOT: Don't send a reboot command, but wait
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) * for a reboot barker notification. This is a one shot; if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) * the state machine needs to send a reboot command it will.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) * Returns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) * < 0 errno code on error, 0 if ok.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) * Description:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) * Tries hard enough to put the device in boot-mode. There are two
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) * main phases to this:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) * a. (1) send a reboot command and (2) get a reboot barker
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) * b. (1) echo/ack the reboot sending the reboot barker back and (2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) * getting an ack barker in return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) * We want to skip (a) in some cases [soft]. The state machine is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) * horrible, but it is basically: on each phase, send what has to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) * sent (if any), wait for the answer and act on the answer. We might
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) * have to backtrack and retry, so we keep a max tries counter for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) * that.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) * It sucks because we don't know ahead of time which is going to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) * the reboot barker (the device might send different ones depending
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) * on its EEPROM config) and once the device reboots and waits for the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) * echo/ack reboot barker being sent back, it doesn't understand
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) * anything else. So we can be left at the point where we don't know
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) * what to send to it -- cold reset and bus reset seem to have little
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) * effect. So the function iterates (in this case) through all the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) * known barkers and tries them all until an ACK is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) * received. Otherwise, it gives up.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) * If we get a timeout after sending a warm reset, we do it again.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) int i2400m_bootrom_init(struct i2400m *i2400m, enum i2400m_bri flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) struct i2400m_bootrom_header *cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) struct i2400m_bootrom_header ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) int count = i2400m->bus_bm_retries;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) int ack_timeout_cnt = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) unsigned i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) BUILD_BUG_ON(sizeof(*cmd) != sizeof(i2400m_barker_db[0].data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) BUILD_BUG_ON(sizeof(ack) != sizeof(i2400m_ACK_BARKER));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) d_fnstart(4, dev, "(i2400m %p flags 0x%08x)\n", i2400m, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) result = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) cmd = i2400m->bm_cmd_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) if (flags & I2400M_BRI_SOFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) goto do_reboot_ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) do_reboot:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) ack_timeout_cnt = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) if (--count < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) goto error_timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) d_printf(4, dev, "device reboot: reboot command [%d # left]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) if ((flags & I2400M_BRI_NO_REBOOT) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) i2400m_reset(i2400m, I2400M_RT_WARM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) result = i2400m_bm_cmd(i2400m, NULL, 0, &ack, sizeof(ack),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) I2400M_BM_CMD_RAW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) flags &= ~I2400M_BRI_NO_REBOOT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) switch (result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) case -ERESTARTSYS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) * at this point, i2400m_bm_cmd(), through
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) * __i2400m_bm_ack_process(), has updated
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) * i2400m->barker and we are good to go.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) d_printf(4, dev, "device reboot: got reboot barker\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) case -EISCONN: /* we don't know how it got here...but we follow it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) d_printf(4, dev, "device reboot: got ack barker - whatever\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) goto do_reboot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) case -ETIMEDOUT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) * Device has timed out, we might be in boot mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) * already and expecting an ack; if we don't know what
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) * the barker is, we just send them all. Cold reset
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) * and bus reset don't work. Beats me.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) if (i2400m->barker != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) dev_err(dev, "device boot: reboot barker timed out, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) "trying (set) %08x echo/ack\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) le32_to_cpu(i2400m->barker->data[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) goto do_reboot_ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) for (i = 0; i < i2400m_barker_db_used; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) struct i2400m_barker_db *barker = &i2400m_barker_db[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) memcpy(cmd, barker->data, sizeof(barker->data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) &ack, sizeof(ack),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) I2400M_BM_CMD_RAW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) if (result == -EISCONN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) dev_warn(dev, "device boot: got ack barker "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) "after sending echo/ack barker "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) "#%d/%08x; rebooting j.i.c.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) i, le32_to_cpu(barker->data[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) flags &= ~I2400M_BRI_NO_REBOOT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) goto do_reboot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) dev_err(dev, "device boot: tried all the echo/acks, could "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) "not get device to respond; giving up");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) result = -ESHUTDOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) case -EPROTO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) case -ESHUTDOWN: /* dev is gone */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) case -EINTR: /* user cancelled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) goto error_dev_gone;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) dev_err(dev, "device reboot: error %d while waiting "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) "for reboot barker - rebooting\n", result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) d_dump(1, dev, &ack, result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) goto do_reboot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) /* At this point we ack back with 4 REBOOT barkers and expect
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) * 4 ACK barkers. This is ugly, as we send a raw command --
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) * hence the cast. _bm_cmd() will catch the reboot ack
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) * notification and report it as -EISCONN. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) do_reboot_ack:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) d_printf(4, dev, "device reboot ack: sending ack [%d # left]\n", count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) memcpy(cmd, i2400m->barker->data, sizeof(i2400m->barker->data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) &ack, sizeof(ack), I2400M_BM_CMD_RAW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) switch (result) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) case -ERESTARTSYS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) d_printf(4, dev, "reboot ack: got reboot barker - retrying\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) if (--count < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) goto error_timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) goto do_reboot_ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) case -EISCONN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) d_printf(4, dev, "reboot ack: got ack barker - good\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) case -ETIMEDOUT: /* no response, maybe it is the other type? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) if (ack_timeout_cnt-- < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) d_printf(4, dev, "reboot ack timedout: retrying\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) goto do_reboot_ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) dev_err(dev, "reboot ack timedout too long: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) "trying reboot\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) goto do_reboot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) case -EPROTO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) case -ESHUTDOWN: /* dev is gone */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) goto error_dev_gone;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) dev_err(dev, "device reboot ack: error %d while waiting for "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) "reboot ack barker - rebooting\n", result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) goto do_reboot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) d_printf(2, dev, "device reboot ack: got ack barker - boot done\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) exit_timeout:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) error_dev_gone:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) d_fnend(4, dev, "(i2400m %p flags 0x%08x) = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) i2400m, flags, result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) error_timeout:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) dev_err(dev, "Timed out waiting for reboot ack\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) result = -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) goto exit_timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) * Read the MAC addr
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) * The position this function reads is fixed in device memory and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) * always available, even without firmware.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) * Note we specify we want to read only six bytes, but provide space
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) * for 16, as we always get it rounded up.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) int i2400m_read_mac_addr(struct i2400m *i2400m)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) struct net_device *net_dev = i2400m->wimax_dev.net_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) struct i2400m_bootrom_header *cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) struct i2400m_bootrom_header ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) u8 ack_pl[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) } __packed ack_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) cmd = i2400m->bm_cmd_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) cmd->command = i2400m_brh_command(I2400M_BRH_READ, 0, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) cmd->target_addr = cpu_to_le32(0x00203fe8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) cmd->data_size = cpu_to_le32(6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) result = i2400m_bm_cmd(i2400m, cmd, sizeof(*cmd),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) &ack_buf.ack, sizeof(ack_buf), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) if (result < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) dev_err(dev, "BM: read mac addr failed: %d\n", result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) goto error_read_mac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) d_printf(2, dev, "mac addr is %pM\n", ack_buf.ack_pl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) if (i2400m->bus_bm_mac_addr_impaired == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) ack_buf.ack_pl[0] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) ack_buf.ack_pl[1] = 0x16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) ack_buf.ack_pl[2] = 0xd3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) get_random_bytes(&ack_buf.ack_pl[3], 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) dev_err(dev, "BM is MAC addr impaired, faking MAC addr to "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) "mac addr is %pM\n", ack_buf.ack_pl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) net_dev->addr_len = ETH_ALEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) memcpy(net_dev->dev_addr, ack_buf.ack_pl, ETH_ALEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) error_read_mac:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) * Initialize a non signed boot
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) * This implies sending some magic values to the device's memory. Note
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) * we convert the values to little endian in the same array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) * declaration.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) int i2400m_dnload_init_nonsigned(struct i2400m *i2400m)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) unsigned i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) if (i2400m->bus_bm_pokes_table) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) while (i2400m->bus_bm_pokes_table[i].address) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) ret = i2400m_download_chunk(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) i2400m,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) &i2400m->bus_bm_pokes_table[i].data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) sizeof(i2400m->bus_bm_pokes_table[i].data),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) i2400m->bus_bm_pokes_table[i].address, 1, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) * Initialize the signed boot process
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) * @i2400m: device descriptor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) * @bcf_hdr: pointer to the firmware header; assumes it is fully in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) * memory (it has gone through basic validation).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) * Returns: 0 if ok, < 0 errno code on error, -ERESTARTSYS if the hw
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) * rebooted.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) * This writes the firmware BCF header to the device using the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) * HASH_PAYLOAD_ONLY command.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) int i2400m_dnload_init_signed(struct i2400m *i2400m,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) const struct i2400m_bcf_hdr *bcf_hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) struct i2400m_bootrom_header cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) struct i2400m_bcf_hdr cmd_pl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) } __packed *cmd_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) struct i2400m_bootrom_header ack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) d_fnstart(5, dev, "(i2400m %p bcf_hdr %p)\n", i2400m, bcf_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) cmd_buf = i2400m->bm_cmd_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) cmd_buf->cmd.command =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) i2400m_brh_command(I2400M_BRH_HASH_PAYLOAD_ONLY, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) cmd_buf->cmd.target_addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) cmd_buf->cmd.data_size = cpu_to_le32(sizeof(cmd_buf->cmd_pl));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) memcpy(&cmd_buf->cmd_pl, bcf_hdr, sizeof(*bcf_hdr));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) ret = i2400m_bm_cmd(i2400m, &cmd_buf->cmd, sizeof(*cmd_buf),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) &ack, sizeof(ack), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) if (ret >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) d_fnend(5, dev, "(i2400m %p bcf_hdr %p) = %d\n", i2400m, bcf_hdr, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) * Initialize the firmware download at the device size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) * Multiplex to the one that matters based on the device's mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) * (signed or non-signed).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) int i2400m_dnload_init(struct i2400m *i2400m,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) const struct i2400m_bcf_hdr *bcf_hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) if (i2400m_boot_is_signed(i2400m)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) d_printf(1, dev, "signed boot\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) result = i2400m_dnload_init_signed(i2400m, bcf_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) if (result == -ERESTARTSYS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) dev_err(dev, "firmware %s: signed boot download "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) "initialization failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) i2400m->fw_name, result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) /* non-signed boot process without pokes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) d_printf(1, dev, "non-signed boot\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) result = i2400m_dnload_init_nonsigned(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) if (result == -ERESTARTSYS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) dev_err(dev, "firmware %s: non-signed download "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) "initialization failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) i2400m->fw_name, result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) * Run consistency tests on the firmware file and load up headers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) * Check for the firmware being made for the i2400m device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) * etc...These checks are mostly informative, as the device will make
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) * them too; but the driver's response is more informative on what
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) * went wrong.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) * This will also look at all the headers present on the firmware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) * file, and update i2400m->fw_bcf_hdr to point to them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) int i2400m_fw_hdr_check(struct i2400m *i2400m,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) const struct i2400m_bcf_hdr *bcf_hdr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) size_t index, size_t offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) unsigned module_type, header_len, major_version, minor_version,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) module_id, module_vendor, date, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) module_type = le32_to_cpu(bcf_hdr->module_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) header_len = sizeof(u32) * le32_to_cpu(bcf_hdr->header_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) major_version = (le32_to_cpu(bcf_hdr->header_version) & 0xffff0000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) >> 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) minor_version = le32_to_cpu(bcf_hdr->header_version) & 0x0000ffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) module_id = le32_to_cpu(bcf_hdr->module_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) module_vendor = le32_to_cpu(bcf_hdr->module_vendor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) date = le32_to_cpu(bcf_hdr->date);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) size = sizeof(u32) * le32_to_cpu(bcf_hdr->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) d_printf(1, dev, "firmware %s #%zd@%08zx: BCF header "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) "type:vendor:id 0x%x:%x:%x v%u.%u (%u/%u B) built %08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) i2400m->fw_name, index, offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) module_type, module_vendor, module_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) major_version, minor_version, header_len, size, date);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) /* Hard errors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) if (major_version != 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) dev_err(dev, "firmware %s #%zd@%08zx: major header version "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) "v%u.%u not supported\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) i2400m->fw_name, index, offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) major_version, minor_version);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) return -EBADF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) if (module_type != 6) { /* built for the right hardware? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) dev_err(dev, "firmware %s #%zd@%08zx: unexpected module "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) "type 0x%x; aborting\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) i2400m->fw_name, index, offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) module_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) return -EBADF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) if (module_vendor != 0x8086) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) dev_err(dev, "firmware %s #%zd@%08zx: unexpected module "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) "vendor 0x%x; aborting\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) i2400m->fw_name, index, offset, module_vendor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) return -EBADF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) if (date < 0x20080300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) dev_warn(dev, "firmware %s #%zd@%08zx: build date %08x "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) "too old; unsupported\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) i2400m->fw_name, index, offset, date);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) * Run consistency tests on the firmware file and load up headers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) * Check for the firmware being made for the i2400m device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) * etc...These checks are mostly informative, as the device will make
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) * them too; but the driver's response is more informative on what
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) * went wrong.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) * This will also look at all the headers present on the firmware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) * file, and update i2400m->fw_hdrs to point to them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) int i2400m_fw_check(struct i2400m *i2400m, const void *bcf, size_t bcf_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) size_t headers = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) const struct i2400m_bcf_hdr *bcf_hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) const void *itr, *next, *top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) size_t slots = 0, used_slots = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) for (itr = bcf, top = itr + bcf_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) itr < top;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) headers++, itr = next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) size_t leftover, offset, header_len, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) leftover = top - itr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) offset = itr - bcf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) if (leftover <= sizeof(*bcf_hdr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) dev_err(dev, "firmware %s: %zu B left at @%zx, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) "not enough for BCF header\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) i2400m->fw_name, leftover, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) bcf_hdr = itr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) /* Only the first header is supposed to be followed by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) * payload */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) header_len = sizeof(u32) * le32_to_cpu(bcf_hdr->header_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) size = sizeof(u32) * le32_to_cpu(bcf_hdr->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) if (headers == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) next = itr + size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) next = itr + header_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) result = i2400m_fw_hdr_check(i2400m, bcf_hdr, headers, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) if (used_slots + 1 >= slots) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) /* +1 -> we need to account for the one we'll
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) * occupy and at least an extra one for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) * always being NULL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) result = i2400m_zrealloc_2x(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) (void **) &i2400m->fw_hdrs, &slots,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) sizeof(i2400m->fw_hdrs[0]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) if (result < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) goto error_zrealloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) i2400m->fw_hdrs[used_slots] = bcf_hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) used_slots++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) if (headers == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) dev_err(dev, "firmware %s: no usable headers found\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) i2400m->fw_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) result = -EBADF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) error_zrealloc:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) * Match a barker to a BCF header module ID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) * The device sends a barker which tells the firmware loader which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) * header in the BCF file has to be used. This does the matching.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) unsigned i2400m_bcf_hdr_match(struct i2400m *i2400m,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) const struct i2400m_bcf_hdr *bcf_hdr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) u32 barker = le32_to_cpu(i2400m->barker->data[0])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) & 0x7fffffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) u32 module_id = le32_to_cpu(bcf_hdr->module_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) & 0x7fffffff; /* high bit used for something else */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) /* special case for 5x50 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) if (barker == I2400M_SBOOT_BARKER && module_id == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) if (module_id == barker)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) const struct i2400m_bcf_hdr *i2400m_bcf_hdr_find(struct i2400m *i2400m)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) const struct i2400m_bcf_hdr **bcf_itr, *bcf_hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) unsigned i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) u32 barker = le32_to_cpu(i2400m->barker->data[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) d_printf(2, dev, "finding BCF header for barker %08x\n", barker);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345) if (barker == I2400M_NBOOT_BARKER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) bcf_hdr = i2400m->fw_hdrs[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) d_printf(1, dev, "using BCF header #%u/%08x for non-signed "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) "barker\n", 0, le32_to_cpu(bcf_hdr->module_id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) return bcf_hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) for (bcf_itr = i2400m->fw_hdrs; *bcf_itr != NULL; bcf_itr++, i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) bcf_hdr = *bcf_itr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) if (i2400m_bcf_hdr_match(i2400m, bcf_hdr)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) d_printf(1, dev, "hit on BCF hdr #%u/%08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) i, le32_to_cpu(bcf_hdr->module_id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) return bcf_hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) d_printf(1, dev, "miss on BCF hdr #%u/%08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) i, le32_to_cpu(bcf_hdr->module_id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) dev_err(dev, "cannot find a matching BCF header for barker %08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) barker);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) * Download the firmware to the device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) * @i2400m: device descriptor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) * @bcf: pointer to loaded (and minimally verified for consistency)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) * firmware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) * @bcf_size: size of the @bcf buffer (header plus payloads)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) * The process for doing this is described in this file's header.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) * Note we only reinitialize boot-mode if the flags say so. Some hw
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) * iterations need it, some don't. In any case, if we loop, we always
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) * need to reinitialize the boot room, hence the flags modification.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) int i2400m_fw_dnload(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) size_t fw_size, enum i2400m_bri flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) int count = i2400m->bus_bm_retries;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) const struct i2400m_bcf_hdr *bcf_hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) size_t bcf_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) d_fnstart(5, dev, "(i2400m %p bcf %p fw size %zu)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) i2400m, bcf, fw_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) i2400m->boot_mode = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) wmb(); /* Make sure other readers see it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) hw_reboot:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) if (count-- == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) ret = -ERESTARTSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) dev_err(dev, "device rebooted too many times, aborting\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) goto error_too_many_reboots;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) if (flags & I2400M_BRI_MAC_REINIT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) ret = i2400m_bootrom_init(i2400m, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) dev_err(dev, "bootrom init failed: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) goto error_bootrom_init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) flags |= I2400M_BRI_MAC_REINIT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) * Initialize the download, push the bytes to the device and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) * then jump to the new firmware. Note @ret is passed with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) * offset of the jump instruction to _dnload_finalize()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415) * Note we need to use the BCF header in the firmware image
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) * that matches the barker that the device sent when it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) * rebooted, so it has to be passed along.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) ret = -EBADF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) bcf_hdr = i2400m_bcf_hdr_find(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) if (bcf_hdr == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422) goto error_bcf_hdr_find;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) ret = i2400m_dnload_init(i2400m, bcf_hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) if (ret == -ERESTARTSYS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) goto error_dev_rebooted;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) goto error_dnload_init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) * bcf_size refers to one header size plus the fw sections size
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) * indicated by the header,ie. if there are other extended headers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) * at the tail, they are not counted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) bcf_size = sizeof(u32) * le32_to_cpu(bcf_hdr->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) ret = i2400m_dnload_bcf(i2400m, bcf, bcf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) if (ret == -ERESTARTSYS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) goto error_dev_rebooted;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) dev_err(dev, "fw %s: download failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) i2400m->fw_name, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) goto error_dnload_bcf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) ret = i2400m_dnload_finalize(i2400m, bcf_hdr, bcf, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) if (ret == -ERESTARTSYS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) goto error_dev_rebooted;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) dev_err(dev, "fw %s: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) "download finalization failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) i2400m->fw_name, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) goto error_dnload_finalize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) d_printf(2, dev, "fw %s successfully uploaded\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) i2400m->fw_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) i2400m->boot_mode = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) wmb(); /* Make sure i2400m_msg_to_dev() sees boot_mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) error_dnload_finalize:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) error_dnload_bcf:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) error_dnload_init:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) error_bcf_hdr_find:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) error_bootrom_init:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) error_too_many_reboots:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) d_fnend(5, dev, "(i2400m %p bcf %p size %zu) = %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) i2400m, bcf, fw_size, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) error_dev_rebooted:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) dev_err(dev, "device rebooted, %d tries left\n", count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) /* we got the notification already, no need to wait for it again */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) flags |= I2400M_BRI_SOFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) goto hw_reboot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) int i2400m_fw_bootstrap(struct i2400m *i2400m, const struct firmware *fw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) enum i2400m_bri flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) const struct i2400m_bcf_hdr *bcf; /* Firmware data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485) bcf = (void *) fw->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) ret = i2400m_fw_check(i2400m, bcf, fw->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) if (ret >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) ret = i2400m_fw_dnload(i2400m, bcf, fw->size, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) dev_err(dev, "%s: cannot use: %d, skipping\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) i2400m->fw_name, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) kfree(i2400m->fw_hdrs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) i2400m->fw_hdrs = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) /* Refcounted container for firmware data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) struct i2400m_fw {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) struct kref kref;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) const struct firmware *fw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) void i2400m_fw_destroy(struct kref *kref)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) struct i2400m_fw *i2400m_fw =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) container_of(kref, struct i2400m_fw, kref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) release_firmware(i2400m_fw->fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512) kfree(i2400m_fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) struct i2400m_fw *i2400m_fw_get(struct i2400m_fw *i2400m_fw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) if (i2400m_fw != NULL && i2400m_fw != (void *) ~0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) kref_get(&i2400m_fw->kref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) return i2400m_fw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) void i2400m_fw_put(struct i2400m_fw *i2400m_fw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) kref_put(&i2400m_fw->kref, i2400m_fw_destroy);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) * i2400m_dev_bootstrap - Bring the device to a known state and upload firmware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) * @i2400m: device descriptor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) * Returns: >= 0 if ok, < 0 errno code on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) * This sets up the firmware upload environment, loads the firmware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) * file from disk, verifies and then calls the firmware upload process
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) * per se.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) * Can be called either from probe, or after a warm reset. Can not be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) * called from within an interrupt. All the flow in this code is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) * single-threade; all I/Os are synchronous.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) int i2400m_dev_bootstrap(struct i2400m *i2400m, enum i2400m_bri flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) int ret, itr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) struct i2400m_fw *i2400m_fw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) const struct firmware *fw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) const char *fw_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) spin_lock(&i2400m->rx_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) i2400m_fw = i2400m_fw_get(i2400m->fw_cached);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) spin_unlock(&i2400m->rx_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) if (i2400m_fw == (void *) ~0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) dev_err(dev, "can't load firmware now!");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) } else if (i2400m_fw != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) dev_info(dev, "firmware %s: loading from cache\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) i2400m->fw_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) ret = i2400m_fw_bootstrap(i2400m, i2400m_fw->fw, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) i2400m_fw_put(i2400m_fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) /* Load firmware files to memory. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) for (itr = 0, ret = -ENOENT; ; itr++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) fw_name = i2400m->bus_fw_names[itr];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) if (fw_name == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) dev_err(dev, "Could not find a usable firmware image\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) d_printf(1, dev, "trying firmware %s (%d)\n", fw_name, itr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) ret = request_firmware(&fw, fw_name, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582) dev_err(dev, "fw %s: cannot load file: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) fw_name, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) i2400m->fw_name = fw_name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) ret = i2400m_fw_bootstrap(i2400m, fw, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) release_firmware(fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) if (ret >= 0) /* firmware loaded successfully */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) i2400m->fw_name = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) EXPORT_SYMBOL_GPL(i2400m_dev_bootstrap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) void i2400m_fw_cache(struct i2400m *i2400m)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) struct i2400m_fw *i2400m_fw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) struct device *dev = i2400m_dev(i2400m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) /* if there is anything there, free it -- now, this'd be weird */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) spin_lock(&i2400m->rx_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608) i2400m_fw = i2400m->fw_cached;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) spin_unlock(&i2400m->rx_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) if (i2400m_fw != NULL && i2400m_fw != (void *) ~0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) i2400m_fw_put(i2400m_fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) WARN(1, "%s:%u: still cached fw still present?\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) __func__, __LINE__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) if (i2400m->fw_name == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) dev_err(dev, "firmware n/a: can't cache\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) i2400m_fw = (void *) ~0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) i2400m_fw = kzalloc(sizeof(*i2400m_fw), GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) if (i2400m_fw == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) kref_init(&i2400m_fw->kref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) result = request_firmware(&i2400m_fw->fw, i2400m->fw_name, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) if (result < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) dev_err(dev, "firmware %s: failed to cache: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629) i2400m->fw_name, result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) kfree(i2400m_fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) i2400m_fw = (void *) ~0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) dev_info(dev, "firmware %s: cached\n", i2400m->fw_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) spin_lock(&i2400m->rx_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) i2400m->fw_cached = i2400m_fw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637) spin_unlock(&i2400m->rx_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641) void i2400m_fw_uncache(struct i2400m *i2400m)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) struct i2400m_fw *i2400m_fw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) spin_lock(&i2400m->rx_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) i2400m_fw = i2400m->fw_cached;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) i2400m->fw_cached = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) spin_unlock(&i2400m->rx_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) if (i2400m_fw != NULL && i2400m_fw != (void *) ~0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) i2400m_fw_put(i2400m_fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653)