Commit 8aae2600 authored by Ron Mercer's avatar Ron Mercer Committed by David S. Miller

qlge: Add basic firmware dump.

Adding the infrstructure and basic data for the firmware
core dump.
The firmware coredump is turned OFF by default.  There will be no
memory allocations for data dumps to the log.
Signed-off-by: default avatarRon Mercer <ron.mercer@qlogic.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b87babeb
...@@ -2211,6 +2211,7 @@ extern int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit, ...@@ -2211,6 +2211,7 @@ extern int ql_write_cfg(struct ql_adapter *qdev, void *ptr, int size, u32 bit,
void ql_queue_fw_error(struct ql_adapter *qdev); void ql_queue_fw_error(struct ql_adapter *qdev);
void ql_mpi_work(struct work_struct *work); void ql_mpi_work(struct work_struct *work);
void ql_mpi_reset_work(struct work_struct *work); void ql_mpi_reset_work(struct work_struct *work);
void ql_mpi_core_to_log(struct work_struct *work);
int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 ebit); int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 ebit);
void ql_queue_asic_error(struct ql_adapter *qdev); void ql_queue_asic_error(struct ql_adapter *qdev);
u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr); u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr);
...@@ -2221,6 +2222,11 @@ void ql_mpi_port_cfg_work(struct work_struct *work); ...@@ -2221,6 +2222,11 @@ void ql_mpi_port_cfg_work(struct work_struct *work);
int ql_mb_get_fw_state(struct ql_adapter *qdev); int ql_mb_get_fw_state(struct ql_adapter *qdev);
int ql_cam_route_initialize(struct ql_adapter *qdev); int ql_cam_route_initialize(struct ql_adapter *qdev);
int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data); int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data);
int ql_write_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 data);
int ql_unpause_mpi_risc(struct ql_adapter *qdev);
int ql_pause_mpi_risc(struct ql_adapter *qdev);
int ql_core_dump(struct ql_adapter *qdev,
struct ql_mpi_coredump *mpi_coredump);
int ql_mb_about_fw(struct ql_adapter *qdev); int ql_mb_about_fw(struct ql_adapter *qdev);
int ql_wol(struct ql_adapter *qdev); int ql_wol(struct ql_adapter *qdev);
int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol); int ql_mb_wol_set_magic(struct ql_adapter *qdev, u32 enable_wol);
......
This diff is collapsed.
...@@ -73,6 +73,13 @@ static int qlge_irq_type = MSIX_IRQ; ...@@ -73,6 +73,13 @@ static int qlge_irq_type = MSIX_IRQ;
module_param(qlge_irq_type, int, MSIX_IRQ); module_param(qlge_irq_type, int, MSIX_IRQ);
MODULE_PARM_DESC(qlge_irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy."); MODULE_PARM_DESC(qlge_irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy.");
static int qlge_mpi_coredump;
module_param(qlge_mpi_coredump, int, 0);
MODULE_PARM_DESC(qlge_mpi_coredump,
"Option to enable MPI firmware dump. "
"Default is OFF - Do Not allocate memory. "
"Do not perform firmware coredump.");
static DEFINE_PCI_DEVICE_TABLE(qlge_pci_tbl) = { static DEFINE_PCI_DEVICE_TABLE(qlge_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)}, {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)},
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8000)}, {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8000)},
...@@ -3842,6 +3849,7 @@ static int ql_adapter_down(struct ql_adapter *qdev) ...@@ -3842,6 +3849,7 @@ static int ql_adapter_down(struct ql_adapter *qdev)
cancel_delayed_work_sync(&qdev->mpi_reset_work); cancel_delayed_work_sync(&qdev->mpi_reset_work);
cancel_delayed_work_sync(&qdev->mpi_work); cancel_delayed_work_sync(&qdev->mpi_work);
cancel_delayed_work_sync(&qdev->mpi_idc_work); cancel_delayed_work_sync(&qdev->mpi_idc_work);
cancel_delayed_work_sync(&qdev->mpi_core_to_log);
cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
for (i = 0; i < qdev->rss_ring_count; i++) for (i = 0; i < qdev->rss_ring_count; i++)
...@@ -4398,6 +4406,7 @@ static void ql_release_all(struct pci_dev *pdev) ...@@ -4398,6 +4406,7 @@ static void ql_release_all(struct pci_dev *pdev)
iounmap(qdev->reg_base); iounmap(qdev->reg_base);
if (qdev->doorbell_area) if (qdev->doorbell_area)
iounmap(qdev->doorbell_area); iounmap(qdev->doorbell_area);
vfree(qdev->mpi_coredump);
pci_release_regions(pdev); pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL); pci_set_drvdata(pdev, NULL);
} }
...@@ -4479,6 +4488,15 @@ static int __devinit ql_init_device(struct pci_dev *pdev, ...@@ -4479,6 +4488,15 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
spin_lock_init(&qdev->hw_lock); spin_lock_init(&qdev->hw_lock);
spin_lock_init(&qdev->stats_lock); spin_lock_init(&qdev->stats_lock);
if (qlge_mpi_coredump) {
qdev->mpi_coredump =
vmalloc(sizeof(struct ql_mpi_coredump));
if (qdev->mpi_coredump == NULL) {
dev_err(&pdev->dev, "Coredump alloc failed.\n");
err = -ENOMEM;
goto err_out;
}
}
/* make sure the EEPROM is good */ /* make sure the EEPROM is good */
err = qdev->nic_ops->get_flash(qdev); err = qdev->nic_ops->get_flash(qdev);
if (err) { if (err) {
...@@ -4508,6 +4526,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev, ...@@ -4508,6 +4526,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
INIT_DELAYED_WORK(&qdev->mpi_work, ql_mpi_work); INIT_DELAYED_WORK(&qdev->mpi_work, ql_mpi_work);
INIT_DELAYED_WORK(&qdev->mpi_port_cfg_work, ql_mpi_port_cfg_work); INIT_DELAYED_WORK(&qdev->mpi_port_cfg_work, ql_mpi_port_cfg_work);
INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work); INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work);
INIT_DELAYED_WORK(&qdev->mpi_core_to_log, ql_mpi_core_to_log);
init_completion(&qdev->ide_completion); init_completion(&qdev->ide_completion);
if (!cards_found) { if (!cards_found) {
...@@ -4630,6 +4649,7 @@ static void ql_eeh_close(struct net_device *ndev) ...@@ -4630,6 +4649,7 @@ static void ql_eeh_close(struct net_device *ndev)
cancel_delayed_work_sync(&qdev->mpi_reset_work); cancel_delayed_work_sync(&qdev->mpi_reset_work);
cancel_delayed_work_sync(&qdev->mpi_work); cancel_delayed_work_sync(&qdev->mpi_work);
cancel_delayed_work_sync(&qdev->mpi_idc_work); cancel_delayed_work_sync(&qdev->mpi_idc_work);
cancel_delayed_work_sync(&qdev->mpi_core_to_log);
cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
for (i = 0; i < qdev->rss_ring_count; i++) for (i = 0; i < qdev->rss_ring_count; i++)
......
#include "qlge.h" #include "qlge.h"
int ql_unpause_mpi_risc(struct ql_adapter *qdev)
{
u32 tmp;
/* Un-pause the RISC */
tmp = ql_read32(qdev, CSR);
if (!(tmp & CSR_RP))
return -EIO;
ql_write32(qdev, CSR, CSR_CMD_CLR_PAUSE);
return 0;
}
int ql_pause_mpi_risc(struct ql_adapter *qdev)
{
u32 tmp;
int count = UDELAY_COUNT;
/* Pause the RISC */
ql_write32(qdev, CSR, CSR_CMD_SET_PAUSE);
do {
tmp = ql_read32(qdev, CSR);
if (tmp & CSR_RP)
break;
mdelay(UDELAY_DELAY);
count--;
} while (count);
return (count == 0) ? -ETIMEDOUT : 0;
}
int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data) int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data)
{ {
int status; int status;
...@@ -45,6 +75,35 @@ int ql_soft_reset_mpi_risc(struct ql_adapter *qdev) ...@@ -45,6 +75,35 @@ int ql_soft_reset_mpi_risc(struct ql_adapter *qdev)
return status; return status;
} }
/* Determine if we are in charge of the firwmare. If
* we are the lower of the 2 NIC pcie functions, or if
* we are the higher function and the lower function
* is not enabled.
*/
int ql_own_firmware(struct ql_adapter *qdev)
{
u32 temp;
/* If we are the lower of the 2 NIC functions
* on the chip the we are responsible for
* core dump and firmware reset after an error.
*/
if (qdev->func < qdev->alt_func)
return 1;
/* If we are the higher of the 2 NIC functions
* on the chip and the lower function is not
* enabled, then we are responsible for
* core dump and firmware reset after an error.
*/
temp = ql_read32(qdev, STS);
if (!(temp & (1 << (8 + qdev->alt_func))))
return 1;
return 0;
}
static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp)
{ {
int i, status; int i, status;
...@@ -1143,5 +1202,19 @@ void ql_mpi_reset_work(struct work_struct *work) ...@@ -1143,5 +1202,19 @@ void ql_mpi_reset_work(struct work_struct *work)
cancel_delayed_work_sync(&qdev->mpi_work); cancel_delayed_work_sync(&qdev->mpi_work);
cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
cancel_delayed_work_sync(&qdev->mpi_idc_work); cancel_delayed_work_sync(&qdev->mpi_idc_work);
/* If we're not the dominant NIC function,
* then there is nothing to do.
*/
if (!ql_own_firmware(qdev)) {
QPRINTK(qdev, DRV, ERR, "Don't own firmware!\n");
return;
}
if (!ql_core_dump(qdev, qdev->mpi_coredump)) {
QPRINTK(qdev, DRV, ERR, "Core is dumped!\n");
qdev->core_is_dumped = 1;
queue_delayed_work(qdev->workqueue,
&qdev->mpi_core_to_log, 5 * HZ);
}
ql_soft_reset_mpi_risc(qdev); ql_soft_reset_mpi_risc(qdev);
} }
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