Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions components/kaos/storage/src/storage_ao.c
Original file line number Diff line number Diff line change
Expand Up @@ -4626,8 +4626,10 @@ static void sd_test_publish(Storage * const me, uint32_t kb_s)
/**
* @brief Put the slot back on the everyday width, whatever the run did.
*
* Asking costs nothing. A card that is on another width is remounted, and
* that is a call to the card.
* Asking costs nothing. A card that is not mounted the way an everyday mount
* mounts it - on one line by request, or on four without the write check - is
* remounted, and that is a call to the card. A card the driver keeps on one
* line, because it took no write on four, is where an everyday mount puts it.
*
* @param me The AO.
* @param then What to go on with when the remount returns.
Expand All @@ -4637,11 +4639,9 @@ static void sd_test_publish(Storage * const me, uint32_t kb_s)
*/
static bool sd_test_restore_width(Storage * const me, SdThen then)
{
int32_t width = 0;

(void)kdrv_sd_set(KDRV_SD_WIDTH_REQ, (int32_t)KDRV_SD_WIDTH_USE);
(void)kdrv_sd_get(KDRV_SD_BUS_WIDTH, &width);
if ( (int32_t)KDRV_SD_WIDTH_USE == width )
(void)kdrv_sd_set(KDRV_SD_CHECK_REQ, 1);
if ( kdrv_sd_mounted_everyday() )
{
return false;
}
Expand Down Expand Up @@ -5473,16 +5473,20 @@ static void sd_script_start(Storage * const me, bool verify)
me->t_capacity_mb = 0U;
me->t_seed = (uint32_t)khal_time_us();

/* Whatever an earlier run or a bench session left in the knob: the row
* judges the slot's four lines, sd_verify the card on the width it is
* used at. */
/* Whatever an earlier run or a bench session left in the knobs: the row
* judges the slot's four lines, mounted as asked with no write check -
* a card that takes no write there would otherwise be narrowed before the
* row looked, and the slot failed for the card's fault - and sd_verify the
* card on the width it is used at, checked as every everyday mount is. */
if ( verify )
{
(void)kdrv_sd_set(KDRV_SD_WIDTH_REQ, (int32_t)KDRV_SD_WIDTH_USE);
(void)kdrv_sd_set(KDRV_SD_CHECK_REQ, 1);
}
else
{
(void)kdrv_sd_set(KDRV_SD_WIDTH_REQ, (int32_t)KBSP_SD_WIDTH);
(void)kdrv_sd_set(KDRV_SD_CHECK_REQ, 0);
}

/* Mount semantics rather than the probe's: somebody just asked for this
Expand Down
1 change: 1 addition & 0 deletions components/kaos/storage/src/storage_verbs.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ static bool sd_field_row(uint16_t field, console_field_t *out)
[KDRV_SD_FREE_MB] = "How much of that filesystem is unused.",
[KDRV_SD_WIDTH_REQ] = "Data lines the NEXT mount asks for: 1 or 4, nothing between. Does not touch the card, and lasts until the board resets.",
[KDRV_SD_FREQ_REQ_KHZ] = "Clock ceiling the NEXT mount asks for. 40000 is what this board is validated at; higher is a bench experiment.",
[KDRV_SD_CHECK_REQ] = "Whether the NEXT mount on four lines proves the card takes a write before keeping it: 1, the default, or 0 for none. Does not touch the card, and lasts until the board resets.",
};
_Static_assert((sizeof(SD_FIELD_DESC) / sizeof(SD_FIELD_DESC[0]))
== (size_t)KDRV_SD_FIELD_MAX,
Expand Down
99 changes: 77 additions & 22 deletions components/kdrv/storage/include/kdrv_sd.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <stddef.h>
#include <stdint.h>

#include "kbsp.h"
#include "kode_defs.h"

#ifdef __cplusplus
Expand Down Expand Up @@ -53,7 +54,9 @@ typedef enum {
KDRV_SD_HIGH_CAPACITY, /**< OCR CCS: addressed by block, not by byte. */
KDRV_SD_BUS_WIDTH, /**< Data lines in use: 1 or 4. THE one to
* watch - a card that came up on one line
* has three that did not reach the slot. */
* either has three that did not reach the slot
* or took no write on four; the log says
* which. */
KDRV_SD_FREQ_KHZ, /**< What the host clock ended up at. */
KDRV_SD_CARD_MAX_KHZ, /**< What the card said it could take. */
KDRV_SD_RCA, /**< Relative card address. */
Expand All @@ -69,11 +72,15 @@ typedef enum {
KDRV_SD_TOTAL_MB, /**< How big the filesystem is. */
KDRV_SD_FREE_MB, /**< How much of it is unused. */

/* What the next mount will ask for. Writable; neither touches the card. */
/* What the next mount will ask for. Writable; none touches the card. */
KDRV_SD_WIDTH_REQ, /**< Data lines to ask for: 1 or 4, nothing
* between. Default KDRV_SD_WIDTH_USE. */
KDRV_SD_FREQ_REQ_KHZ, /**< Clock ceiling to ask for. Default
* KBSP_SD_FREQ_KHZ. */
KDRV_SD_CHECK_REQ, /**< Whether a mount on four lines proves the
* card takes a write before it is kept: 1 or
* 0. Default 1. 0 mounts on the lines asked
* for, with no check and no memory of cards. */

KDRV_SD_FIELD_MAX
} kdrv_sd_field_t;
Expand All @@ -87,33 +94,49 @@ typedef struct {
int32_t min; /**< Smallest value the field can hold. */
int32_t max; /**< Largest. */
uint16_t step; /**< Resolution; always 1 here. */
bool writable; /**< True for the two knobs and nothing else. */
bool writable; /**< True for the next-mount knobs and nothing else. */
} kdrv_sd_field_info_t;

/** @brief Data lines an everyday mount asks for: one. The counterfeit cards
* shipped with some units read on four lines and fail to write on
* them, and a failed write leaves the controller, which the C5's
* link shares, unable to bring a card up again until the P4 resets.
* Every card reads and writes on one. The slot's four lines
* (KBSP_SD_WIDTH) are what `test component=sd` judges. */
#define KDRV_SD_WIDTH_USE 1U
/** @brief Data lines an everyday mount asks for: the slot's four. A card that
* takes no write on them is mounted on one (see kdrv_sd_mount()), and
* `width_req` overrides this for the next mount. */
#define KDRV_SD_WIDTH_USE KBSP_SD_WIDTH

/* ---- How long a call may take --------------------------------------------
* The bounds a caller that runs these on a task of its own waits by. They are
* judgements about the card, not measurements, and each is built from the one
* under it.
*/

/** @brief The wait for the card's rail to rise behind Q1, before the first
* bring-up of a boot. */
/** @brief The wait for the card's rail to rise behind Q1, after the supply is
* switched on. */
#define KDRV_SD_POWER_SETTLE_MS 50U
/** @brief How long the card's supply stays off when the driver cycles it. */
#define KDRV_SD_POWER_OFF_MS 100U
/** @brief One cycle of the card's supply: off for its time, then on and
* settled. */
#define KDRV_SD_CYCLE_MS (KDRV_SD_POWER_OFF_MS + KDRV_SD_POWER_SETTLE_MS)
/** @brief The most one try at the card may take: the identification and the
* volume's mount behind it, each command waiting out the host's own
* timeout. */
#define KDRV_SD_TRY_MAX_MS 3000U
/** @brief A mount: the rail, four data lines and then, when the card does
* not take them, one. */
#define KDRV_SD_MOUNT_MAX_MS (KDRV_SD_POWER_SETTLE_MS + (2U * KDRV_SD_TRY_MAX_MS))
/** @brief The most the write check on four lines may take: one sector read and
* the same sector written back, each given as long as a try. */
#define KDRV_SD_CHECK_MAX_MS (2U * KDRV_SD_TRY_MAX_MS)
/** @brief How many times a card that takes no write on four lines is mounted
* on one, each after a cycle of its supply, before it is reported as a
* card that would not come up. */
#define KDRV_SD_ONE_LINE_TRIES 2U
/** @brief A mount: the rail, a try on one line for a card remembered as one
* that takes no write on four, which another card in the slot then
* repeats on four, the write check behind that, and, when the card
* takes no write on four lines, cycles of its supply, each followed
* by a try on one. A card that does not come up on four lines at all
* takes two tries, which is less. */
#define KDRV_SD_MOUNT_MAX_MS (KDRV_SD_POWER_SETTLE_MS + (2U * KDRV_SD_TRY_MAX_MS) \
+ KDRV_SD_CHECK_MAX_MS \
+ (KDRV_SD_ONE_LINE_TRIES \
* (KDRV_SD_CYCLE_MS + KDRV_SD_TRY_MAX_MS)))
/** @brief A transfer of 32 KB of sectors, which is the largest one asked. */
#define KDRV_SD_SECTORS_MAX_MS 5000U
/** @brief A format of the largest card the slot takes, with the volume's size
Expand All @@ -123,11 +146,30 @@ typedef struct {
/* ---- Mounting ------------------------------------------------------------ */

