Misc HW patches

- Fix SD cards wired in SPI mode
 - Fix microvm-only build by selecting Kconfig ACPI_PCI
 - Fix legacy Intel SMT info removing 'x-vendor-cpuid-only-v2' property check
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmiSP8sACgkQ4+MsLN6t
 wN52pw//R2z+DDdtezzOGIsCS8lmcI+sp0rM2UXA0LLuqH4++/SNgSOuH/yr0k9g
 3DxvYxQ+zgx2gxrxG9T/KlGYdl6lE3mb9cWBah8+4UUeKuji2Zt3dh0LrZoIt9A0
 EfHfPihpmVxf0OWXzDUsu3WdUyso3QHHJWVqiUCqnhvNsx1ZSAA7gOUOURL8YUEt
 BsCJ4ufRJA6SRqLgiOQHSn1zRVwEmXZWRt6lqWx45ynzxkquaA+pvGY3UlzUsw4b
 5XyBL5Wyq1K7/FTXVXiMCYSNhgSUEbKy7Agnrr1i5s+/XfBjXMuzGFwjAWdCdwVW
 /Kqqndlu6COla9APndqjfMhCHU6Ql8KyKqb9HImvZyMks4QNiX3c18CjAuCVoIzE
 GxoXaTQ/y+Dv4tarI4EEP5m4P3gka7QVekhbSLQZJAdNDrt0QlOgmyvDLin4tQho
 ot/jXYTnbPZBfyZyecFnY/6Uszr5dcrI1bXdEYhiy3LZUWkzM2xNq9BJ6Y2495Ad
 ryqZ09UzVK8Rn6KaXTXx926eFWxFVN2VOolmLJ50D8MQfwrmMAsHtHl+qoa6T6Ta
 ezgnuHwONjNYAgGQgVz483/nKu4TvQ6q9bATYrZIumBITXLgVqS7GRFZ9Q17Y+V4
 UHlIJ/Ay32KkMAKD+cNj01s7g6nK3YS2tP7tt16IOQHhVmsNvGE=
 =Rq7l
 -----END PGP SIGNATURE-----

Merge tag 'hw-misc-20250805' of https://github.com/philmd/qemu into staging

Misc HW patches

- Fix SD cards wired in SPI mode
- Fix microvm-only build by selecting Kconfig ACPI_PCI
- Fix legacy Intel SMT info removing 'x-vendor-cpuid-only-v2' property check

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmiSP8sACgkQ4+MsLN6t
# wN52pw//R2z+DDdtezzOGIsCS8lmcI+sp0rM2UXA0LLuqH4++/SNgSOuH/yr0k9g
# 3DxvYxQ+zgx2gxrxG9T/KlGYdl6lE3mb9cWBah8+4UUeKuji2Zt3dh0LrZoIt9A0
# EfHfPihpmVxf0OWXzDUsu3WdUyso3QHHJWVqiUCqnhvNsx1ZSAA7gOUOURL8YUEt
# BsCJ4ufRJA6SRqLgiOQHSn1zRVwEmXZWRt6lqWx45ynzxkquaA+pvGY3UlzUsw4b
# 5XyBL5Wyq1K7/FTXVXiMCYSNhgSUEbKy7Agnrr1i5s+/XfBjXMuzGFwjAWdCdwVW
# /Kqqndlu6COla9APndqjfMhCHU6Ql8KyKqb9HImvZyMks4QNiX3c18CjAuCVoIzE
# GxoXaTQ/y+Dv4tarI4EEP5m4P3gka7QVekhbSLQZJAdNDrt0QlOgmyvDLin4tQho
# ot/jXYTnbPZBfyZyecFnY/6Uszr5dcrI1bXdEYhiy3LZUWkzM2xNq9BJ6Y2495Ad
# ryqZ09UzVK8Rn6KaXTXx926eFWxFVN2VOolmLJ50D8MQfwrmMAsHtHl+qoa6T6Ta
# ezgnuHwONjNYAgGQgVz483/nKu4TvQ6q9bATYrZIumBITXLgVqS7GRFZ9Q17Y+V4
# UHlIJ/Ay32KkMAKD+cNj01s7g6nK3YS2tP7tt16IOQHhVmsNvGE=
# =Rq7l
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 05 Aug 2025 13:30:51 EDT
# gpg:                using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE
# gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full]
# Primary key fingerprint: FAAB E75E 1291 7221 DCFD  6BB2 E3E3 2C2C DEAD C0DE

