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

Commit 0ca41c04 authored by Divy Le Ray's avatar Divy Le Ray Committed by David S. Miller
Browse files

[2.6.28,1/1] cxgb3 - fix race in EEH



A SGE queue set timer might access registers while in EEH recovery,
triggering an EEH error loop. Stop all timers early in EEH process.

Signed-off-by: default avatarDivy Le Ray <divy@chelsio.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 822f1a57
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -284,6 +284,7 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status,


void t3_sge_start(struct adapter *adap);
void t3_sge_start(struct adapter *adap);
void t3_sge_stop(struct adapter *adap);
void t3_sge_stop(struct adapter *adap);
void t3_stop_sge_timers(struct adapter *adap);
void t3_free_sge_resources(struct adapter *adap);
void t3_free_sge_resources(struct adapter *adap);
void t3_sge_err_intr_handler(struct adapter *adapter);
void t3_sge_err_intr_handler(struct adapter *adapter);
irq_handler_t t3_intr_handler(struct adapter *adap, int polling);
irq_handler_t t3_intr_handler(struct adapter *adap, int polling);
+5 −0
Original line number Original line Diff line number Diff line
@@ -479,6 +479,7 @@ static int setup_sge_qsets(struct adapter *adap)
							     irq_idx,
							     irq_idx,
				&adap->params.sge.qset[qset_idx], ntxq, dev);
				&adap->params.sge.qset[qset_idx], ntxq, dev);
			if (err) {
			if (err) {
				t3_stop_sge_timers(adap);
				t3_free_sge_resources(adap);
				t3_free_sge_resources(adap);
				return err;
				return err;
			}
			}
@@ -2449,6 +2450,9 @@ static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev,
	    test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
	    test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
		offload_close(&adapter->tdev);
		offload_close(&adapter->tdev);


	/* Stop SGE timers */
	t3_stop_sge_timers(adapter);

	adapter->flags &= ~FULL_INIT_DONE;
	adapter->flags &= ~FULL_INIT_DONE;


	pci_disable_device(pdev);
	pci_disable_device(pdev);
@@ -2801,6 +2805,7 @@ static void __devexit remove_one(struct pci_dev *pdev)
		    if (test_bit(i, &adapter->registered_device_map))
		    if (test_bit(i, &adapter->registered_device_map))
			unregister_netdev(adapter->port[i]);
			unregister_netdev(adapter->port[i]);


		t3_stop_sge_timers(adapter);
		t3_free_sge_resources(adapter);
		t3_free_sge_resources(adapter);
		cxgb_disable_msi(adapter);
		cxgb_disable_msi(adapter);


+18 −3
Original line number Original line Diff line number Diff line
@@ -603,9 +603,6 @@ static void t3_free_qset(struct adapter *adapter, struct sge_qset *q)
	int i;
	int i;
	struct pci_dev *pdev = adapter->pdev;
	struct pci_dev *pdev = adapter->pdev;


	if (q->tx_reclaim_timer.function)
		del_timer_sync(&q->tx_reclaim_timer);

	for (i = 0; i < SGE_RXQ_PER_SET; ++i)
	for (i = 0; i < SGE_RXQ_PER_SET; ++i)
		if (q->fl[i].desc) {
		if (q->fl[i].desc) {
			spin_lock_irq(&adapter->sge.reg_lock);
			spin_lock_irq(&adapter->sge.reg_lock);
@@ -3008,6 +3005,24 @@ err:
	return ret;
	return ret;
}
}


/**
 *	t3_stop_sge_timers - stop SGE timer call backs
 *	@adap: the adapter
 *
 *	Stops each SGE queue set's timer call back
 */
void t3_stop_sge_timers(struct adapter *adap)
{
	int i;

	for (i = 0; i < SGE_QSETS; ++i) {
		struct sge_qset *q = &adap->sge.qs[i];

		if (q->tx_reclaim_timer.function)
			del_timer_sync(&q->tx_reclaim_timer);
	}
}

/**
/**
 *	t3_free_sge_resources - free SGE resources
 *	t3_free_sge_resources - free SGE resources
 *	@adap: the adapter
 *	@adap: the adapter