Commit c0eab5b3 authored by Raghu Vatsavayi's avatar Raghu Vatsavayi Committed by David S. Miller

liquidio: CN23XX firmware download

Add firmware download support for cn23xx device.
Signed-off-by: default avatarDerek Chickles <derek.chickles@caviumnetworks.com>
Signed-off-by: default avatarSatanand Burla <satananda.burla@caviumnetworks.com>
Signed-off-by: default avatarFelix Manlunas <felix.manlunas@caviumnetworks.com>
Signed-off-by: default avatarRaghu Vatsavayi <raghu.vatsavayi@caviumnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5b07aee1
...@@ -214,6 +214,37 @@ void cn23xx_dump_pf_initialized_regs(struct octeon_device *oct) ...@@ -214,6 +214,37 @@ void cn23xx_dump_pf_initialized_regs(struct octeon_device *oct)
CVM_CAST64(octeon_read_csr64(oct, CN23XX_SLI_PKT_CNT_INT))); CVM_CAST64(octeon_read_csr64(oct, CN23XX_SLI_PKT_CNT_INT)));
} }
static int cn23xx_pf_soft_reset(struct octeon_device *oct)
{
octeon_write_csr64(oct, CN23XX_WIN_WR_MASK_REG, 0xFF);
dev_dbg(&oct->pci_dev->dev, "OCTEON[%d]: BIST enabled for CN23XX soft reset\n",
oct->octeon_id);
octeon_write_csr64(oct, CN23XX_SLI_SCRATCH1, 0x1234ULL);
/* Initiate chip-wide soft reset */
lio_pci_readq(oct, CN23XX_RST_SOFT_RST);
lio_pci_writeq(oct, 1, CN23XX_RST_SOFT_RST);
/* Wait for 100ms as Octeon resets. */
mdelay(100);
if (octeon_read_csr64(oct, CN23XX_SLI_SCRATCH1) == 0x1234ULL) {
dev_err(&oct->pci_dev->dev, "OCTEON[%d]: Soft reset failed\n",
oct->octeon_id);
return 1;
}
dev_dbg(&oct->pci_dev->dev, "OCTEON[%d]: Reset completed\n",
oct->octeon_id);
/* restore the reset value*/
octeon_write_csr64(oct, CN23XX_WIN_WR_MASK_REG, 0xFF);
return 0;
}
static void cn23xx_enable_error_reporting(struct octeon_device *oct) static void cn23xx_enable_error_reporting(struct octeon_device *oct)
{ {
u32 regval; u32 regval;
...@@ -1030,6 +1061,7 @@ int setup_cn23xx_octeon_pf_device(struct octeon_device *oct) ...@@ -1030,6 +1061,7 @@ int setup_cn23xx_octeon_pf_device(struct octeon_device *oct)
oct->fn_list.process_interrupt_regs = cn23xx_interrupt_handler; oct->fn_list.process_interrupt_regs = cn23xx_interrupt_handler;
oct->fn_list.msix_interrupt_handler = cn23xx_pf_msix_interrupt_handler; oct->fn_list.msix_interrupt_handler = cn23xx_pf_msix_interrupt_handler;
oct->fn_list.soft_reset = cn23xx_pf_soft_reset;
oct->fn_list.setup_device_regs = cn23xx_setup_pf_device_regs; oct->fn_list.setup_device_regs = cn23xx_setup_pf_device_regs;
oct->fn_list.enable_interrupt = cn23xx_enable_pf_interrupt; oct->fn_list.enable_interrupt = cn23xx_enable_pf_interrupt;
...@@ -1129,3 +1161,11 @@ void cn23xx_dump_iq_regs(struct octeon_device *oct) ...@@ -1129,3 +1161,11 @@ void cn23xx_dump_iq_regs(struct octeon_device *oct)
CVM_CAST64(octeon_read_csr64( CVM_CAST64(octeon_read_csr64(
oct, CN23XX_SLI_S2M_PORTX_CTL(oct->pcie_port)))); oct, CN23XX_SLI_S2M_PORTX_CTL(oct->pcie_port))));
} }
int cn23xx_fw_loaded(struct octeon_device *oct)
{
u64 val;
val = octeon_read_csr64(oct, CN23XX_SLI_SCRATCH1);
return (val >> 1) & 1ULL;
}
...@@ -52,4 +52,6 @@ int validate_cn23xx_pf_config_info(struct octeon_device *oct, ...@@ -52,4 +52,6 @@ int validate_cn23xx_pf_config_info(struct octeon_device *oct,
struct octeon_config *conf23xx); struct octeon_config *conf23xx);
void cn23xx_dump_pf_initialized_regs(struct octeon_device *oct); void cn23xx_dump_pf_initialized_regs(struct octeon_device *oct);
int cn23xx_fw_loaded(struct octeon_device *oct);
#endif #endif
...@@ -1312,9 +1312,9 @@ static void octeon_destroy_resources(struct octeon_device *oct) ...@@ -1312,9 +1312,9 @@ static void octeon_destroy_resources(struct octeon_device *oct)
/* fallthrough */ /* fallthrough */
case OCT_DEV_PCI_MAP_DONE: case OCT_DEV_PCI_MAP_DONE:
/* Soft reset the octeon device before exiting */ /* Soft reset the octeon device before exiting */
oct->fn_list.soft_reset(oct); if ((!OCTEON_CN23XX_PF(oct)) || !oct->octeon_id)
oct->fn_list.soft_reset(oct);
octeon_unmap_pci_barx(oct, 0); octeon_unmap_pci_barx(oct, 0);
octeon_unmap_pci_barx(oct, 1); octeon_unmap_pci_barx(oct, 1);
...@@ -3823,6 +3823,7 @@ static void nic_starter(struct work_struct *work) ...@@ -3823,6 +3823,7 @@ static void nic_starter(struct work_struct *work)
static int octeon_device_init(struct octeon_device *octeon_dev) static int octeon_device_init(struct octeon_device *octeon_dev)
{ {
int j, ret; int j, ret;
int fw_loaded = 0;
char bootcmd[] = "\n"; char bootcmd[] = "\n";
struct octeon_device_priv *oct_priv = struct octeon_device_priv *oct_priv =
(struct octeon_device_priv *)octeon_dev->priv; (struct octeon_device_priv *)octeon_dev->priv;
...@@ -3844,9 +3845,23 @@ static int octeon_device_init(struct octeon_device *octeon_dev) ...@@ -3844,9 +3845,23 @@ static int octeon_device_init(struct octeon_device *octeon_dev)
octeon_dev->app_mode = CVM_DRV_INVALID_APP; octeon_dev->app_mode = CVM_DRV_INVALID_APP;
/* Do a soft reset of the Octeon device. */ if (OCTEON_CN23XX_PF(octeon_dev)) {
if (octeon_dev->fn_list.soft_reset(octeon_dev)) if (!cn23xx_fw_loaded(octeon_dev)) {
fw_loaded = 0;
/* Do a soft reset of the Octeon device. */
if (octeon_dev->fn_list.soft_reset(octeon_dev))
return 1;
/* things might have changed */
if (!cn23xx_fw_loaded(octeon_dev))
fw_loaded = 0;
else
fw_loaded = 1;
} else {
fw_loaded = 1;
}
} else if (octeon_dev->fn_list.soft_reset(octeon_dev)) {
return 1; return 1;
}
/* Initialize the dispatch mechanism used to push packets arriving on /* Initialize the dispatch mechanism used to push packets arriving on
* Octeon Output queues. * Octeon Output queues.
...@@ -3955,56 +3970,65 @@ static int octeon_device_init(struct octeon_device *octeon_dev) ...@@ -3955,56 +3970,65 @@ static int octeon_device_init(struct octeon_device *octeon_dev)
atomic_set(&octeon_dev->status, OCT_DEV_IO_QUEUES_DONE); atomic_set(&octeon_dev->status, OCT_DEV_IO_QUEUES_DONE);
dev_dbg(&octeon_dev->pci_dev->dev, "Waiting for DDR initialization...\n"); if ((!OCTEON_CN23XX_PF(octeon_dev)) || !fw_loaded) {
dev_dbg(&octeon_dev->pci_dev->dev, "Waiting for DDR initialization...\n");
if (ddr_timeout == 0) if (!ddr_timeout) {
dev_info(&octeon_dev->pci_dev->dev, "WAITING. Set ddr_timeout to non-zero value to proceed with initialization.\n"); dev_info(&octeon_dev->pci_dev->dev,
"WAITING. Set ddr_timeout to non-zero value to proceed with initialization.\n");
}
schedule_timeout_uninterruptible(HZ * LIO_RESET_SECS); schedule_timeout_uninterruptible(HZ * LIO_RESET_SECS);
/* Wait for the octeon to initialize DDR after the soft-reset. */ /* Wait for the octeon to initialize DDR after the soft-reset.*/
while (ddr_timeout == 0) { while (!ddr_timeout) {
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (schedule_timeout(HZ / 10)) { if (schedule_timeout(HZ / 10)) {
/* user probably pressed Control-C */ /* user probably pressed Control-C */
return 1;
}
}
ret = octeon_wait_for_ddr_init(octeon_dev, &ddr_timeout);
if (ret) {
dev_err(&octeon_dev->pci_dev->dev,
"DDR not initialized. Please confirm that board is configured to boot from Flash, ret: %d\n",
ret);
return 1; return 1;
} }
}
ret = octeon_wait_for_ddr_init(octeon_dev, &ddr_timeout);
if (ret) {
dev_err(&octeon_dev->pci_dev->dev,
"DDR not initialized. Please confirm that board is configured to boot from Flash, ret: %d\n",
ret);
return 1;
}
if (octeon_wait_for_bootloader(octeon_dev, 1000) != 0) { if (octeon_wait_for_bootloader(octeon_dev, 1000)) {
dev_err(&octeon_dev->pci_dev->dev, "Board not responding\n"); dev_err(&octeon_dev->pci_dev->dev, "Board not responding\n");
return 1; return 1;
} }
/* Divert uboot to take commands from host instead. */ /* Divert uboot to take commands from host instead. */
ret = octeon_console_send_cmd(octeon_dev, bootcmd, 50); ret = octeon_console_send_cmd(octeon_dev, bootcmd, 50);
dev_dbg(&octeon_dev->pci_dev->dev, "Initializing consoles\n"); dev_dbg(&octeon_dev->pci_dev->dev, "Initializing consoles\n");
ret = octeon_init_consoles(octeon_dev); ret = octeon_init_consoles(octeon_dev);
if (ret) { if (ret) {
dev_err(&octeon_dev->pci_dev->dev, "Could not access board consoles\n"); dev_err(&octeon_dev->pci_dev->dev, "Could not access board consoles\n");
return 1; return 1;
} }
ret = octeon_add_console(octeon_dev, 0); ret = octeon_add_console(octeon_dev, 0);
if (ret) { if (ret) {
dev_err(&octeon_dev->pci_dev->dev, "Could not access board console\n"); dev_err(&octeon_dev->pci_dev->dev, "Could not access board console\n");
return 1; return 1;
} }
atomic_set(&octeon_dev->status, OCT_DEV_CONSOLE_INIT_DONE); atomic_set(&octeon_dev->status, OCT_DEV_CONSOLE_INIT_DONE);
dev_dbg(&octeon_dev->pci_dev->dev, "Loading firmware\n"); dev_dbg(&octeon_dev->pci_dev->dev, "Loading firmware\n");
ret = load_firmware(octeon_dev); ret = load_firmware(octeon_dev);
if (ret) { if (ret) {
dev_err(&octeon_dev->pci_dev->dev, "Could not load firmware to board\n"); dev_err(&octeon_dev->pci_dev->dev, "Could not load firmware to board\n");
return 1; return 1;
}
/* set bit 1 of SLI_SCRATCH_1 to indicate that firmware is
* loaded
*/
if (OCTEON_CN23XX_PF(octeon_dev))
octeon_write_csr64(octeon_dev, CN23XX_SLI_SCRATCH1,
2ULL);
} }
handshake[octeon_dev->octeon_id].init_ok = 1; handshake[octeon_dev->octeon_id].init_ok = 1;
...@@ -4020,7 +4044,6 @@ static int octeon_device_init(struct octeon_device *octeon_dev) ...@@ -4020,7 +4044,6 @@ static int octeon_device_init(struct octeon_device *octeon_dev)
octeon_dev->droq[j]->pkts_credit_reg); octeon_dev->droq[j]->pkts_credit_reg);
/* Packets can start arriving on the output queues from this point. */ /* Packets can start arriving on the output queues from this point. */
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment