Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5e3d3189 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'be2net-next'



Sathya Perla says:

====================
be2net: patch set

Hi Dave, the following patch set reduces code duplication
in probe/pci-resume/eeh-resume and remove/pci-suspend/eeh-error and UE-error
detect/recovery paths. New helper routines have been introduced for this
purpose. Pls apply this set to the net-next tree. Thanks!

Patch 1 refactors the alloc/free code of adapter struct's fields into
a new set of helper routines -- be_drv_init/cleanup().

Patch 2 gets rid of the be_get_initial_config() routine as be_get_config()
is the place holder for related code.

Patch 3 introduces a new helper routine be_func_init() to execute the
initialization code used in probe/pci-resume/eeh-resume to remove
code duplication.

Patch 4 introduces a wrapper for scheduling/canceling error detection
task on similar lines to the be_worker task.

Patch 5 refactors UE error detection and recovery code on similar lines
to EEH code. Cleaning up resources is done in the error detection routine
followed by error recovery.

Patch 6 gets rid of the lancer_test_and_set_rdy_state() routine as the
same code now available in be_func_init().

Patch 7 creates a new helper routine be_resume() for all the common code
in be_probe(), be_pci_resume() and be_eeh_resume(), to reduce code duplication.

Patch 8 creates a new helper routine be_cleanup() for all the common
cleanup code duplicated in the suspend/EEH err detection paths.

Patch 9 moves be_func_init() inside be_setup() as everytime be_setup()
is called, the driver will have to wait for the function/FW to be be
initialized.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b7853d73 f962f840
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -376,6 +376,7 @@ enum vf_state {
#define BE_FLAGS_VXLAN_OFFLOADS			BIT(8)
#define BE_FLAGS_VXLAN_OFFLOADS			BIT(8)
#define BE_FLAGS_SETUP_DONE			BIT(9)
#define BE_FLAGS_SETUP_DONE			BIT(9)
#define BE_FLAGS_EVT_INCOMPATIBLE_SFP		BIT(10)
#define BE_FLAGS_EVT_INCOMPATIBLE_SFP		BIT(10)
#define BE_FLAGS_ERR_DETECTION_SCHEDULED	BIT(11)


#define BE_UC_PMAC_COUNT			30
#define BE_UC_PMAC_COUNT			30
#define BE_VF_UC_PMAC_COUNT			2
#define BE_VF_UC_PMAC_COUNT			2
@@ -501,7 +502,7 @@ struct be_adapter {
	struct delayed_work work;
	struct delayed_work work;
	u16 work_counter;
	u16 work_counter;


	struct delayed_work func_recovery_work;
	struct delayed_work be_err_detection_work;
	u32 flags;
	u32 flags;
	u32 cmd_privileges;
	u32 cmd_privileges;
	/* Ethtool knobs and info */
	/* Ethtool knobs and info */
+14 −71
Original line number Original line Diff line number Diff line
@@ -635,73 +635,16 @@ static int lancer_wait_ready(struct be_adapter *adapter)
	for (i = 0; i < SLIPORT_READY_TIMEOUT; i++) {
	for (i = 0; i < SLIPORT_READY_TIMEOUT; i++) {
		sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET);
		sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET);
		if (sliport_status & SLIPORT_STATUS_RDY_MASK)
		if (sliport_status & SLIPORT_STATUS_RDY_MASK)
			break;

		msleep(1000);
	}

	if (i == SLIPORT_READY_TIMEOUT)
		return sliport_status ? : -1;

			return 0;
			return 0;
}

static bool lancer_provisioning_error(struct be_adapter *adapter)
{
	u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0;

	sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET);
	if (sliport_status & SLIPORT_STATUS_ERR_MASK) {
		sliport_err1 = ioread32(adapter->db + SLIPORT_ERROR1_OFFSET);
		sliport_err2 = ioread32(adapter->db + SLIPORT_ERROR2_OFFSET);


		if (sliport_err1 == SLIPORT_ERROR_NO_RESOURCE1 &&
		if (sliport_status & SLIPORT_STATUS_ERR_MASK &&
		    sliport_err2 == SLIPORT_ERROR_NO_RESOURCE2)
		    !(sliport_status & SLIPORT_STATUS_RN_MASK))
			return true;
			return -EIO;
	}
	return false;
}

int lancer_test_and_set_rdy_state(struct be_adapter *adapter)
{
	int status;
	u32 sliport_status, err, reset_needed;
	bool resource_error;

	resource_error = lancer_provisioning_error(adapter);
	if (resource_error)
		return -EAGAIN;

	status = lancer_wait_ready(adapter);
	if (!status) {
		sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET);
		err = sliport_status & SLIPORT_STATUS_ERR_MASK;
		reset_needed = sliport_status & SLIPORT_STATUS_RN_MASK;
		if (err && reset_needed) {
			iowrite32(SLI_PORT_CONTROL_IP_MASK,
				  adapter->db + SLIPORT_CONTROL_OFFSET);


			/* check if adapter has corrected the error */
		msleep(1000);
			status = lancer_wait_ready(adapter);
			sliport_status = ioread32(adapter->db +
						  SLIPORT_STATUS_OFFSET);
			sliport_status &= (SLIPORT_STATUS_ERR_MASK |
						SLIPORT_STATUS_RN_MASK);
			if (status || sliport_status)
				status = -1;
		} else if (err || reset_needed) {
			status = -1;
		}
	}
	}
	/* Stop error recovery if error is not recoverable.
	 * No resource error is temporary errors and will go away
	 * when PF provisions resources.
	 */
	resource_error = lancer_provisioning_error(adapter);
	if (resource_error)
		status = -EAGAIN;


	return status;
	return sliport_status ? : -1;
}
}


int be_fw_wait_ready(struct be_adapter *adapter)
int be_fw_wait_ready(struct be_adapter *adapter)
@@ -720,6 +663,10 @@ int be_fw_wait_ready(struct be_adapter *adapter)
	}
	}


	do {
	do {
		/* There's no means to poll POST state on BE2/3 VFs */
		if (BEx_chip(adapter) && be_virtfn(adapter))
			return 0;

		stage = be_POST_stage_get(adapter);
		stage = be_POST_stage_get(adapter);
		if (stage == POST_STAGE_ARMFW_RDY)
		if (stage == POST_STAGE_ARMFW_RDY)
			return 0;
			return 0;
@@ -734,7 +681,7 @@ int be_fw_wait_ready(struct be_adapter *adapter)


err:
err:
	dev_err(dev, "POST timeout; stage=%#x\n", stage);
	dev_err(dev, "POST timeout; stage=%#x\n", stage);
	return -1;
	return -ETIMEDOUT;
}
}


static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb)
static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb)
@@ -2126,16 +2073,12 @@ int be_cmd_reset_function(struct be_adapter *adapter)
	int status;
	int status;


	if (lancer_chip(adapter)) {
	if (lancer_chip(adapter)) {
		status = lancer_wait_ready(adapter);
		if (!status) {
		iowrite32(SLI_PORT_CONTROL_IP_MASK,
		iowrite32(SLI_PORT_CONTROL_IP_MASK,
			  adapter->db + SLIPORT_CONTROL_OFFSET);
			  adapter->db + SLIPORT_CONTROL_OFFSET);
			status = lancer_test_and_set_rdy_state(adapter);
		status = lancer_wait_ready(adapter);
		}
		if (status)
		if (status) {
			dev_err(&adapter->pdev->dev,
			dev_err(&adapter->pdev->dev,
				"Adapter in non recoverable error\n");
				"Adapter in non recoverable error\n");
		}
		return status;
		return status;
	}
	}


+287 −338
Original line number Original line Diff line number Diff line
@@ -2844,12 +2844,12 @@ void be_detect_error(struct be_adapter *adapter)
			sliport_err2 = ioread32(adapter->db +
			sliport_err2 = ioread32(adapter->db +
						SLIPORT_ERROR2_OFFSET);
						SLIPORT_ERROR2_OFFSET);
			adapter->hw_error = true;
			adapter->hw_error = true;
			error_detected = true;
			/* Do not log error messages if its a FW reset */
			/* Do not log error messages if its a FW reset */
			if (sliport_err1 == SLIPORT_ERROR_FW_RESET1 &&
			if (sliport_err1 == SLIPORT_ERROR_FW_RESET1 &&
			    sliport_err2 == SLIPORT_ERROR_FW_RESET2) {
			    sliport_err2 == SLIPORT_ERROR_FW_RESET2) {
				dev_info(dev, "Firmware update in progress\n");
				dev_info(dev, "Firmware update in progress\n");
			} else {
			} else {
				error_detected = true;
				dev_err(dev, "Error detected in the card\n");
				dev_err(dev, "Error detected in the card\n");
				dev_err(dev, "ERR: sliport status 0x%x\n",
				dev_err(dev, "ERR: sliport status 0x%x\n",
					sliport_status);
					sliport_status);
@@ -3363,6 +3363,14 @@ static void be_cancel_worker(struct be_adapter *adapter)
	}
	}
}
}


static void be_cancel_err_detection(struct be_adapter *adapter)
{
	if (adapter->flags & BE_FLAGS_ERR_DETECTION_SCHEDULED) {
		cancel_delayed_work_sync(&adapter->be_err_detection_work);
		adapter->flags &= ~BE_FLAGS_ERR_DETECTION_SCHEDULED;
	}
}

