mirror of
https://review.coreboot.org/flashrom.git
synced 2025-10-27 19:32:11 +01:00
nv_sma_spi: Add Nvidia SMA Programmer
Add initial support for System Management Agent (SMA) programmer. SMA is a SOC which is working as a side band management on Nvidia server board. One of its functionality is to flash firmware to other components. Test: 1. Build flashrom with this change. 2. Run operation: erase, write, read 3. All operations completed with expected performance. NV_SMA_SPI has been tested with the following SPI flash models: w25r128jw w25r64jv w25q16v Change-Id: I6b2522788db3dcee2b30faff29f605cede8c0eaf Co-Developed-by: Gilbert Chen <gilbertc@nvidia.com> Co-Developed-by: Willie Thai <wthai@nvidia.com> Signed-off-by: Willie Thai <wthai@nvidia.com> Signed-off-by: Gilbert Chen <gilbertc@nvidia.com> Reviewed-on: https://review.coreboot.org/c/flashrom/+/88816 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Peter Marheine <pmarheine@chromium.org> Reviewed-by: Anastasia Klimchuk <aklm@chromium.org>
This commit is contained in:
committed by
Anastasia Klimchuk
parent
c54d068418
commit
db43ab2989
@@ -81,6 +81,8 @@ struct io_mock {
|
||||
int (*libusb_submit_transfer)(void *state, struct libusb_transfer *transfer);
|
||||
void (*libusb_free_transfer)(void *state, struct libusb_transfer *transfer);
|
||||
int (*libusb_handle_events_timeout)(void *state, libusb_context *ctx, struct timeval *tv);
|
||||
int (*libusb_bulk_transfer)(void *state, libusb_device_handle *devh, unsigned char endpoint,
|
||||
unsigned char *data, int length, int *actual_length, unsigned int timeout);
|
||||
|
||||
/* POSIX File I/O */
|
||||
int (*iom_open)(void *state, const char *pathname, int flags, mode_t mode);
|
||||
|
||||
@@ -118,6 +118,14 @@ int __wrap_libusb_get_config_descriptor(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __wrap_libusb_get_active_config_descriptor(libusb_device *dev, struct libusb_config_descriptor **config)
|
||||
{
|
||||
LOG_ME;
|
||||
if (get_io() && get_io()->libusb_get_config_descriptor)
|
||||
return get_io()->libusb_get_config_descriptor(get_io()->state, dev, 0, config);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __wrap_libusb_free_config_descriptor(struct libusb_config_descriptor *config)
|
||||
{
|
||||
LOG_ME;
|
||||
@@ -155,6 +163,16 @@ int __wrap_libusb_control_transfer(libusb_device_handle *devh, uint8_t bmRequest
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __wrap_libusb_bulk_transfer(libusb_device_handle *devh, unsigned char endpoint,
|
||||
unsigned char *data, int length, int *actual_length, unsigned int timeout)
|
||||
{
|
||||
LOG_ME;
|
||||
if (get_io() && get_io()->libusb_bulk_transfer)
|
||||
return get_io()->libusb_bulk_transfer(get_io()->state, devh, endpoint, data,
|
||||
length, actual_length, timeout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __wrap_libusb_release_interface(libusb_device_handle *devh, int interface_number)
|
||||
{
|
||||
LOG_ME;
|
||||
|
||||
@@ -29,6 +29,7 @@ uint8_t __wrap_libusb_get_device_address(libusb_device *dev);
|
||||
int __wrap_libusb_get_device_descriptor(libusb_device *dev, struct libusb_device_descriptor *desc);
|
||||
int __wrap_libusb_get_config_descriptor(
|
||||
libusb_device *dev, uint8_t config_index, struct libusb_config_descriptor **config);
|
||||
int __wrap_libusb_get_active_config_descriptor(libusb_device *dev, struct libusb_config_descriptor **config);
|
||||
void __wrap_libusb_free_config_descriptor(struct libusb_config_descriptor *config);
|
||||
int __wrap_libusb_get_configuration(libusb_device_handle *devh, int *config);
|
||||
int __wrap_libusb_set_configuration(libusb_device_handle *devh, int config);
|
||||
@@ -36,6 +37,8 @@ int __wrap_libusb_claim_interface(libusb_device_handle *devh, int interface_numb
|
||||
int __wrap_libusb_control_transfer(libusb_device_handle *devh, uint8_t bmRequestType,
|
||||
uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data,
|
||||
uint16_t wLength, unsigned int timeout);
|
||||
int __wrap_libusb_bulk_transfer(libusb_device_handle *devh, unsigned char endpoint,
|
||||
unsigned char *data, int length, int *actual_length, unsigned int timeout);
|
||||
int __wrap_libusb_release_interface(libusb_device_handle *devh, int interface_number);
|
||||
void __wrap_libusb_close(libusb_device_handle *devh);
|
||||
libusb_device *__wrap_libusb_ref_device(libusb_device *dev);
|
||||
|
||||
@@ -95,11 +95,13 @@ mocks = [
|
||||
'-Wl,--wrap=libusb_get_device_address',
|
||||
'-Wl,--wrap=libusb_get_device_descriptor',
|
||||
'-Wl,--wrap=libusb_get_config_descriptor',
|
||||
'-Wl,--wrap=libusb_get_active_config_descriptor',
|
||||
'-Wl,--wrap=libusb_free_config_descriptor',
|
||||
'-Wl,--wrap=libusb_get_configuration',
|
||||
'-Wl,--wrap=libusb_set_configuration',
|
||||
'-Wl,--wrap=libusb_claim_interface',
|
||||
'-Wl,--wrap=libusb_control_transfer',
|
||||
'-Wl,--wrap=libusb_bulk_transfer',
|
||||
'-Wl,--wrap=libusb_release_interface',
|
||||
'-Wl,--wrap=libusb_ref_device',
|
||||
'-Wl,--wrap=libusb_unref_device',
|
||||
|
||||
138
tests/nv_sma_spi.c
Normal file
138
tests/nv_sma_spi.c
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* This file is part of the flashrom project.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only
|
||||
* SPDX-FileCopyrightText: 2025 NVIDIA CORPORATION
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lifecycle.h"
|
||||
|
||||
#if CONFIG_NV_SMA_SPI == 1
|
||||
|
||||
/* Constants from nv_sma_spi.c */
|
||||
#define NV_SMA_INTERFACE_CLASS 0xFF /* Vendor Specific */
|
||||
#define NV_SMA_INTERFACE_SUBCLASS 0x3F /* Nvidia assigned class */
|
||||
#define NV_SMA_INTERFACE_PROTOCOL 0x01 /* Protocol v1 */
|
||||
|
||||
static ssize_t nv_sma_spi_libusb_get_device_list(void *state, libusb_context *ctx, libusb_device ***list)
|
||||
{
|
||||
*list = calloc(1, sizeof(**list));
|
||||
assert_non_null(*list);
|
||||
|
||||
/*
|
||||
* libusb_device is opaque type, it is tossed around between libusb functions but always
|
||||
* stays opaque to the caller.
|
||||
* Given that all libusb functions are mocked in tests, and nv_sma_spi test is mocking
|
||||
* only one device, we don't need to initialise libusb_device.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void nv_sma_spi_libusb_free_device_list(void *state, libusb_device **list, int unref_devices)
|
||||
{
|
||||
free(list);
|
||||
}
|
||||
|
||||
static int nv_sma_spi_libusb_get_device_descriptor(
|
||||
void *state, libusb_device *dev, struct libusb_device_descriptor *desc)
|
||||
{
|
||||
desc->idVendor = 0x0955; /* NVIDIA_VID */
|
||||
desc->idProduct = 0xcf11; /* NV_SMA_PID */
|
||||
desc->bNumConfigurations = 1;
|
||||
desc->bcdDevice = 0x0100; /* Device version 1.0.0 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nv_sma_spi_libusb_get_config_descriptor(
|
||||
void *state, libusb_device *dev, uint8_t config_index, struct libusb_config_descriptor **config)
|
||||
{
|
||||
*config = calloc(1, sizeof(**config));
|
||||
assert_non_null(*config);
|
||||
|
||||
struct libusb_endpoint_descriptor *tmp_endpoint = calloc(2, sizeof(*tmp_endpoint));
|
||||
assert_non_null(tmp_endpoint);
|
||||
struct libusb_interface_descriptor *tmp_interface_desc = calloc(1, sizeof(*tmp_interface_desc));
|
||||
assert_non_null(tmp_interface_desc);
|
||||
struct libusb_interface *tmp_interface = calloc(1, sizeof(*tmp_interface));
|
||||
assert_non_null(tmp_interface);
|
||||
|
||||
/* OUT endpoint (write) */
|
||||
tmp_endpoint[0].bEndpointAddress = 0x01;
|
||||
tmp_endpoint[0].bmAttributes = 0x02; /* Bulk transfer */
|
||||
/* IN endpoint (read) */
|
||||
tmp_endpoint[1].bEndpointAddress = 0x81;
|
||||
tmp_endpoint[1].bmAttributes = 0x02; /* Bulk transfer */
|
||||
|
||||
tmp_interface_desc->bInterfaceClass = NV_SMA_INTERFACE_CLASS;
|
||||
tmp_interface_desc->bInterfaceSubClass = NV_SMA_INTERFACE_SUBCLASS;
|
||||
tmp_interface_desc->bInterfaceProtocol = NV_SMA_INTERFACE_PROTOCOL;
|
||||
tmp_interface_desc->bInterfaceNumber = 0;
|
||||
tmp_interface_desc->bNumEndpoints = 2; /* in_endpoint and out_endpoint */
|
||||
tmp_interface_desc->endpoint = tmp_endpoint;
|
||||
|
||||
tmp_interface->num_altsetting = 1;
|
||||
tmp_interface->altsetting = tmp_interface_desc;
|
||||
|
||||
(*config)->bConfigurationValue = 0;
|
||||
(*config)->bNumInterfaces = 1;
|
||||
(*config)->interface = tmp_interface;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nv_sma_spi_libusb_free_config_descriptor(void *state, struct libusb_config_descriptor *config)
|
||||
{
|
||||
free((void *)config->interface->altsetting->endpoint);
|
||||
free((void *)config->interface->altsetting);
|
||||
free((void *)config->interface);
|
||||
free(config);
|
||||
}
|
||||
|
||||
static int nv_sma_spi_libusb_bulk_transfer(void *state, libusb_device_handle *devh, unsigned char endpoint,
|
||||
unsigned char *data, int length, int *actual_length, unsigned int timeout)
|
||||
{
|
||||
if (data && length == 512) {
|
||||
int all_zero = 1;
|
||||
for (int i = 0; i < 512; ++i) {
|
||||
if (data[i] != 0) {
|
||||
all_zero = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (all_zero) {
|
||||
if (actual_length)
|
||||
*actual_length = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (actual_length)
|
||||
*actual_length = length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nv_sma_spi_basic_lifecycle_test_success(void **state)
|
||||
{
|
||||
struct io_mock_fallback_open_state nv_sma_spi_fallback_open_state = {
|
||||
.noc = 0,
|
||||
.paths = { NULL },
|
||||
};
|
||||
const struct io_mock nv_sma_spi_io = {
|
||||
.libusb_get_device_list = nv_sma_spi_libusb_get_device_list,
|
||||
.libusb_free_device_list = nv_sma_spi_libusb_free_device_list,
|
||||
.libusb_get_device_descriptor = nv_sma_spi_libusb_get_device_descriptor,
|
||||
.libusb_get_config_descriptor = nv_sma_spi_libusb_get_config_descriptor,
|
||||
.libusb_free_config_descriptor = nv_sma_spi_libusb_free_config_descriptor,
|
||||
.libusb_bulk_transfer = nv_sma_spi_libusb_bulk_transfer,
|
||||
.fallback_open_state = &nv_sma_spi_fallback_open_state,
|
||||
};
|
||||
run_basic_lifecycle(state, &nv_sma_spi_io, &programmer_nv_sma_spi, "");
|
||||
}
|
||||
|
||||
#else
|
||||
SKIP_TEST(nv_sma_spi_basic_lifecycle_test_success)
|
||||
#endif /* CONFIG_NV_SMA_SPI */
|
||||
@@ -528,6 +528,7 @@ int main(int argc, char *argv[])
|
||||
cmocka_unit_test(ch341a_spi_basic_lifecycle_test_success),
|
||||
cmocka_unit_test(ch341a_spi_probe_lifecycle_test_success),
|
||||
cmocka_unit_test(spidriver_probe_lifecycle_test_success),
|
||||
cmocka_unit_test(nv_sma_spi_basic_lifecycle_test_success),
|
||||
};
|
||||
ret |= cmocka_run_group_tests_name("lifecycle.c tests", lifecycle_tests, NULL, NULL);
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ void realtek_mst_no_allow_brick_test_success(void **state);
|
||||
void ch341a_spi_basic_lifecycle_test_success(void **state);
|
||||
void ch341a_spi_probe_lifecycle_test_success(void **state);
|
||||
void spidriver_probe_lifecycle_test_success(void **state);
|
||||
void nv_sma_spi_basic_lifecycle_test_success(void **state);
|
||||
|
||||
/* layout.c */
|
||||
void included_regions_dont_overlap_test_success(void **state);
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#ifndef _USB_UNITTESTS_H_
|
||||
#define _USB_UNITTESTS_H_
|
||||
|
||||
#if CONFIG_RAIDEN_DEBUG_SPI == 1 || CONFIG_DEDIPROG == 1 || CONFIG_CH341A_SPI == 1
|
||||
#if CONFIG_RAIDEN_DEBUG_SPI == 1 || CONFIG_DEDIPROG == 1 || CONFIG_CH341A_SPI == 1 || CONFIG_NV_SMA_SPI == 1
|
||||
|
||||
#include <libusb.h>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user