wcte13xp: wcxb: Add delayed reset firmware feature

Allow certain older firmwares to delay the hard reset until a full power cycle.
This way we can "preload" newer firmware images, without requiring the user to
physically power off/on their machine.

Signed-off-by: Russ Meyerriecks <rmeyerriecks@digium.com>
Acked-by: Shaun Ruffell <sruffell@digium.com>
remotes/origin/2.9.y v2.9.0-rc1
Russ Meyerriecks 11 years ago
parent 4cd09feb54
commit 3efa9d8cd1

@ -3909,7 +3909,7 @@ static int wcaxx_check_firmware(struct wcaxx *wc)
}
return wcxb_check_firmware(&wc->xb, firmware_version,
filename, force_firmware);
filename, force_firmware, WCXB_RESET_NOW);
}
static void wcaxx_check_sethook(struct wcaxx *wc, struct wcaxx_module *mod)

@ -2431,6 +2431,26 @@ error_exit:
return serial;
}
static int te13xp_check_firmware(struct t13x *wc)
{
const char *filename;
enum wcxb_reset_option reset;
if (is_pcie(wc))
filename = TE133_FW_FILENAME;
else
filename = TE134_FW_FILENAME;
/* Specific firmware requires power cycle to properly reset */
if (0x6f0017 == wcxb_get_firmware_version(&wc->xb))
reset = WCXB_RESET_LATER;
else
reset = WCXB_RESET_NOW;
return wcxb_check_firmware(&wc->xb, TE13X_FW_VERSION, filename,
force_firmware, reset);
}
static int __devinit te13xp_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@ -2513,18 +2533,9 @@ static int __devinit te13xp_init_one(struct pci_dev *pdev,
if (res)
goto fail_exit;
/* Check for field updatable firmware */
if (is_pcie(wc)) {
res = wcxb_check_firmware(&wc->xb, TE13X_FW_VERSION,
TE133_FW_FILENAME, force_firmware);
if (res)
goto fail_exit;
} else {
res = wcxb_check_firmware(&wc->xb, TE13X_FW_VERSION,
TE134_FW_FILENAME, force_firmware);
if (res)
goto fail_exit;
}
res = te13xp_check_firmware(wc);
if (res)
goto fail_exit;
wc->ddev->hardware_id = t13x_read_serial(wc);
if (!wc->ddev->hardware_id) {

@ -3357,7 +3357,7 @@ static int __devinit t43x_init_one(struct pci_dev *pdev,
/* Check for field updatable firmware */
res = wcxb_check_firmware(&wc->xb, TE435_VERSION,
TE435_FW_FILENAME, force_firmware);
TE435_FW_FILENAME, force_firmware, WCXB_RESET_NOW);
if (res)
goto fail_exit;

@ -792,7 +792,7 @@ struct wcxb_firm_header {
__le32 version;
} __packed;
static u32 wcxb_get_firmware_version(struct wcxb *xb)
u32 wcxb_get_firmware_version(struct wcxb *xb)
{
u32 version = 0;
@ -807,7 +807,8 @@ static u32 wcxb_get_firmware_version(struct wcxb *xb)
}
static int wcxb_update_firmware(struct wcxb *xb, const struct firmware *fw,
const char *filename)
const char *filename,
enum wcxb_reset_option reset)
{
u32 tdm_control;
static const int APPLICATION_ADDRESS = 0x200000;
@ -859,14 +860,20 @@ static int wcxb_update_firmware(struct wcxb *xb, const struct firmware *fw,
APPLICATION_ADDRESS + META_BLOCK_OFFSET,
&meta, sizeof(meta));
/* Reset fpga after loading firmware */
dev_info(&xb->pdev->dev, "Firmware load complete. Reseting device.\n");
tdm_control = ioread32be(xb->membase + TDM_CONTROL);
if (WCXB_RESET_NOW == reset) {
/* Reset fpga after loading firmware */
dev_info(&xb->pdev->dev,
"Firmware load complete. Reseting device.\n");
tdm_control = ioread32be(xb->membase + TDM_CONTROL);
wcxb_hard_reset(xb);
wcxb_hard_reset(xb);
iowrite32be(0, xb->membase + 0x04);
iowrite32be(tdm_control, xb->membase + TDM_CONTROL);
iowrite32be(0, xb->membase + 0x04);
iowrite32be(tdm_control, xb->membase + TDM_CONTROL);
} else {
dev_info(&xb->pdev->dev,
"Delaying reset. Firmware load requires a power cycle\n");
}
wcxb_spi_device_destroy(flash_spi_device);
wcxb_spi_master_destroy(flash_spi_master);
@ -874,10 +881,16 @@ static int wcxb_update_firmware(struct wcxb *xb, const struct firmware *fw,
}
int wcxb_check_firmware(struct wcxb *xb, const u32 expected_version,
const char *firmware_filename, bool force_firmware)
const char *firmware_filename, bool force_firmware,
enum wcxb_reset_option reset)
{
const struct firmware *fw;
const struct wcxb_firm_header *header;
static const int APPLICATION_ADDRESS = 0x200000;
static const int META_BLOCK_OFFSET = 0x170000;
struct wcxb_spi_master *flash_spi_master;
struct wcxb_spi_device *flash_spi_device;
struct wcxb_meta_block meta;
int res = 0;
u32 crc;
u32 version = 0;
@ -896,6 +909,27 @@ int wcxb_check_firmware(struct wcxb *xb, const u32 expected_version,
return 0;
}
/* Check meta firmware version for a not-booted application image */
flash_spi_master = wcxb_spi_master_create(&xb->pdev->dev,
xb->membase + FLASH_SPI_BASE,
false);
flash_spi_device = wcxb_spi_device_create(flash_spi_master, 0);
res = wcxb_flash_read(flash_spi_device,
APPLICATION_ADDRESS + META_BLOCK_OFFSET,
&meta, sizeof(meta));
if (res) {
dev_info(&xb->pdev->dev, "Unable to read flash\n");
return -EIO;
}
if ((meta.version == cpu_to_le32(expected_version))
&& !force_firmware) {
dev_info(&xb->pdev->dev,
"Detected previous firmware updated to current version %x, but not running. You likely need to power cycle your system.\n",
expected_version);
return 0;
}
if (force_firmware) {
dev_info(&xb->pdev->dev,
"force_firmware module parameter is set. Forcing firmware load, regardless of version\n");
@ -938,12 +972,22 @@ int wcxb_check_firmware(struct wcxb *xb, const u32 expected_version,
dev_info(&xb->pdev->dev, "Found %s (version: %x) Preparing for flash\n",
firmware_filename, header->version);
res = wcxb_update_firmware(xb, fw, firmware_filename);
res = wcxb_update_firmware(xb, fw, firmware_filename, reset);
version = wcxb_get_firmware_version(xb);
dev_info(&xb->pdev->dev, "Reset into firmware version: %x\n", version);
if (WCXB_RESET_NOW == reset) {
dev_info(&xb->pdev->dev,
"Reset into firmware version: %x\n", version);
} else {
dev_info(&xb->pdev->dev,
"Running firmware version: %x\n", version);
dev_info(&xb->pdev->dev,
"Loaded firmware version: %x (Will load after next power cycle)\n",
header->version);
}
if ((expected_version != version) && !force_firmware) {
if ((WCXB_RESET_NOW == reset) && (expected_version != version)
&& !force_firmware) {
/* On the off chance that the interface is in a state where it
* cannot boot into the updated firmware image, power cycling
* the card can recover. A simple "reset" of the computer is not

@ -105,9 +105,17 @@ static inline void wcxb_disable_timing_header_driver(struct wcxb *xb)
xb->flags.drive_timing_cable = 0;
}
enum wcxb_reset_option {
WCXB_RESET_NOW,
WCXB_RESET_LATER
};
extern u32 wcxb_get_firmware_version(struct wcxb *xb);
extern int wcxb_check_firmware(struct wcxb *xb, const u32 expected_version,
const char *firmware_filename,
bool force_firmware);
bool force_firmware,
enum wcxb_reset_option reset);
extern void wcxb_stop_dma(struct wcxb *xb);
extern void wcxb_disable_interrupts(struct wcxb *xb);

Loading…
Cancel
Save