static void be_mac_clear(struct be_adapter *adapter)
static void be_mac_clear(struct be_adapter *adapter)
{
{
	if (adapter->pmac_id) {
	if (adapter->pmac_id) {
@@ -3771,13 +3779,25 @@ static void be_sriov_config(struct be_adapter *adapter)


static int be_get_config(struct be_adapter *adapter)
static int be_get_config(struct be_adapter *adapter)
{
{
	int status, level;
	u16 profile_id;
	u16 profile_id;
	int status;

	status = be_cmd_get_cntl_attributes(adapter);
	if (status)
		return status;


	status = be_cmd_query_fw_cfg(adapter);
	status = be_cmd_query_fw_cfg(adapter);
	if (status)
	if (status)
		return status;
		return status;


	if (BEx_chip(adapter)) {
		level = be_cmd_get_fw_log_level(adapter);
		adapter->msg_enable =
			level <= FW_LOG_LEVEL_DEFAULT ? NETIF_MSG_HW : 0;
	}

	be_cmd_get_acpi_wol_cap(adapter);

	be_cmd_query_port_name(adapter);
	be_cmd_query_port_name(adapter);


	if (be_physfn(adapter)) {
	if (be_physfn(adapter)) {
@@ -3835,6 +3855,13 @@ static void be_schedule_worker(struct be_adapter *adapter)
	adapter->flags |= BE_FLAGS_WORKER_SCHEDULED;
	adapter->flags |= BE_FLAGS_WORKER_SCHEDULED;
}
}


static void be_schedule_err_detection(struct be_adapter *adapter)
{
	schedule_delayed_work(&adapter->be_err_detection_work,
			      msecs_to_jiffies(1000));
	adapter->flags |= BE_FLAGS_ERR_DETECTION_SCHEDULED;
}

static int be_setup_queues(struct be_adapter *adapter)
static int be_setup_queues(struct be_adapter *adapter)
{
{
	struct net_device *netdev = adapter->netdev;
	struct net_device *netdev = adapter->netdev;
@@ -3917,11 +3944,53 @@ static inline int fw_major_num(const char *fw_ver)
	return fw_major;
	return fw_major;
}
}


/* If any VFs are already enabled don't FLR the PF */
static bool be_reset_required(struct be_adapter *adapter)
{
	return pci_num_vf(adapter->pdev) ? false : true;
}

/* Wait for the FW to be ready and perform the required initialization */
static int be_func_init(struct be_adapter *adapter)
{
	int status;

	status = be_fw_wait_ready(adapter);
	if (status)
		return status;

	if (be_reset_required(adapter)) {
		status = be_cmd_reset_function(adapter);
		if (status)
			return status;

		/* Wait for interrupts to quiesce after an FLR */
		msleep(100);

		/* We can clear all errors when function reset succeeds */
		be_clear_all_error(adapter);
	}

	/* Tell FW we're ready to fire cmds */
	status = be_cmd_fw_init(adapter);
	if (status)
		return status;

	/* Allow interrupts for other ULPs running on NIC function */
	be_intr_set(adapter, true);

	return 0;
}

static int be_setup(struct be_adapter *adapter)
static int be_setup(struct be_adapter *adapter)
{
{
	struct device *dev = &adapter->pdev->dev;
	struct device *dev = &adapter->pdev->dev;
	int status;
	int status;


	status = be_func_init(adapter);
	if (status)
		return status;

	be_setup_init(adapter);
	be_setup_init(adapter);


	if (!lancer_chip(adapter))
	if (!lancer_chip(adapter))
@@ -3967,8 +4036,6 @@ static int be_setup(struct be_adapter *adapter)


	be_set_rx_mode(adapter->netdev);
	be_set_rx_mode(adapter->netdev);


	be_cmd_get_acpi_wol_cap(adapter);

	status = be_cmd_set_flow_control(adapter, adapter->tx_fc,
	status = be_cmd_set_flow_control(adapter, adapter->tx_fc,
					 adapter->rx_fc);
					 adapter->rx_fc);
	if (status)
	if (status)
@@ -4878,6 +4945,142 @@ static void be_netdev_init(struct net_device *netdev)
	netdev->ethtool_ops = &be_ethtool_ops;
	netdev->ethtool_ops = &be_ethtool_ops;
}
}


static void be_cleanup(struct be_adapter *adapter)
{
	struct net_device *netdev = adapter->netdev;

	rtnl_lock();
	netif_device_detach(netdev);
	if (netif_running(netdev))
		be_close(netdev);
	rtnl_unlock();

	be_clear(adapter);
}

static int be_resume(struct be_adapter *adapter)
{
	struct net_device *netdev = adapter->netdev;
	int status;

	status = be_setup(adapter);
	if (status)
		return status;

	if (netif_running(netdev)) {
		status = be_open(netdev);
		if (status)
			return status;
	}

	netif_device_attach(netdev);

	return 0;
}

static int be_err_recover(struct be_adapter *adapter)
{
	struct device *dev = &adapter->pdev->dev;
	int status;

	status = be_resume(adapter);
	if (status)
		goto err;

	dev_info(dev, "Adapter recovery successful\n");
	return 0;
err:
	if (be_physfn(adapter))
		dev_err(dev, "Adapter recovery failed\n");
	else
		dev_err(dev, "Re-trying adapter recovery\n");

	return status;
}

static void be_err_detection_task(struct work_struct *work)
{
	struct be_adapter *adapter =
				container_of(work, struct be_adapter,
					     be_err_detection_work.work);
	int status = 0;

	be_detect_error(adapter);

	if (adapter->hw_error) {
		be_cleanup(adapter);

		/* As of now error recovery support is in Lancer only */
		if (lancer_chip(adapter))
			status = be_err_recover(adapter);
	}

	/* Always attempt recovery on VFs */
	if (!status || be_virtfn(adapter))
		be_schedule_err_detection(adapter);
}

static void be_log_sfp_info(struct be_adapter *adapter)
{
	int status;

	status = be_cmd_query_sfp_info(adapter);
	if (!status) {
		dev_err(&adapter->pdev->dev,
			"Unqualified SFP+ detected on %c from %s part no: %s",
			adapter->port_name, adapter->phy.vendor_name,
			adapter->phy.vendor_pn);
	}
	adapter->flags &= ~BE_FLAGS_EVT_INCOMPATIBLE_SFP;
}

static void be_worker(struct work_struct *work)
{
	struct be_adapter *adapter =
		container_of(work, struct be_adapter, work.work);
	struct be_rx_obj *rxo;
	int i;

	/* when interrupts are not yet enabled, just reap any pending
	 * mcc completions
	 */
	if (!netif_running(adapter->netdev)) {
		local_bh_disable();
		be_process_mcc(adapter);
		local_bh_enable();
		goto reschedule;
	}

	if (!adapter->stats_cmd_sent) {
		if (lancer_chip(adapter))
			lancer_cmd_get_pport_stats(adapter,
						   &adapter->stats_cmd);
		else
			be_cmd_get_stats(adapter, &adapter->stats_cmd);
	}

	if (be_physfn(adapter) &&
	    MODULO(adapter->work_counter, adapter->be_get_temp_freq) == 0)
		be_cmd_get_die_temperature(adapter);

	for_all_rx_queues(adapter, rxo, i) {
		/* Replenish RX-queues starved due to memory
		 * allocation failures.
		 */
		if (rxo->rx_post_starved)
			be_post_rx_frags(rxo, GFP_KERNEL, MAX_RX_POST);
	}

	be_eqd_update(adapter);

	if (adapter->flags & BE_FLAGS_EVT_INCOMPATIBLE_SFP)
		be_log_sfp_info(adapter);

reschedule:
	adapter->work_counter++;
	schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
}

static void be_unmap_pci_bars(struct be_adapter *adapter)
static void be_unmap_pci_bars(struct be_adapter *adapter)
{
{
	if (adapter->csr)
	if (adapter->csr)
@@ -4909,6 +5112,12 @@ static int be_roce_map_pci_bars(struct be_adapter *adapter)
static int be_map_pci_bars(struct be_adapter *adapter)
static int be_map_pci_bars(struct be_adapter *adapter)
{
{
	u8 __iomem *addr;
	u8 __iomem *addr;
	u32 sli_intf;

	pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf);
	adapter->sli_family = (sli_intf & SLI_INTF_FAMILY_MASK) >>
				SLI_INTF_FAMILY_SHIFT;
	adapter->virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0;


	if (BEx_chip(adapter) && be_physfn(adapter)) {
	if (BEx_chip(adapter) && be_physfn(adapter)) {
		adapter->csr = pci_iomap(adapter->pdev, 2, 0);
		adapter->csr = pci_iomap(adapter->pdev, 2, 0);
@@ -4930,109 +5139,94 @@ static int be_map_pci_bars(struct be_adapter *adapter)
	return -ENOMEM;
	return -ENOMEM;
}
}


static void be_ctrl_cleanup(struct be_adapter *adapter)
static void be_drv_cleanup(struct be_adapter *adapter)
{
{
	struct be_dma_mem *mem = &adapter->mbox_mem_alloced;
	struct be_dma_mem *mem = &adapter->mbox_mem_alloced;

	struct device *dev = &adapter->pdev->dev;
	be_unmap_pci_bars(adapter);


	if (mem->va)
	if (mem->va)
		dma_free_coherent(&adapter->pdev->dev, mem->size, mem->va,
		dma_free_coherent(dev, mem->size, mem->va, mem->dma);
				  mem->dma);


	mem = &adapter->rx_filter;
	mem = &adapter->rx_filter;
	if (mem->va)
	if (mem->va)
		dma_free_coherent(&adapter->pdev->dev, mem->size, mem->va,
		dma_free_coherent(dev, mem->size, mem->va, mem->dma);
				  mem->dma);

	mem = &adapter->stats_cmd;
	if (mem->va)
		dma_free_coherent(dev, mem->size, mem->va, mem->dma);
}
}


static int be_ctrl_init(struct be_adapter *adapter)
/* Allocate and initialize various fields in be_adapter struct */
static int be_drv_init(struct be_adapter *adapter)
{
{
	struct be_dma_mem *mbox_mem_alloc = &adapter->mbox_mem_alloced;
	struct be_dma_mem *mbox_mem_alloc = &adapter->mbox_mem_alloced;
	struct be_dma_mem *mbox_mem_align = &adapter->mbox_mem;
	struct be_dma_mem *mbox_mem_align = &adapter->mbox_mem;
	struct be_dma_mem *rx_filter = &adapter->rx_filter;
	struct be_dma_mem *rx_filter = &adapter->rx_filter;
	u32 sli_intf;
	struct be_dma_mem *stats_cmd = &adapter->stats_cmd;
	int status;
	struct device *dev = &adapter->pdev->dev;

	int status = 0;
	pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf);
	adapter->sli_family = (sli_intf & SLI_INTF_FAMILY_MASK) >>
				 SLI_INTF_FAMILY_SHIFT;
	adapter->virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0;

	status = be_map_pci_bars(adapter);
	if (status)
		goto done;


	mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16;
	mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16;
	mbox_mem_alloc->va = dma_alloc_coherent(&adapter->pdev->dev,
	mbox_mem_alloc->va = dma_alloc_coherent(dev, mbox_mem_alloc->size,
						mbox_mem_alloc->size,
						&mbox_mem_alloc->dma,
						&mbox_mem_alloc->dma,
						GFP_KERNEL);
						GFP_KERNEL);
	if (!mbox_mem_alloc->va) {
	if (!mbox_mem_alloc->va)
		status = -ENOMEM;
		return -ENOMEM;
		goto unmap_pci_bars;

	}
	mbox_mem_align->size = sizeof(struct be_mcc_mailbox);
	mbox_mem_align->size = sizeof(struct be_mcc_mailbox);
	mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16);
	mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16);
	mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16);
	mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16);
	memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox));
	memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox));


	rx_filter->size = sizeof(struct be_cmd_req_rx_filter);
	rx_filter->size = sizeof(struct be_cmd_req_rx_filter);
	rx_filter->va = dma_zalloc_coherent(&adapter->pdev->dev,
	rx_filter->va = dma_zalloc_coherent(dev, rx_filter->size,
					    rx_filter->size, &rx_filter->dma,
					    &rx_filter->dma, GFP_KERNEL);
					    GFP_KERNEL);
	if (!rx_filter->va) {
	if (!rx_filter->va) {
		status = -ENOMEM;
		status = -ENOMEM;
		goto free_mbox;
		goto free_mbox;
	}
	}


	if (lancer_chip(adapter))
		stats_cmd->size = sizeof(struct lancer_cmd_req_pport_stats);
	else if (BE2_chip(adapter))
		stats_cmd->size = sizeof(struct be_cmd_req_get_stats_v0);
	else if (BE3_chip(adapter))
		stats_cmd->size = sizeof(struct be_cmd_req_get_stats_v1);
	else
		stats_cmd->size = sizeof(struct be_cmd_req_get_stats_v2);
	stats_cmd->va = dma_zalloc_coherent(dev, stats_cmd->size,
					    &stats_cmd->dma, GFP_KERNEL);
	if (!stats_cmd->va) {
		status = -ENOMEM;
		goto free_rx_filter;
	}

	mutex_init(&adapter->mbox_lock);
	mutex_init(&adapter->mbox_lock);
	spin_lock_init(&adapter->mcc_lock);
	spin_lock_init(&adapter->mcc_lock);
	spin_lock_init(&adapter->mcc_cq_lock);
	spin_lock_init(&adapter->mcc_cq_lock);

	init_completion(&adapter->et_cmd_compl);
	init_completion(&adapter->et_cmd_compl);
	pci_save_state(adapter->pdev);
	return 0;

free_mbox:
	dma_free_coherent(&adapter->pdev->dev, mbox_mem_alloc->size,
			  mbox_mem_alloc->va, mbox_mem_alloc->dma);

unmap_pci_bars:
	be_unmap_pci_bars(adapter);


done:
	pci_save_state(adapter->pdev);
	return status;
}

static void be_stats_cleanup(struct be_adapter *adapter)
{
	struct be_dma_mem *cmd = &adapter->stats_cmd;


	if (cmd->va)
	INIT_DELAYED_WORK(&adapter->work, be_worker);
		dma_free_coherent(&adapter->pdev->dev, cmd->size,
	INIT_DELAYED_WORK(&adapter->be_err_detection_work,
				  cmd->va, cmd->dma);
			  be_err_detection_task);
}


static int be_stats_init(struct be_adapter *adapter)
	adapter->rx_fc = true;
{
	adapter->tx_fc = true;
	struct be_dma_mem *cmd = &adapter->stats_cmd;


	if (lancer_chip(adapter))
	/* Must be a power of 2 or else MODULO will BUG_ON */
		cmd->size = sizeof(struct lancer_cmd_req_pport_stats);
	adapter->be_get_temp_freq = 64;
	else if (BE2_chip(adapter))
	adapter->cfg_num_qs = netif_get_num_default_rss_queues();
		cmd->size = sizeof(struct be_cmd_req_get_stats_v0);
	else if (BE3_chip(adapter))
		cmd->size = sizeof(struct be_cmd_req_get_stats_v1);
	else
		/* ALL non-BE ASICs */
		cmd->size = sizeof(struct be_cmd_req_get_stats_v2);


	cmd->va = dma_zalloc_coherent(&adapter->pdev->dev, cmd->size, &cmd->dma,
				      GFP_KERNEL);
	if (!cmd->va)
		return -ENOMEM;
	return 0;
	return 0;

free_rx_filter:
	dma_free_coherent(dev, rx_filter->size, rx_filter->va, rx_filter->dma);
free_mbox:
	dma_free_coherent(dev, mbox_mem_alloc->size, mbox_mem_alloc->va,
			  mbox_mem_alloc->dma);
	return status;
}
}


