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

Commit e6a8fee2 authored by Ananda Raju's avatar Ananda Raju Committed by Jeff Garzik
Browse files

[PATCH] s2io driver irq fix



Modification and bug fixes with respect to irq registration.

- Enable interrupts after request_irq

- Restored MSI data register value at driver unload time

Signed-off-by: default avatarAnanda Raju <ananda.raju@neterion.com>
Cc: Jeff Garzik <jeff@garzik.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent 61ef5c00
Loading
Loading
Loading
Loading
+143 −142
Original line number Original line Diff line number Diff line
@@ -1976,7 +1976,6 @@ static int start_nic(struct s2io_nic *nic)
	XENA_dev_config_t __iomem *bar0 = nic->bar0;
	XENA_dev_config_t __iomem *bar0 = nic->bar0;
	struct net_device *dev = nic->dev;
	struct net_device *dev = nic->dev;
	register u64 val64 = 0;
	register u64 val64 = 0;
	u16 interruptible;
	u16 subid, i;
	u16 subid, i;
	mac_info_t *mac_control;
	mac_info_t *mac_control;
	struct config_param *config;
	struct config_param *config;
@@ -2047,16 +2046,6 @@ static int start_nic(struct s2io_nic *nic)
		return FAILURE;
		return FAILURE;
	}
	}


	/*  Enable select interrupts */
	if (nic->intr_type != INTA)
		en_dis_able_nic_intrs(nic, ENA_ALL_INTRS, DISABLE_INTRS);
	else {
		interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
		interruptible |= TX_PIC_INTR | RX_PIC_INTR;
		interruptible |= TX_MAC_INTR | RX_MAC_INTR;
		en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS);
	}

	/*
	/*
	 * With some switches, link might be already up at this point.
	 * With some switches, link might be already up at this point.
	 * Because of this weird behavior, when we enable laser,
	 * Because of this weird behavior, when we enable laser,
@@ -3749,101 +3738,19 @@ static int s2io_open(struct net_device *dev)
	if (err) {
	if (err) {
		DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
		DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
			  dev->name);
			  dev->name);
		if (err == -ENODEV)
		goto hw_init_failed;
		goto hw_init_failed;
		else
			goto hw_enable_failed;
	}

	/* Store the values of the MSIX table in the nic_t structure */
	store_xmsi_data(sp);

	/* After proper initialization of H/W, register ISR */
	if (sp->intr_type == MSI) {
		err = request_irq((int) sp->pdev->irq, s2io_msi_handle, 
			IRQF_SHARED, sp->name, dev);
		if (err) {
			DBG_PRINT(ERR_DBG, "%s: MSI registration \
failed\n", dev->name);
			goto isr_registration_failed;
		}
	}
	if (sp->intr_type == MSI_X) {
		int i;

		for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
			if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
				sprintf(sp->desc1, "%s:MSI-X-%d-TX",
					dev->name, i);
				err = request_irq(sp->entries[i].vector,
					  s2io_msix_fifo_handle, 0, sp->desc1,
					  sp->s2io_entries[i].arg);
				DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc1, 
				    (unsigned long long)sp->msix_info[i].addr);
			} else {
				sprintf(sp->desc2, "%s:MSI-X-%d-RX",
					dev->name, i);
				err = request_irq(sp->entries[i].vector,
					  s2io_msix_ring_handle, 0, sp->desc2,
					  sp->s2io_entries[i].arg);
				DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc2, 
				     (unsigned long long)sp->msix_info[i].addr);
			}
			if (err) {
				DBG_PRINT(ERR_DBG, "%s: MSI-X-%d registration \
failed\n", dev->name, i);
				DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
				goto isr_registration_failed;
			}
			sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
		}
	}
	if (sp->intr_type == INTA) {
		err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
				sp->name, dev);
		if (err) {
			DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
				  dev->name);
			goto isr_registration_failed;
		}
	}
	}


	if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
	if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
		DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
		DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
		s2io_card_down(sp);
		err = -ENODEV;
		err = -ENODEV;
		goto setting_mac_address_failed;
		goto hw_init_failed;
	}
	}


	netif_start_queue(dev);
	netif_start_queue(dev);
	return 0;
	return 0;