/**
* @brief Mount the card, four data lines first and then one.
* @brief Mount the card on the lines `width_req` asks for: four first and then
* one, by default.
*
* The retry is not a policy, it is what makes a counterfeit card readable: the
* cards shipped with some units advertise 4-bit in their SCR and then fail
* 4-bit writes. Reads work either way. What a 1-bit mount MEANS is the
* The fall to one line is not a policy, it is what makes a counterfeit card
* usable: the cards shipped with some units advertise 4-bit in their SCR, read
* on four lines and fail the first write there. A mount that comes up on four
* lines therefore proves the card takes a write: it reads the card's last
* sector, where no partition lives, and writes the same bytes back. When that
* read or write fails, or there is no memory to try it, the card is unmounted,
* its supply is cycled and it is mounted on one line, up to
* KDRV_SD_ONE_LINE_TRIES times with a cycle before each, and the outcome is
* told at NOTICE. A card that comes up on none of them is reported as one that
* would not come up. A mount that does not come up on four lines at all falls
* to one line without that check, and a mount asked on one line never writes.
*
* What a card took is remembered for the boot, in RAM, for the last card
* judged: it is known by what its CID says of it. A card that took the write is
* not checked again, and a card that took none is mounted on one line from the
* start, with no failed write and no cycle of its supply; if the card that
* answers there is another, it is judged as a card nobody judged. A different
* card is judged afresh, and a check that could not be made is no verdict.
* With `check_req` at 0 the card is mounted on the lines asked for, with no
* check and without consulting or changing what is remembered: the production
* test, which judges the slot, mounts that way. What a 1-bit mount MEANS is the
* caller's to judge - the production test fails on it, because on a healthy
* board all four lines reach the slot.
*
Expand Down Expand Up @@ -168,6 +210,18 @@ kode_status_t kdrv_sd_park(void);
/** @brief Whether a card is currently mounted. */
bool kdrv_sd_mounted(void);