static void be_remove(struct pci_dev *pdev)
static void be_remove(struct pci_dev *pdev)
@@ -5045,7 +5239,7 @@ static void be_remove(struct pci_dev *pdev)
	be_roce_dev_remove(adapter);
	be_roce_dev_remove(adapter);
	be_intr_set(adapter, false);
	be_intr_set(adapter, false);


	cancel_delayed_work_sync(&adapter->func_recovery_work);
	be_cancel_err_detection(adapter);


	unregister_netdev(adapter->netdev);
	unregister_netdev(adapter->netdev);


@@ -5054,9 +5248,8 @@ static void be_remove(struct pci_dev *pdev)
	/* tell fw we're done with firing cmds */
	/* tell fw we're done with firing cmds */
	be_cmd_fw_clean(adapter);
	be_cmd_fw_clean(adapter);


	be_stats_cleanup(adapter);
	be_unmap_pci_bars(adapter);

	be_drv_cleanup(adapter);
	be_ctrl_cleanup(adapter);


	pci_disable_pcie_error_reporting(pdev);
	pci_disable_pcie_error_reporting(pdev);


@@ -5066,156 +5259,6 @@ static void be_remove(struct pci_dev *pdev)
	free_netdev(adapter->netdev);
	free_netdev(adapter->netdev);
}
}