setting_mac_address_failed:
	if (sp->intr_type != MSI_X)
		free_irq(sp->pdev->irq, dev);
isr_registration_failed:
	del_timer_sync(&sp->alarm_timer);
	if (sp->intr_type == MSI_X) {
		int i;
		u16 msi_control; /* Temp variable */

		for (i=1; (sp->s2io_entries[i].in_use == 
				MSIX_REGISTERED_SUCCESS); i++) {
			int vector = sp->entries[i].vector;
			void *arg = sp->s2io_entries[i].arg;

			free_irq(vector, arg);
		}
		pci_disable_msix(sp->pdev);

		/* Temp */
		pci_read_config_word(sp->pdev, 0x42, &msi_control);
		msi_control &= 0xFFFE; /* Disable MSI */
		pci_write_config_word(sp->pdev, 0x42, msi_control);
	}
	else if (sp->intr_type == MSI)
		pci_disable_msi(sp->pdev);
hw_enable_failed:
	s2io_reset(sp);
hw_init_failed:
hw_init_failed:
	if (sp->intr_type == MSI_X) {
	if (sp->intr_type == MSI_X) {
		if (sp->entries)
		if (sp->entries)
@@ -3874,7 +3781,7 @@ static int s2io_close(struct net_device *dev)
	flush_scheduled_work();
	flush_scheduled_work();
	netif_stop_queue(dev);
	netif_stop_queue(dev);
	/* Reset card, kill tasklet and free Tx and Rx buffers. */
	/* Reset card, kill tasklet and free Tx and Rx buffers. */
	s2io_card_down(sp, 1);
	s2io_card_down(sp);


	sp->device_close_flag = TRUE;	/* Device is shut down. */
	sp->device_close_flag = TRUE;	/* Device is shut down. */
	return 0;
	return 0;
@@ -5919,7 +5826,7 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)


	dev->mtu = new_mtu;
	dev->mtu = new_mtu;
	if (netif_running(dev)) {
	if (netif_running(dev)) {
		s2io_card_down(sp, 0);
		s2io_card_down(sp);
		netif_stop_queue(dev);
		netif_stop_queue(dev);
		if (s2io_card_up(sp)) {
		if (s2io_card_up(sp)) {
			DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
			DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
@@ -6216,24 +6123,81 @@ static int rxd_owner_bit_reset(nic_t *sp)


}
}


static void s2io_card_down(nic_t * sp, int flag)
static int s2io_add_isr(nic_t * sp)
{
{
	int cnt = 0;
	int ret = 0;
	XENA_dev_config_t __iomem *bar0 = sp->bar0;
	unsigned long flags;
	register u64 val64 = 0;
	struct net_device *dev = sp->dev;
	struct net_device *dev = sp->dev;
	int err = 0;


	del_timer_sync(&sp->alarm_timer);
	if (sp->intr_type == MSI)
	/* If s2io_set_link task is executing, wait till it completes. */
		ret = s2io_enable_msi(sp);
	while (test_and_set_bit(0, &(sp->link_state))) {
	else if (sp->intr_type == MSI_X)
		msleep(50);
		ret = s2io_enable_msi_x(sp);
	if (ret) {
		DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
		sp->intr_type = INTA;
	}
	}
	atomic_set(&sp->card_state, CARD_DOWN);


	/* disable Tx and Rx traffic on the NIC */
	/* Store the values of the MSIX table in the nic_t structure */
	stop_nic(sp);
	store_xmsi_data(sp);
	if (flag) {

	/* After proper initialization of H/W, register ISR */
	if (sp->intr_type == MSI) {
		err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
			IRQF_SHARED, sp->name, dev);
		if (err) {
			pci_disable_msi(sp->pdev);
			DBG_PRINT(ERR_DBG, "%s: MSI registration failed\n",
				  dev->name);
			return -1;
		}
	}
	if (sp->intr_type == MSI_X) {
		int i;

		for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
			if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
				sprintf(sp->desc[i], "%s:MSI-X-%d-TX",
					dev->name, i);
				err = request_irq(sp->entries[i].vector,
					  s2io_msix_fifo_handle, 0, sp->desc[i],
						  sp->s2io_entries[i].arg);
				DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc[i],
				(unsigned long long)sp->msix_info[i].addr);
			} else {
				sprintf(sp->desc[i], "%s:MSI-X-%d-RX",
					dev->name, i);
				err = request_irq(sp->entries[i].vector,
					  s2io_msix_ring_handle, 0, sp->desc[i],
						  sp->s2io_entries[i].arg);
				DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc[i],
				(unsigned long long)sp->msix_info[i].addr);
			}
			if (err) {
				DBG_PRINT(ERR_DBG,"%s:MSI-X-%d registration "
					  "failed\n", dev->name, i);
				DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
				return -1;
			}
			sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
		}
	}
	if (sp->intr_type == INTA) {
		err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
				sp->name, dev);
		if (err) {
			DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
				  dev->name);
			return -1;
		}
	}
	return 0;
}
static void s2io_rem_isr(nic_t * sp)
{
	int cnt = 0;
	struct net_device *dev = sp->dev;

	if (sp->intr_type == MSI_X) {
	if (sp->intr_type == MSI_X) {
		int i;
		int i;
		u16 msi_control;
		u16 msi_control;
@@ -6248,11 +6212,17 @@ static void s2io_card_down(nic_t * sp, int flag)
		pci_read_config_word(sp->pdev, 0x42, &msi_control);
		pci_read_config_word(sp->pdev, 0x42, &msi_control);
		msi_control &= 0xFFFE; /* Disable MSI */
		msi_control &= 0xFFFE; /* Disable MSI */
		pci_write_config_word(sp->pdev, 0x42, msi_control);
		pci_write_config_word(sp->pdev, 0x42, msi_control);

		pci_disable_msix(sp->pdev);
		pci_disable_msix(sp->pdev);
	} else {
	} else {
		free_irq(sp->pdev->irq, dev);
		free_irq(sp->pdev->irq, dev);
			if (sp->intr_type == MSI)
		if (sp->intr_type == MSI) {
			u16 val;

			pci_disable_msi(sp->pdev);
			pci_disable_msi(sp->pdev);
			pci_read_config_word(sp->pdev, 0x4c, &val);
			val ^= 0x1;
			pci_write_config_word(sp->pdev, 0x4c, val);
		}
		}
	}
	}
	/* Waiting till all Interrupt handlers are complete */
	/* Waiting till all Interrupt handlers are complete */
