+static irqreturn_t
+jme_msix_misc(int irq, void *dev_id)
+{
+ struct net_device *netdev = dev_id;
+ struct jme_adapter *jme = netdev_priv(netdev);
+ __u32 intrstat;
+
+ pci_dma_sync_single_for_cpu(jme->pdev,
+ jme->shadow_dma,
+ sizeof(__u32) * SHADOW_REG_NR,
+ PCI_DMA_FROMDEVICE);
+ intrstat = jme->shadow_regs[SHADOW_IEVE];
+ jme->shadow_regs[SHADOW_IEVE] &= ~INTR_EN_MISC;
+
+ /*
+ * Disable interrupt
+ */
+ jwrite32f(jme, JME_IENC, INTR_EN_MISC);
+
+ if(intrstat & (INTR_LINKCH | INTR_SWINTR)) {
+ tasklet_schedule(&jme->linkch_task);
+ goto out_reenable;
+ }
+
+ if(intrstat & INTR_TMINTR)
+ tasklet_schedule(&jme->pcc_task);
+
+out_reenable:
+ /*
+ * Write 1 clear interrupt status
+ */
+ jwrite32f(jme, JME_IEVE, INTR_EN_MISC);
+
+ /*
+ * Re-enable interrupt
+ */
+ jwrite32f(jme, JME_IENS, INTR_EN_MISC);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+jme_msix_tx(int irq, void *dev_id)
+{
+ struct net_device *netdev = dev_id;
+ struct jme_adapter *jme = netdev_priv(netdev);
+
+ /*
+ * Disable interrupt
+ */
+ jwrite32f(jme, JME_IENC, INTR_EN_TX);
+
+ if(unlikely(atomic_read(&jme->link_changing) != 1))
+ goto out_reenable;
+
+ tasklet_schedule(&jme->txclean_task);
+
+out_reenable:
+ /*
+ * Write 1 clear interrupt status
+ */
+ jwrite32f(jme, JME_IEVE, INTR_EN_TX | INTR_TX0);
+
+ /*
+ * Re-enable interrupt
+ */
+ jwrite32f(jme, JME_IENS, INTR_EN_TX);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+jme_msix_rx(int irq, void *dev_id)
+{
+ struct net_device *netdev = dev_id;
+ struct jme_adapter *jme = netdev_priv(netdev);
+ __u32 intrstat;
+
+ pci_dma_sync_single_for_cpu(jme->pdev,
+ jme->shadow_dma,
+ sizeof(__u32) * SHADOW_REG_NR,
+ PCI_DMA_FROMDEVICE);
+ intrstat = jme->shadow_regs[SHADOW_IEVE];
+ jme->shadow_regs[SHADOW_IEVE] &= ~INTR_EN_RX0;
+
+ /*
+ * Disable interrupt
+ */
+ jwrite32f(jme, JME_IENC, INTR_EN_RX0);
+
+ if(unlikely(atomic_read(&jme->link_changing) != 1))
+ goto out_reenable;
+
+ if(jme->flags & JME_FLAG_POLL) {
+ if(intrstat & INTR_RX0EMP)
+ atomic_inc(&jme->rx_empty);
+
+ if(likely(JME_RX_SCHEDULE_PREP(jme))) {
+ jme_polling_mode(jme);
+ JME_RX_SCHEDULE(jme);
+ }
+ }
+ else {
+ if(intrstat & INTR_RX0EMP) {
+ atomic_inc(&jme->rx_empty);
+ tasklet_schedule(&jme->rxempty_task);
+ }
+ else if(intrstat & (INTR_PCCRX0TO | INTR_PCCRX0))
+ tasklet_schedule(&jme->rxclean_task);
+ }
+
+out_reenable:
+ /*
+ * Write 1 clear interrupt status
+ */
+ jwrite32f(jme, JME_IEVE, INTR_EN_RX0 | INTR_RX0);
+
+ /*
+ * Re-enable interrupt
+ */
+ jwrite32f(jme, JME_IENS, INTR_EN_RX0);
+
+ return IRQ_HANDLED;
+}