static int be_get_initial_config(struct be_adapter *adapter)
{
	int status, level;

	status = be_cmd_get_cntl_attributes(adapter);
	if (status)
		return status;

	/* Must be a power of 2 or else MODULO will BUG_ON */
	adapter->be_get_temp_freq = 64;

	if (BEx_chip(adapter)) {
		level = be_cmd_get_fw_log_level(adapter);
		adapter->msg_enable =
			level <= FW_LOG_LEVEL_DEFAULT ? NETIF_MSG_HW : 0;
	}

	adapter->cfg_num_qs = netif_get_num_default_rss_queues();
	return 0;
}

static int lancer_recover_func(struct be_adapter *adapter)
{
	struct device *dev = &adapter->pdev->dev;
	int status;

	status = lancer_test_and_set_rdy_state(adapter);
	if (status)
		goto err;

	if (netif_running(adapter->netdev))
		be_close(adapter->netdev);

	be_clear(adapter);

	be_clear_all_error(adapter);

	status = be_setup(adapter);
	if (status)
		goto err;

	if (netif_running(adapter->netdev)) {
		status = be_open(adapter->netdev);
		if (status)
			goto err;
	}

	dev_err(dev, "Adapter recovery successful\n");
	return 0;
err:
	if (status == -EAGAIN)
		dev_err(dev, "Waiting for resource provisioning\n");
	else
		dev_err(dev, "Adapter recovery failed\n");

	return status;
}