@@ -6263,6 +6233,26 @@ static void s2io_card_down(nic_t * sp, int flag)
			break;
			break;
		cnt++;
		cnt++;
	} while(cnt < 5);
	} while(cnt < 5);
}

static void s2io_card_down(nic_t * sp)
{
	int cnt = 0;
	XENA_dev_config_t __iomem *bar0 = sp->bar0;
	unsigned long flags;
	register u64 val64 = 0;

	del_timer_sync(&sp->alarm_timer);
	/* If s2io_set_link task is executing, wait till it completes. */
	while (test_and_set_bit(0, &(sp->link_state))) {
		msleep(50);
	}
	atomic_set(&sp->card_state, CARD_DOWN);

	/* disable Tx and Rx traffic on the NIC */
	stop_nic(sp);

	s2io_rem_isr(sp);


	/* Kill tasklet. */
	/* Kill tasklet. */
	tasklet_kill(&sp->task);
	tasklet_kill(&sp->task);
@@ -6314,23 +6304,16 @@ static int s2io_card_up(nic_t * sp)
	mac_info_t *mac_control;
	mac_info_t *mac_control;
	struct config_param *config;
	struct config_param *config;
	struct net_device *dev = (struct net_device *) sp->dev;
	struct net_device *dev = (struct net_device *) sp->dev;
	u16 interruptible;


	/* Initialize the H/W I/O registers */
	/* Initialize the H/W I/O registers */
	if (init_nic(sp) != 0) {
	if (init_nic(sp) != 0) {
		DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
		DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
			  dev->name);
			  dev->name);
		s2io_reset(sp);
		return -ENODEV;
		return -ENODEV;
	}
	}


	if (sp->intr_type == MSI)
		ret = s2io_enable_msi(sp);
	else if (sp->intr_type == MSI_X)
		ret = s2io_enable_msi_x(sp);
	if (ret) {
		DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
		sp->intr_type = INTA;
	}

	/*
	/*
	 * Initializing the Rx buffers. For now we are considering only 1
	 * Initializing the Rx buffers. For now we are considering only 1
	 * Rx ring and initializing buffers into 30 Rx blocks
	 * Rx ring and initializing buffers into 30 Rx blocks
@@ -6361,21 +6344,39 @@ static int s2io_card_up(nic_t * sp)
			sp->lro_max_aggr_per_sess = lro_max_pkts;
			sp->lro_max_aggr_per_sess = lro_max_pkts;
	}
	}


	/* Enable tasklet for the device */
	tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);

	/* Enable Rx Traffic and interrupts on the NIC */
	/* Enable Rx Traffic and interrupts on the NIC */
	if (start_nic(sp)) {
	if (start_nic(sp)) {
		DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
		DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
		tasklet_kill(&sp->task);
		s2io_reset(sp);
		s2io_reset(sp);
		free_irq(dev->irq, dev);
		free_rx_buffers(sp);
		return -ENODEV;
	}

	/* Add interrupt service routine */
	if (s2io_add_isr(sp) != 0) {
		if (sp->intr_type == MSI_X)
			s2io_rem_isr(sp);
		s2io_reset(sp);
		free_rx_buffers(sp);
		free_rx_buffers(sp);
		return -ENODEV;
		return -ENODEV;
	}
	}


	S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
	S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));


	/* Enable tasklet for the device */
	tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);

	/*  Enable select interrupts */
	if (sp->intr_type != INTA)
		en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS);
	else {
		interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
		interruptible |= TX_PIC_INTR | RX_PIC_INTR;
		interruptible |= TX_MAC_INTR | RX_MAC_INTR;
		en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS);
	}


	atomic_set(&sp->card_state, CARD_UP);
	atomic_set(&sp->card_state, CARD_UP);
	return 0;
	return 0;
}
}
@@ -6395,7 +6396,7 @@ static void s2io_restart_nic(unsigned long data)
	struct net_device *dev = (struct net_device *) data;
	struct net_device *dev = (struct net_device *) data;
	nic_t *sp = dev->priv;
	nic_t *sp = dev->priv;


	s2io_card_down(sp, 0);
	s2io_card_down(sp);
	if (s2io_card_up(sp)) {
	if (s2io_card_up(sp)) {
		DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
		DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
			  dev->name);
			  dev->name);