/**
* @brief Whether the mounted card sits where an everyday mount puts it.
*
* True for a card mounted with `width_req` at KDRV_SD_WIDTH_USE and the write
* check on, whatever width that came to: four lines for a card that took a
* write there, one for a card that took none or would not come up on four.
* False with nothing mounted, and for a mount asked on other terms: one line
* by request, or four lines with the check off. A caller that wants the
* everyday width back asks for it and remounts only when this says false.
*/
bool kdrv_sd_mounted_everyday(void);

/** @brief The card's mount point string, mounted or not. */
const char *kdrv_sd_mount_point(void);

Expand All @@ -191,9 +245,10 @@ kode_status_t kdrv_sd_get(kdrv_sd_field_t f, int32_t *value);
/**
* @brief Write one field.
*
* Only the two next-mount knobs can be written, and neither reaches the card:
* they are read by the next kdrv_sd_mount(). `width_req` takes 1 or 4 and
* nothing between, because those are the only widths an SD slot has.
* Only the next-mount knobs can be written, and none reaches the card: they
* are read by the next kdrv_sd_mount(). `width_req` takes 1 or 4 and nothing
* between, because those are the only widths an SD slot has; `check_req` takes
* 1 or 0.
*
* @param[in] f Which field.
* @param[in] value Its new value, in the field's unit.
Expand Down
Loading
Loading