static void be_func_recovery_task(struct work_struct *work)
{
	struct be_adapter *adapter =
		container_of(work, struct be_adapter,  func_recovery_work.work);
	int status = 0;

	be_detect_error(adapter);

	if (adapter->hw_error && lancer_chip(adapter)) {
		rtnl_lock();
		netif_device_detach(adapter->netdev);
		rtnl_unlock();

		status = lancer_recover_func(adapter);
		if (!status)
			netif_device_attach(adapter->netdev);
	}

	/* In Lancer, for all errors other than provisioning error (-EAGAIN),
	 * no need to attempt further recovery.
	 */
	if (!status || status == -EAGAIN)
		schedule_delayed_work(&adapter->func_recovery_work,
				      msecs_to_jiffies(1000));
}

static void be_log_sfp_info(struct be_adapter *adapter)
{
	int status;

	status = be_cmd_query_sfp_info(adapter);
	if (!status) {
		dev_err(&adapter->pdev->dev,
			"Unqualified SFP+ detected on %c from %s part no: %s",
			adapter->port_name, adapter->phy.vendor_name,
			adapter->phy.vendor_pn);
	}
	adapter->flags &= ~BE_FLAGS_EVT_INCOMPATIBLE_SFP;
}

static void be_worker(struct work_struct *work)
{
	struct be_adapter *adapter =
		container_of(work, struct be_adapter, work.work);
	struct be_rx_obj *rxo;
	int i;

	/* when interrupts are not yet enabled, just reap any pending
	* mcc completions */
	if (!netif_running(adapter->netdev)) {
		local_bh_disable();
		be_process_mcc(adapter);
		local_bh_enable();
		goto reschedule;
	}

	if (!adapter->stats_cmd_sent) {
		if (lancer_chip(adapter))
			lancer_cmd_get_pport_stats(adapter,
						   &adapter->stats_cmd);
		else
			be_cmd_get_stats(adapter, &adapter->stats_cmd);
	}

	if (be_physfn(adapter) &&
	    MODULO(adapter->work_counter, adapter->be_get_temp_freq) == 0)
		be_cmd_get_die_temperature(adapter);

	for_all_rx_queues(adapter, rxo, i) {
		/* Replenish RX-queues starved due to memory
		 * allocation failures.
		 */
		if (rxo->rx_post_starved)
			be_post_rx_frags(rxo, GFP_KERNEL, MAX_RX_POST);
	}

	be_eqd_update(adapter);

	if (adapter->flags & BE_FLAGS_EVT_INCOMPATIBLE_SFP)
		be_log_sfp_info(adapter);

reschedule:
	adapter->work_counter++;
	schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
}