+2 −3
Original line number Original line Diff line number Diff line
@@ -829,8 +829,7 @@ struct s2io_nic {
#define MSIX_FLG                0xA5
#define MSIX_FLG                0xA5
	struct msix_entry *entries;
	struct msix_entry *entries;
	struct s2io_msix_entry *s2io_entries;
	struct s2io_msix_entry *s2io_entries;
	char desc1[35];
	char desc[MAX_REQUESTED_MSI_X][25];
	char desc2[35];


	int avail_msix_vectors; /* No. of MSI-X vectors granted by system */
	int avail_msix_vectors; /* No. of MSI-X vectors granted by system */


@@ -1002,7 +1001,7 @@ static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag);
static struct ethtool_ops netdev_ethtool_ops;
static struct ethtool_ops netdev_ethtool_ops;
static void s2io_set_link(unsigned long data);
static void s2io_set_link(unsigned long data);
static int s2io_set_swapper(nic_t * sp);
static int s2io_set_swapper(nic_t * sp);
static void s2io_card_down(nic_t *nic, int flag);
static void s2io_card_down(nic_t *nic);
static int s2io_card_up(nic_t *nic);
static int s2io_card_up(nic_t *nic);
static int get_xena_rev_id(struct pci_dev *pdev);
static int get_xena_rev_id(struct pci_dev *pdev);
static void restore_xmsi_data(nic_t *nic);
static void restore_xmsi_data(nic_t *nic);