* tag 'hw-misc-20250805' of https://github.com/philmd/qemu:
  hw/i386/microvm: Explicitly select ACPI_PCI
  target/i386/cpu: Move addressable ID encoding out of compat property in CPUID[0x1]
  tests/functional: Test SD cards in SPI mode (using sifive_u machine)
  hw/sd/sdcard: Remove SDState::mode field
  hw/sd/sdcard: Disable checking STBY mode in SPI SEND_CSD/CID
  hw/sd/sdcard: Factor spi_cmd_SEND_CxD() out
  hw/sd/sdcard: Allow using SWITCH_FUNCTION in more SPI states
  hw/sd/sdcard: Use complete SEND_OP_COND implementation in SPI mode
  hw/sd/sdcard: Implement SPI R2 return value
  hw/sd/sdcard: Fill SPI response bits in card code
  hw/sd/sdbus: Provide buffer size to sdbus_do_command()
  hw/sd/sdcard: Factor sd_response_size() out
  hw/sd/sdcard: Do not ignore errors in sd_cmd_to_sendingdata()

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2025-08-05 15:05:28 -04:00
commit d2d08975fc
15 changed files with 251 additions and 167 deletions

View file

@ -1695,6 +1695,7 @@ S: Supported
F: docs/system/riscv/sifive_u.rst
F: hw/*/*sifive*.c
F: include/hw/*/*sifive*.h
F: tests/functional/test_riscv64_sifive_u.py
AMD Microblaze-V Generic Board
M: Sai Pavan Boddu <sai.pavan.boddu@amd.com>

View file

@ -131,6 +131,7 @@ config MICROVM
select I8259
select MC146818RTC
select VIRTIO_MMIO
select ACPI_PCI
select ACPI_HW_REDUCED
select PCI_EXPRESS_GENERIC_BRIDGE
select USB_XHCI_SYSBUS

View file