/* If any VFs are already enabled don't FLR the PF */
static bool be_reset_required(struct be_adapter *adapter)
{
	return pci_num_vf(adapter->pdev) ? false : true;
}

static char *mc_name(struct be_adapter *adapter)
static char *mc_name(struct be_adapter *adapter)
{
{
	char *str = "";	/* default */
	char *str = "";	/* default */
@@ -5314,50 +5357,17 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
	if (!status)
	if (!status)
		dev_info(&pdev->dev, "PCIe error reporting enabled\n");
		dev_info(&pdev->dev, "PCIe error reporting enabled\n");


	status = be_ctrl_init(adapter);
	status = be_map_pci_bars(adapter);
	if (status)
	if (status)
		goto free_netdev;
		goto free_netdev;


	/* sync up with fw's ready state */
	status = be_drv_init(adapter);
	if (be_physfn(adapter)) {
		status = be_fw_wait_ready(adapter);
	if (status)
	if (status)
			goto ctrl_clean;
		goto unmap_bars;
	}

	if (be_reset_required(adapter)) {
		status = be_cmd_reset_function(adapter);
		if (status)
			goto ctrl_clean;

		/* Wait for interrupts to quiesce after an FLR */
		msleep(100);
	}

	/* Allow interrupts for other ULPs running on NIC function */
	be_intr_set(adapter, true);

	/* tell fw we're ready to fire cmds */
	status = be_cmd_fw_init(adapter);
	if (status)
		goto ctrl_clean;

	status = be_stats_init(adapter);
	if (status)
		goto ctrl_clean;

	status = be_get_initial_config(adapter);
	if (status)
		goto stats_clean;

	INIT_DELAYED_WORK(&adapter->work, be_worker);
	INIT_DELAYED_WORK(&adapter->func_recovery_work, be_func_recovery_task);
	adapter->rx_fc = true;
	adapter->tx_fc = true;


	status = be_setup(adapter);
	status = be_setup(adapter);
	if (status)
	if (status)
		goto stats_clean;
		goto drv_cleanup;


	be_netdev_init(netdev);
	be_netdev_init(netdev);
	status = register_netdev(netdev);
	status = register_netdev(netdev);
@@ -5366,8 +5376,7 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)


	be_roce_dev_add(adapter);
	be_roce_dev_add(adapter);


	schedule_delayed_work(&adapter->func_recovery_work,
	be_schedule_err_detection(adapter);
			      msecs_to_jiffies(1000));


	dev_info(&pdev->dev, "%s: %s %s port %c\n", nic_name(pdev),
	dev_info(&pdev->dev, "%s: %s %s port %c\n", nic_name(pdev),
		 func_name(adapter), mc_name(adapter), adapter->port_name);
		 func_name(adapter), mc_name(adapter), adapter->port_name);
@@ -5376,10 +5385,10 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)


unsetup:
unsetup:
	be_clear(adapter);
	be_clear(adapter);
stats_clean:
drv_cleanup:
	be_stats_cleanup(adapter);
	be_drv_cleanup(adapter);
ctrl_clean:
unmap_bars:
	be_ctrl_cleanup(adapter);
	be_unmap_pci_bars(adapter);
free_netdev:
free_netdev:
	free_netdev(netdev);
	free_netdev(netdev);
rel_reg:
rel_reg:
@@ -5394,21 +5403,14 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
static int be_suspend(struct pci_dev *pdev, pm_message_t state)
static int be_suspend(struct pci_dev *pdev, pm_message_t state)
{
{
	struct be_adapter *adapter = pci_get_drvdata(pdev);
	struct be_adapter *adapter = pci_get_drvdata(pdev);
	struct net_device *netdev =  adapter->netdev;


	if (adapter->wol_en)
	if (adapter->wol_en)
		be_setup_wol(adapter, true);
		be_setup_wol(adapter, true);


	be_intr_set(adapter, false);
	be_intr_set(adapter, false);
	cancel_delayed_work_sync(&adapter->func_recovery_work);
	be_cancel_err_detection(adapter);


	netif_device_detach(netdev);
	be_cleanup(adapter);
	if (netif_running(netdev)) {
		rtnl_lock();
		be_close(netdev);
		rtnl_unlock();
	}
	be_clear(adapter);


	pci_save_state(pdev);
	pci_save_state(pdev);
	pci_disable_device(pdev);
	pci_disable_device(pdev);
@@ -5416,13 +5418,10 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state)
	return 0;
	return 0;
}
}


static int be_resume(struct pci_dev *pdev)
static int be_pci_resume(struct pci_dev *pdev)
{
{
	int status = 0;
	struct be_adapter *adapter = pci_get_drvdata(pdev);
	struct be_adapter *adapter = pci_get_drvdata(pdev);
	struct net_device *netdev =  adapter->netdev;
	int status = 0;

	netif_device_detach(netdev);


	status = pci_enable_device(pdev);
	status = pci_enable_device(pdev);
	if (status)
	if (status)
@@ -5431,30 +5430,11 @@ static int be_resume(struct pci_dev *pdev)
	pci_set_power_state(pdev, PCI_D0);
	pci_set_power_state(pdev, PCI_D0);
	pci_restore_state(pdev);
	pci_restore_state(pdev);


	status = be_fw_wait_ready(adapter);
	status = be_resume(adapter);
	if (status)
		return status;

	status = be_cmd_reset_function(adapter);
	if (status)
		return status;

	be_intr_set(adapter, true);
	/* tell fw we're ready to fire cmds */
	status = be_cmd_fw_init(adapter);
	if (status)
	if (status)
		return status;
		return status;


	be_setup(adapter);
	be_schedule_err_detection(adapter);
	if (netif_running(netdev)) {
		rtnl_lock();
		be_open(netdev);
		rtnl_unlock();
	}

	schedule_delayed_work(&adapter->func_recovery_work,
			      msecs_to_jiffies(1000));
	netif_device_attach(netdev);


	if (adapter->wol_en)
	if (adapter->wol_en)
		be_setup_wol(adapter, false);
		be_setup_wol(adapter, false);
@@ -5474,7 +5454,7 @@ static void be_shutdown(struct pci_dev *pdev)


	be_roce_dev_shutdown(adapter);
	be_roce_dev_shutdown(adapter);
	cancel_delayed_work_sync(&adapter->work);
	cancel_delayed_work_sync(&adapter->work);
	cancel_delayed_work_sync(&adapter->func_recovery_work);
	be_cancel_err_detection(adapter);


	netif_device_detach(adapter->netdev);
	netif_device_detach(adapter->netdev);


@@ -5487,22 +5467,15 @@ static pci_ers_result_t be_eeh_err_detected(struct pci_dev *pdev,
					    pci_channel_state_t state)
					    pci_channel_state_t state)
{
{
	struct be_adapter *adapter = pci_get_drvdata(pdev);
	struct be_adapter *adapter = pci_get_drvdata(pdev);
	struct net_device *netdev =  adapter->netdev;


	dev_err(&adapter->pdev->dev, "EEH error detected\n");
	dev_err(&adapter->pdev->dev, "EEH error detected\n");


	if (!adapter->eeh_error) {
	if (!adapter->eeh_error) {
		adapter->eeh_error = true;
		adapter->eeh_error = true;


		cancel_delayed_work_sync(&adapter->func_recovery_work);
		be_cancel_err_detection(adapter);

		rtnl_lock();
		netif_device_detach(netdev);
		if (netif_running(netdev))
			be_close(netdev);
		rtnl_unlock();


		be_clear(adapter);
		be_cleanup(adapter);
	}
	}


	if (state == pci_channel_io_perm_failure)
	if (state == pci_channel_io_perm_failure)
@@ -5553,40 +5526,16 @@ static void be_eeh_resume(struct pci_dev *pdev)
{
{
	int status = 0;
	int status = 0;
	struct be_adapter *adapter = pci_get_drvdata(pdev);
	struct be_adapter *adapter = pci_get_drvdata(pdev);
	struct net_device *netdev =  adapter->netdev;


	dev_info(&adapter->pdev->dev, "EEH resume\n");
	dev_info(&adapter->pdev->dev, "EEH resume\n");


	pci_save_state(pdev);
	pci_save_state(pdev);


	status = be_cmd_reset_function(adapter);
	status = be_resume(adapter);
	if (status)
	if (status)
		goto err;
		goto err;


	/* On some BE3 FW versions, after a HW reset,
	be_schedule_err_detection(adapter);
	 * interrupts will remain disabled for each function.
	 * So, explicitly enable interrupts
	 */
	be_intr_set(adapter, true);

	/* tell fw we're ready to fire cmds */
	status = be_cmd_fw_init(adapter);
	if (status)
		goto err;

	status = be_setup(adapter);
	if (status)
		goto err;

	if (netif_running(netdev)) {
		status = be_open(netdev);
		if (status)
			goto err;
	}

	schedule_delayed_work(&adapter->func_recovery_work,
			      msecs_to_jiffies(1000));
	netif_device_attach(netdev);
	return;
	return;
err:
err:
	dev_err(&adapter->pdev->dev, "EEH resume failed\n");
	dev_err(&adapter->pdev->dev, "EEH resume failed\n");
@@ -5604,7 +5553,7 @@ static struct pci_driver be_driver = {
	.probe = be_probe,
	.probe = be_probe,
	.remove = be_remove,
	.remove = be_remove,
	.suspend = be_suspend,
	.suspend = be_suspend,
	.resume = be_resume,
	.resume = be_pci_resume,
	.shutdown = be_shutdown,
	.shutdown = be_shutdown,
	.err_handler = &be_eeh_handlers
	.err_handler = &be_eeh_handlers
};
};