@ -233,7 +233,7 @@ static void allwinner_sdhost_send_command(AwSdHostState *s)
{
SDRequest request;
uint8_t resp[16];
int rlen;
size_t rlen;
/* Auto clear load flag */
s->command &= ~SD_CMDR_LOAD;
@ -246,10 +246,7 @@ static void allwinner_sdhost_send_command(AwSdHostState *s)
request.arg = s->command_arg;
/* Send request to SD bus */
rlen = sdbus_do_command(&s->sdbus, &request, resp);
if (rlen < 0) {
goto error;
}
rlen = sdbus_do_command(&s->sdbus, &request, resp, sizeof(resp));
/* If the command has a response, store it in the response registers */
if ((s->command & SD_CMDR_RESPONSE)) {

View file

@ -113,15 +113,12 @@ static void bcm2835_sdhost_send_command(BCM2835SDHostState *s)
{
SDRequest request;
uint8_t rsp[16];
int rlen;
size_t rlen;
request.cmd = s->cmd & SDCMD_CMD_MASK;
request.arg = s->cmdarg;
rlen = sdbus_do_command(&s->sdbus, &request, rsp);
if (rlen < 0) {
goto error;
}
rlen = sdbus_do_command(&s->sdbus, &request, rsp, sizeof(rsp));
if (!(s->cmd & SDCMD_NO_RESPONSE)) {
if (rlen == 0 || (rlen == 4 && (s->cmd & SDCMD_LONG_RESPONSE))) {
goto error;

View file

@ -90,7 +90,8 @@ void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts)
}
}
int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
size_t sdbus_do_command(SDBus *sdbus, SDRequest *req,
uint8_t *resp, size_t respsz)
{
SDState *card = get_card(sdbus);
@ -98,7 +99,7 @@ int sdbus_do_command(SDBus *sdbus, SDRequest *req, uint8_t *response)
if (card) {
SDCardClass *sc = SDMMC_COMMON_GET_CLASS(card);
return sc->do_command(card, req, response);
return sc->do_command(card, req, resp, respsz);
}
return 0;

View file

@ -130,7 +130,8 @@ static void omap_mmc_command(OMAPMMCState *host, int cmd, int dir,
sd_rsp_type_t resptype, int init)
{
uint32_t rspstatus, mask;
int rsplen, timeout;
size_t rsplen;
int timeout;
SDRequest request;
uint8_t response[16];
@ -157,7 +158,7 @@ static void omap_mmc_command(OMAPMMCState *host, int cmd, int dir,
request.arg = host->arg;
request.crc = 0; /* FIXME */
rsplen = sdbus_do_command(&host->sdbus, &request, response);
rsplen = sdbus_do_command(&host->sdbus, &request, response, sizeof(response));
/* TODO: validate CRCs */
switch (resptype) {

View file

@ -173,14 +173,12 @@ static void pl181_do_command(PL181State *s)
{
SDRequest request;
uint8_t response[16];
int rlen;
size_t rlen;
request.cmd = s->cmd & PL181_CMD_INDEX;
request.arg = s->cmdarg;
trace_pl181_command_send(request.cmd, request.arg);
rlen = sdbus_do_command(&s->sdbus, &request, response);
if (rlen < 0)
goto error;
rlen = sdbus_do_command(&s->sdbus, &request, response, sizeof(response));
if (s->cmd & PL181_CMD_RESPONSE) {
if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
goto error;

View file

@ -61,6 +61,7 @@
typedef enum {
sd_r0 = 0, /* no response */
sd_r1, /* normal response command */
spi_r2, /* STATUS */
sd_r2_i, /* CID register */
sd_r2_s, /* CSD register */
sd_r3, /* OCR register */
@ -146,7 +147,6 @@ struct SDState {
/* Runtime changeables */
uint32_t mode; /* current card mode, one of SDCardModes */
int32_t state; /* current card state, one of SDCardStates */
uint32_t vhs;
bool wp_switch;
@ -247,6 +247,7 @@ static const char *sd_response_name(sd_rsp_type_t rsp)
static const char *response_name[] = {
[sd_r0] = "RESP#0 (no response)",
[sd_r1] = "RESP#1 (normal cmd)",
[spi_r2] = "RESP#2 (STATUS reg)",
[sd_r2_i] = "RESP#2 (CID reg)",
[sd_r2_s] = "RESP#2 (CSD reg)",
[sd_r3] = "RESP#3 (OCR reg)",
@ -313,27 +314,24 @@ static void sd_set_voltage(SDState *sd, uint16_t millivolts)
}
}
static void sd_set_mode(SDState *sd)
static enum SDCardModes sd_mode(SDState *sd)
{
switch (sd->state) {
case sd_inactive_state:
sd->mode = sd_inactive;
break;
return sd_inactive;
case sd_idle_state:
case sd_ready_state:
case sd_identification_state:
sd->mode = sd_card_identification_mode;
break;
return sd_card_identification_mode;
case sd_standby_state:
case sd_transfer_state:
case sd_sendingdata_state:
case sd_receivingdata_state:
case sd_programming_state:
case sd_disconnect_state:
sd->mode = sd_data_transfer_mode;
break;
return sd_data_transfer_mode;
default:
g_assert_not_reached();
}
}
@ -729,16 +727,82 @@ static int sd_req_crc_validate(SDRequest *req)
return sd_crc7(buffer, 5) != req->crc; /* TODO */
}
static size_t sd_response_size(SDState *sd, sd_rsp_type_t rtype)
{
switch (rtype) {
case sd_r1:
case sd_r1b:
return sd_is_spi(sd) ? 1 : 4;
case spi_r2:
assert(sd_is_spi(sd));
return 2;
case sd_r2_i:
case sd_r2_s:
assert(!sd_is_spi(sd));
return 16;
case sd_r3:
case sd_r7:
return sd_is_spi(sd) ? 5 : 4;
case sd_r6:
assert(!sd_is_spi(sd));
return 4;
case sd_r0:
case sd_illegal:
return sd_is_spi(sd) ? 1 : 0;
default:
g_assert_not_reached();
}
}
static void sd_response_r1_make(SDState *sd, uint8_t *response)
{
stl_be_p(response, sd->card_status);
if (sd_is_spi(sd)) {
response[0] = sd->state == sd_idle_state
&& !FIELD_EX32(sd->ocr, OCR, CARD_POWER_UP);
response[0] |= FIELD_EX32(sd->card_status, CSR, ERASE_RESET) << 1;
response[0] |= FIELD_EX32(sd->card_status, CSR, ILLEGAL_COMMAND) << 2;
response[0] |= FIELD_EX32(sd->card_status, CSR, COM_CRC_ERROR) << 3;
response[0] |= FIELD_EX32(sd->card_status, CSR, ERASE_SEQ_ERROR) << 4;
response[0] |= FIELD_EX32(sd->card_status, CSR, ADDRESS_ERROR) << 5;
response[0] |= FIELD_EX32(sd->card_status, CSR, BLOCK_LEN_ERROR) << 6;
response[0] |= 0 << 7;
} else {
stl_be_p(response, sd->card_status);
}
/* Clear the "clear on read" status bits */
sd->card_status &= ~CARD_STATUS_C;
}
static void spi_response_r2_make(SDState *sd, uint8_t *resp)
{
/* Prepend R1 */
sd_response_r1_make(sd, resp);
resp[1] = FIELD_EX32(sd->card_status, CSR, CARD_IS_LOCKED) << 0;
resp[1] |= (FIELD_EX32(sd->card_status, CSR, LOCK_UNLOCK_FAILED)
|| FIELD_EX32(sd->card_status, CSR, WP_ERASE_SKIP)) << 1;
resp[1] |= FIELD_EX32(sd->card_status, CSR, ERROR) << 2;
resp[1] |= FIELD_EX32(sd->card_status, CSR, CC_ERROR) << 3;
resp[1] |= FIELD_EX32(sd->card_status, CSR, CARD_ECC_FAILED) << 4;
resp[1] |= FIELD_EX32(sd->card_status, CSR, WP_VIOLATION) << 5;
resp[1] |= FIELD_EX32(sd->card_status, CSR, ERASE_PARAM) << 6;
resp[1] |= FIELD_EX32(sd->card_status, CSR, OUT_OF_RANGE) << 7;
}
static void sd_response_r3_make(SDState *sd, uint8_t *response)
{
if (sd_is_spi(sd)) {
/* Prepend R1 */
sd_response_r1_make(sd, response);
response++;
}
stl_be_p(response, sd->ocr & ACMD41_R3_MASK);
}
@ -756,6 +820,11 @@ static void sd_response_r6_make(SDState *sd, uint8_t *response)
static void sd_response_r7_make(SDState *sd, uint8_t *response)
{
if (sd_is_spi(sd)) {
/* Prepend R1 */
sd_response_r1_make(sd, response);
response++;
}
stl_be_p(response, sd->vhs);
}
@ -952,7 +1021,7 @@ static const VMStateDescription sd_vmstate = {
.minimum_version_id = 2,
.pre_load = sd_vmstate_pre_load,
.fields = (const VMStateField[]) {
VMSTATE_UINT32(mode, SDState),
VMSTATE_UNUSED(4),
VMSTATE_INT32(state, SDState),
VMSTATE_UINT8_ARRAY(cid, SDState, 16),
VMSTATE_UINT8_ARRAY(csd, SDState, 16),
@ -1252,7 +1321,7 @@ static sd_rsp_type_t sd_invalid_state_for_cmd(SDState *sd, SDRequest req)
static sd_rsp_type_t sd_invalid_mode_for_cmd(SDState *sd, SDRequest req)
{
qemu_log_mask(LOG_GUEST_ERROR, "%s: CMD%i in a wrong mode: %s (spec %s)\n",
sd->proto->name, req.cmd, sd_mode_name(sd->mode),
sd->proto->name, req.cmd, sd_mode_name(sd_mode(sd)),
sd_version_str(sd->spec_version));
return sd_illegal;
@ -1305,7 +1374,7 @@ static sd_rsp_type_t sd_cmd_to_sendingdata(SDState *sd, SDRequest req,
const void *data, size_t size)
{
if (sd->state != sd_transfer_state) {
sd_invalid_state_for_cmd(sd, req);
return sd_invalid_state_for_cmd(sd, req);
}
sd->state = sd_sendingdata_state;
@ -1341,14 +1410,6 @@ static sd_rsp_type_t sd_cmd_GO_IDLE_STATE(SDState *sd, SDRequest req)
return sd_is_spi(sd) ? sd_r1 : sd_r0;
}
/* CMD1 */
static sd_rsp_type_t spi_cmd_SEND_OP_COND(SDState *sd, SDRequest req)
{
sd->state = sd_transfer_state;
return sd_r1;
}
/* CMD2 */
static sd_rsp_type_t sd_cmd_ALL_SEND_CID(SDState *sd, SDRequest req)
{
@ -1420,11 +1481,17 @@ static sd_rsp_type_t emmc_cmd_sleep_awake(SDState *sd, SDRequest req)
/* CMD6 */
static sd_rsp_type_t sd_cmd_SWITCH_FUNCTION(SDState *sd, SDRequest req)
{
if (sd->mode != sd_data_transfer_mode) {
if (sd_mode(sd) != sd_data_transfer_mode) {
return sd_invalid_mode_for_cmd(sd, req);
}
if (sd->state != sd_transfer_state) {
return sd_invalid_state_for_cmd(sd, req);
if (sd_is_spi(sd)) {
if (sd->state == sd_idle_state) {
return sd_invalid_state_for_cmd(sd, req);
}
} else {
if (sd->state != sd_transfer_state) {
return sd_invalid_state_for_cmd(sd, req);
}
}
sd_function_switch(sd, req.arg);
@ -1517,14 +1584,30 @@ static sd_rsp_type_t emmc_cmd_SEND_EXT_CSD(SDState *sd, SDRequest req)
sd->ext_csd, sizeof(sd->ext_csd));
}
/* CMD9 */
static sd_rsp_type_t spi_cmd_SEND_CSD(SDState *sd, SDRequest req)
static sd_rsp_type_t spi_cmd_SEND_CxD(SDState *sd, SDRequest req,
const void *data, size_t size)
{
/*
* XXX as of v10.1.0-rc1 command is reached in sd_idle_state,
* so disable this check.
if (sd->state != sd_standby_state) {
return sd_invalid_state_for_cmd(sd, req);
}
return sd_cmd_to_sendingdata(sd, req, sd_req_get_address(sd, req),
sd->csd, 16);
*/
/*
* Since SPI returns CSD and CID on the DAT lines,
* switch to sd_transfer_state.
*/
sd->state = sd_transfer_state;
return sd_cmd_to_sendingdata(sd, req, 0, data, size);
}
/* CMD9 */
static sd_rsp_type_t spi_cmd_SEND_CSD(SDState *sd, SDRequest req)
{
return spi_cmd_SEND_CxD(sd, req, sd->csd, sizeof(sd->csd));
}
static sd_rsp_type_t sd_cmd_SEND_CSD(SDState *sd, SDRequest req)
@ -1539,11 +1622,7 @@ static sd_rsp_type_t sd_cmd_SEND_CSD(SDState *sd, SDRequest req)
/* CMD10 */
static sd_rsp_type_t spi_cmd_SEND_CID(SDState *sd, SDRequest req)
{
if (sd->state != sd_standby_state) {
return sd_invalid_state_for_cmd(sd, req);
}
return sd_cmd_to_sendingdata(sd, req, sd_req_get_address(sd, req),
sd->cid, 16);
return spi_cmd_SEND_CxD(sd, req, sd->cid, sizeof(sd->cid));
}
static sd_rsp_type_t sd_cmd_SEND_CID(SDState *sd, SDRequest req)
@ -1575,7 +1654,7 @@ static sd_rsp_type_t sd_cmd_STOP_TRANSMISSION(SDState *sd, SDRequest req)
/* CMD13 */
static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
{
if (sd->mode != sd_data_transfer_mode) {
if (sd_mode(sd) != sd_data_transfer_mode) {
return sd_invalid_mode_for_cmd(sd, req);
}
@ -1592,7 +1671,7 @@ static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
}
if (sd_is_spi(sd)) {
return sd_r2_s;
return spi_r2;
}
return sd_req_rca_same(sd, req) ? sd_r1 : sd_r0;
@ -1601,7 +1680,7 @@ static sd_rsp_type_t sd_cmd_SEND_STATUS(SDState *sd, SDRequest req)
/* CMD15 */
static sd_rsp_type_t sd_cmd_GO_INACTIVE_STATE(SDState *sd, SDRequest req)
{
if (sd->mode != sd_data_transfer_mode) {
if (sd_mode(sd) != sd_data_transfer_mode) {
return sd_invalid_mode_for_cmd(sd, req);
}
switch (sd->state) {
@ -1906,8 +1985,14 @@ static sd_rsp_type_t sd_acmd_SET_BUS_WIDTH(SDState *sd, SDRequest req)
/* ACMD13 */
static sd_rsp_type_t sd_acmd_SD_STATUS(SDState *sd, SDRequest req)
{
return sd_cmd_to_sendingdata(sd, req, 0,
sd->sd_status, sizeof(sd->sd_status));
sd_rsp_type_t rsp;
rsp = sd_cmd_to_sendingdata(sd, req, 0,
sd->sd_status, sizeof(sd->sd_status));
if (sd_is_spi(sd) && rsp != sd_illegal) {
return spi_r2;
}
return rsp;
}
/* ACMD22 */
@ -1967,6 +2052,9 @@ static sd_rsp_type_t sd_cmd_SEND_OP_COND(SDState *sd, SDRequest req)
sd->state = sd_ready_state;
}
if (sd_is_spi(sd)) {
return sd_r1;
}
return sd_r3;
}
@ -1998,7 +2086,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, SDRequest req)
if (req.cmd != 55 || sd->expecting_acmd) {
trace_sdcard_normal_command(sd->proto->name,
sd->last_cmd_name, req.cmd,
req.arg, sd_state_name(sd->state));
req.arg,
sd_mode_name(sd_mode(sd)),
sd_state_name(sd->state));
}
/* Not interpreting this as an app command */
@ -2084,7 +2174,9 @@ static sd_rsp_type_t sd_app_command(SDState *sd,
{
sd->last_cmd_name = sd_acmd_name(sd, req.cmd);
trace_sdcard_app_command(sd->proto->name, sd->last_cmd_name,
req.cmd, req.arg, sd_state_name(sd->state));
req.cmd, req.arg,
sd_mode_name(sd_mode(sd)),
sd_state_name(sd->state));
sd->card_status |= APP_CMD;
if (sd->proto->acmd[req.cmd].handler) {
@ -2139,8 +2231,9 @@ static bool cmd_valid_while_locked(SDState *sd, unsigned cmd)
return cmd_class == 0 || cmd_class == 7;
}
static int sd_do_command(SDState *sd, SDRequest *req,
uint8_t *response) {
static size_t sd_do_command(SDState *sd, SDRequest *req,
uint8_t *response, size_t respsz)
{
int last_state;
sd_rsp_type_t rtype;
int rsplen;
@ -2183,7 +2276,6 @@ static int sd_do_command(SDState *sd, SDRequest *req,
}
last_state = sd->state;
sd_set_mode(sd);
if (sd->expecting_acmd) {
sd->expecting_acmd = false;
@ -2203,36 +2295,37 @@ static int sd_do_command(SDState *sd, SDRequest *req,
}
send_response:
rsplen = sd_response_size(sd, rtype);
assert(rsplen <= respsz);
switch (rtype) {
case sd_r1:
case sd_r1b:
sd_response_r1_make(sd, response);
rsplen = 4;
break;
case spi_r2:
spi_response_r2_make(sd, response);
break;
case sd_r2_i:
memcpy(response, sd->cid, sizeof(sd->cid));
rsplen = 16;
break;
case sd_r2_s:
memcpy(response, sd->csd, sizeof(sd->csd));
rsplen = 16;
break;
case sd_r3:
sd_response_r3_make(sd, response);
rsplen = 4;
break;
case sd_r6:
sd_response_r6_make(sd, response);
rsplen = 4;
break;
case sd_r7:
sd_response_r7_make(sd, response);
rsplen = 4;
break;
case sd_r0:
@ -2244,7 +2337,6 @@ send_response:
sd->data_offset = 0;
/* fall-through */
case sd_illegal:
rsplen = 0;
break;
default:
g_assert_not_reached();
@ -2510,7 +2602,7 @@ static const SDProto sd_proto_spi = {
.name = "SPI",
.cmd = {
[0] = {0, sd_spi, "GO_IDLE_STATE", sd_cmd_GO_IDLE_STATE},
[1] = {0, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND},
[1] = {0, sd_spi, "SEND_OP_COND", sd_cmd_SEND_OP_COND},
[5] = {9, sd_spi, "IO_SEND_OP_COND", sd_cmd_optional},
[6] = {10, sd_spi, "SWITCH_FUNCTION", sd_cmd_SWITCH_FUNCTION},
[8] = {0, sd_spi, "SEND_IF_COND", sd_cmd_SEND_IF_COND},
@ -2546,7 +2638,7 @@ static const SDProto sd_proto_spi = {
[13] = {8, sd_spi, "SD_STATUS", sd_acmd_SD_STATUS},
[22] = {8, sd_spi, "SEND_NUM_WR_BLOCKS", sd_acmd_SEND_NUM_WR_BLOCKS},
[23] = {8, sd_spi, "SET_WR_BLK_ERASE_COUNT", sd_acmd_SET_WR_BLK_ERASE_COUNT},
[41] = {8, sd_spi, "SEND_OP_COND", spi_cmd_SEND_OP_COND},
[41] = {8, sd_spi, "SEND_OP_COND", sd_cmd_SEND_OP_COND},
[42] = {8, sd_spi, "SET_CLR_CARD_DETECT", sd_acmd_SET_CLR_CARD_DETECT},
[51] = {8, sd_spi, "SEND_SCR", sd_acmd_SEND_SCR},
},

View file

@ -337,7 +337,7 @@ static void sdhci_send_command(SDHCIState *s)
{
SDRequest request;
uint8_t response[16];
int rlen;
size_t rlen;
bool timeout = false;
s->errintsts = 0;
@ -346,7 +346,7 @@ static void sdhci_send_command(SDHCIState *s)
request.arg = s->argument;
trace_sdhci_send_command(request.cmd, request.arg);
rlen = sdbus_do_command(&s->sdbus, &request, response);
rlen = sdbus_do_command(&s->sdbus, &request, response, sizeof(response));
if (s->cmdreg & SDHC_CMD_RESPONSE) {
if (rlen == 4) {
@ -400,7 +400,7 @@ static void sdhci_end_transfer(SDHCIState *s)
request.cmd = 0x0C;
request.arg = 0;
trace_sdhci_end_transfer(request.cmd, request.arg);
sdbus_do_command(&s->sdbus, &request, response);
sdbus_do_command(&s->sdbus, &request, response, sizeof(response));
/* Auto CMD12 response goes to the upper Response register */
s->rspreg[3] = ldl_be_p(response);
}

View file

@ -70,23 +70,6 @@ struct ssi_sd_state {
#define TYPE_SSI_SD "ssi-sd"
OBJECT_DECLARE_SIMPLE_TYPE(ssi_sd_state, SSI_SD)
/* State word bits. */
#define SSI_SDR_LOCKED 0x0001
#define SSI_SDR_WP_ERASE 0x0002
#define SSI_SDR_ERROR 0x0004
#define SSI_SDR_CC_ERROR 0x0008
#define SSI_SDR_ECC_FAILED 0x0010
#define SSI_SDR_WP_VIOLATION 0x0020
#define SSI_SDR_ERASE_PARAM 0x0040
#define SSI_SDR_OUT_OF_RANGE 0x0080
#define SSI_SDR_IDLE 0x0100
#define SSI_SDR_ERASE_RESET 0x0200
#define SSI_SDR_ILLEGAL_COMMAND 0x0400
#define SSI_SDR_COM_CRC_ERROR 0x0800
#define SSI_SDR_ERASE_SEQ_ERROR 0x1000
#define SSI_SDR_ADDRESS_ERROR 0x2000
#define SSI_SDR_PARAMETER_ERROR 0x4000
/* multiple block write */
#define SSI_TOKEN_MULTI_WRITE 0xfc
/* terminate multiple block write */
@ -104,7 +87,7 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
{
ssi_sd_state *s = SSI_SD(dev);
SDRequest request;
uint8_t longresp[16];
uint8_t longresp[5];
/*
* Special case: allow CMD12 (STOP TRANSMISSION) while reading data.
@ -146,8 +129,9 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
/* manually issue cmd12 to stop the transfer */
request.cmd = 12;
request.arg = 0;
s->arglen = sdbus_do_command(&s->sdbus, &request, longresp);
if (s->arglen <= 0) {
s->arglen = sdbus_do_command(&s->sdbus, &request,
longresp, sizeof(longresp));
if (s->arglen == 0) {
s->arglen = 1;
/* a zero value indicates the card is busy */
s->response[0] = 0;
@ -170,73 +154,15 @@ static uint32_t ssi_sd_transfer(SSIPeripheral *dev, uint32_t val)
/* FIXME: Check CRC. */
request.cmd = s->cmd;
request.arg = ldl_be_p(s->cmdarg);
DPRINTF("CMD%d arg 0x%08x\n", s->cmd, request.arg);
s->arglen = sdbus_do_command(&s->sdbus, &request, longresp);
if (s->arglen <= 0) {
s->arglen = 1;
s->response[0] = 4;
DPRINTF("SD command failed\n");
} else if (s->cmd == 8 || s->cmd == 58) {
/* CMD8/CMD58 returns R3/R7 response */
DPRINTF("Returned R3/R7\n");
s->arglen = 5;
s->response[0] = 1;
memcpy(&s->response[1], longresp, 4);
} else if (s->arglen != 4) {
BADF("Unexpected response to cmd %d\n", s->cmd);
/* Illegal command is about as near as we can get. */
s->arglen = 1;
s->response[0] = 4;
} else {
/* All other commands return status. */
uint32_t cardstatus;
uint16_t status;
/* CMD13 returns a 2-byte statuse work. Other commands
only return the first byte. */
s->arglen = (s->cmd == 13) ? 2 : 1;
s->arglen = sdbus_do_command(&s->sdbus, &request,
longresp, sizeof(longresp));
DPRINTF("CMD%d arg 0x%08x = %d\n", s->cmd, request.arg, s->arglen);
assert(s->arglen > 0);
memcpy(s->response, longresp, s->arglen);
/* handle R1b */
if (s->cmd == 28 || s->cmd == 29 || s->cmd == 38) {
s->stopping = 1;
}
cardstatus = ldl_be_p(longresp);
status = 0;
if (((cardstatus >> 9) & 0xf) < 4)
status |= SSI_SDR_IDLE;
if (cardstatus & ERASE_RESET)
status |= SSI_SDR_ERASE_RESET;
if (cardstatus & ILLEGAL_COMMAND)
status |= SSI_SDR_ILLEGAL_COMMAND;
if (cardstatus & COM_CRC_ERROR)
status |= SSI_SDR_COM_CRC_ERROR;
if (cardstatus & ERASE_SEQ_ERROR)
status |= SSI_SDR_ERASE_SEQ_ERROR;
if (cardstatus & ADDRESS_ERROR)
status |= SSI_SDR_ADDRESS_ERROR;
if (cardstatus & CARD_IS_LOCKED)
status |= SSI_SDR_LOCKED;
if (cardstatus & (LOCK_UNLOCK_FAILED | WP_ERASE_SKIP))
status |= SSI_SDR_WP_ERASE;
if (cardstatus & SD_ERROR)
status |= SSI_SDR_ERROR;
if (cardstatus & CC_ERROR)
status |= SSI_SDR_CC_ERROR;
if (cardstatus & CARD_ECC_FAILED)
status |= SSI_SDR_ECC_FAILED;
if (cardstatus & WP_VIOLATION)
status |= SSI_SDR_WP_VIOLATION;
if (cardstatus & ERASE_PARAM)
status |= SSI_SDR_ERASE_PARAM;
if (cardstatus & (OUT_OF_RANGE | CID_CSD_OVERWRITE))
status |= SSI_SDR_OUT_OF_RANGE;
/* ??? Don't know what Parameter Error really means, so
assume it's set if the second byte is nonzero. */
if (status & 0xff)
status |= SSI_SDR_PARAMETER_ERROR;
s->response[0] = status >> 8;
s->response[1] = status;
DPRINTF("Card status 0x%02x\n", status);
/* handle R1b (busy signal) */
if (s->cmd == 28 || s->cmd == 29 || s->cmd == 38) {
s->stopping = 1;
}
s->mode = SSI_SD_PREP_RESP;
s->response_pos = 0;
@ -333,7 +259,7 @@ static int ssi_sd_post_load(void *opaque, int version_id)
return -EINVAL;
}
if (s->mode == SSI_SD_CMDARG &&
(s->arglen < 0 || s->arglen >= ARRAY_SIZE(s->cmdarg))) {
(s->arglen >= ARRAY_SIZE(s->cmdarg))) {
return -EINVAL;
}
if (s->mode == SSI_SD_RESPONSE &&

View file

@ -37,8 +37,8 @@ sdhci_write_dataport(uint16_t data_count) "write buffer filled with %u bytes of
sdhci_capareg(const char *desc, uint16_t val) "%s: %u"
# sd.c
sdcard_normal_command(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t arg, const char *state) "%s %20s/ CMD%02d arg 0x%08x (state %s)"
sdcard_app_command(const char *proto, const char *acmd_desc, uint8_t acmd, uint32_t arg, const char *state) "%s %23s/ACMD%02d arg 0x%08x (state %s)"
sdcard_normal_command(const char *proto, const char *cmd_desc, uint8_t cmd, uint32_t arg, const char *mode, const char *state) "%s %20s/ CMD%02d arg 0x%08x (mode %s, state %s)"
sdcard_app_command(const char *proto, const char *acmd_desc, uint8_t acmd, uint32_t arg, const char *mode, const char *state) "%s %23s/ACMD%02d arg 0x%08x (mode %s, state %s)"
sdcard_response(const char *rspdesc, int rsplen) "%s (sz:%d)"
sdcard_powerup(void) ""
sdcard_inquiry_cmd41(void) ""

View file

@ -96,7 +96,17 @@ struct SDCardClass {
DeviceClass parent_class;
/*< public >*/
int (*do_command)(SDState *sd, SDRequest *req, uint8_t *response);
/**
* Process a SD command request.
* @sd: card
* @req: command request
* @resp: buffer to receive the command response
* @respsz: size of @resp buffer
*
* Return: size of the response
*/
size_t (*do_command)(SDState *sd, SDRequest *req,
uint8_t *resp, size_t respsz);
/**
* Write a byte to a SD card.
* @sd: card
@ -153,7 +163,16 @@ struct SDBusClass {
void sdbus_set_voltage(SDBus *sdbus, uint16_t millivolts);
uint8_t sdbus_get_dat_lines(SDBus *sdbus);
bool sdbus_get_cmd_line(SDBus *sdbus);
int sdbus_do_command(SDBus *sd, SDRequest *req, uint8_t *response);
/**
* sdbus_do_command: Process a SD command request
* @sd: card
* @req: command request
* @resp: buffer to receive the command response
* @respsz: size of @resp buffer
*
* Return: size of the response
*/
size_t sdbus_do_command(SDBus *sd, SDRequest *req, uint8_t *resp, size_t respsz);
/**
* Write a byte to a SD bus.
* @sd: bus

View file

@ -7885,8 +7885,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
* count, but Intel needs maximum number of addressable IDs for
* logical processors per package.
*/
if (cpu->vendor_cpuid_only_v2 &&
(IS_INTEL_CPU(env) || IS_ZHAOXIN_CPU(env))) {
if ((IS_INTEL_CPU(env) || IS_ZHAOXIN_CPU(env))) {
num = 1 << apicid_pkg_offset(topo_info);
} else {
num = threads_per_pkg;

View file

@ -274,6 +274,7 @@ tests_riscv64_system_quick = [
]
tests_riscv64_system_thorough = [
'riscv64_sifive_u',
'riscv64_tuxrun',
]

View file

@ -0,0 +1,51 @@
#!/usr/bin/env python3
#
# Functional test that boots a Linux kernel on a Sifive U machine
# and checks the console
#
# Copyright (c) Linaro Ltd.
#
# Author:
# Philippe Mathieu-Daudé
#
# SPDX-License-Identifier: GPL-2.0-or-later
import os
from qemu_test import Asset, LinuxKernelTest
from qemu_test import skipIfMissingCommands
class SifiveU(LinuxKernelTest):
ASSET_KERNEL = Asset(
'https://storage.tuxboot.com/buildroot/20241119/riscv64/Image',
'2bd8132a3bf21570290042324fff48c987f42f2a00c08de979f43f0662ebadba')
ASSET_ROOTFS = Asset(
('https://github.com/groeck/linux-build-test/raw/'
'9819da19e6eef291686fdd7b029ea00e764dc62f/rootfs/riscv64/'
'rootfs.ext2.gz'),
'b6ed95610310b7956f9bf20c4c9c0c05fea647900df441da9dfe767d24e8b28b')
def test_riscv64_sifive_u_mmc_spi(self):
self.set_machine('sifive_u')
kernel_path = self.ASSET_KERNEL.fetch()
rootfs_path = self.uncompress(self.ASSET_ROOTFS)
self.vm.set_console()
kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
'root=/dev/mmcblk0 rootwait '
'earlycon=sbi console=ttySIF0 '
'panic=-1 noreboot')
self.vm.add_args('-kernel', kernel_path,
'-drive', f'file={rootfs_path},if=sd,format=raw',
'-append', kernel_command_line,
'-no-reboot')
self.vm.launch()
self.wait_for_console_pattern('Boot successful.')
os.remove(rootfs_path)
if __name__ == '__main__':
LinuxKernelTest.main()