|
@@ -116,6 +116,56 @@ static int intelxl_fetch_mac ( struct intelxl_nic *intelxl,
|
116
|
116
|
return 0;
|
117
|
117
|
}
|
118
|
118
|
|
|
119
|
+/******************************************************************************
|
|
120
|
+ *
|
|
121
|
+ * MSI-X interrupts
|
|
122
|
+ *
|
|
123
|
+ ******************************************************************************
|
|
124
|
+ */
|
|
125
|
+
|
|
126
|
+/**
|
|
127
|
+ * Enable MSI-X dummy interrupt
|
|
128
|
+ *
|
|
129
|
+ * @v intelxl Intel device
|
|
130
|
+ * @v pci PCI device
|
|
131
|
+ * @ret rc Return status code
|
|
132
|
+ */
|
|
133
|
+int intelxl_msix_enable ( struct intelxl_nic *intelxl,
|
|
134
|
+ struct pci_device *pci ) {
|
|
135
|
+ int rc;
|
|
136
|
+
|
|
137
|
+ /* Enable MSI-X capability */
|
|
138
|
+ if ( ( rc = pci_msix_enable ( pci, &intelxl->msix ) ) != 0 ) {
|
|
139
|
+ DBGC ( intelxl, "INTELXL %p could not enable MSI-X: %s\n",
|
|
140
|
+ intelxl, strerror ( rc ) );
|
|
141
|
+ return rc;
|
|
142
|
+ }
|
|
143
|
+
|
|
144
|
+ /* Configure interrupt zero to write to dummy location */
|
|
145
|
+ pci_msix_map ( &intelxl->msix, 0, virt_to_bus ( &intelxl->msg ), 0 );
|
|
146
|
+
|
|
147
|
+ /* Enable dummy interrupt zero */
|
|
148
|
+ pci_msix_unmask ( &intelxl->msix, 0 );
|
|
149
|
+
|
|
150
|
+ return 0;
|
|
151
|
+}
|
|
152
|
+
|
|
153
|
+/**
|
|
154
|
+ * Disable MSI-X dummy interrupt
|
|
155
|
+ *
|
|
156
|
+ * @v intelxl Intel device
|
|
157
|
+ * @v pci PCI device
|
|
158
|
+ */
|
|
159
|
+void intelxl_msix_disable ( struct intelxl_nic *intelxl,
|
|
160
|
+ struct pci_device *pci ) {
|
|
161
|
+
|
|
162
|
+ /* Disable dummy interrupt zero */
|
|
163
|
+ pci_msix_mask ( &intelxl->msix, 0 );
|
|
164
|
+
|
|
165
|
+ /* Disable MSI-X capability */
|
|
166
|
+ pci_msix_disable ( pci, &intelxl->msix );
|
|
167
|
+}
|
|
168
|
+
|
119
|
169
|
/******************************************************************************
|
120
|
170
|
*
|
121
|
171
|
* Admin queue
|
|
@@ -480,6 +530,39 @@ static int intelxl_admin_shutdown ( struct intelxl_nic *intelxl ) {
|
480
|
530
|
return 0;
|
481
|
531
|
}
|
482
|
532
|
|
|
533
|
+/**
|
|
534
|
+ * Clear PXE mode
|
|
535
|
+ *
|
|
536
|
+ * @v intelxl Intel device
|
|
537
|
+ * @ret rc Return status code
|
|
538
|
+ */
|
|
539
|
+static int intelxl_admin_clear_pxe ( struct intelxl_nic *intelxl ) {
|
|
540
|
+ struct intelxl_admin_descriptor *cmd;
|
|
541
|
+ struct intelxl_admin_clear_pxe_params *pxe;
|
|
542
|
+ uint32_t gllan_rctl_0;
|
|
543
|
+ int rc;
|
|
544
|
+
|
|
545
|
+ /* Do nothing if device is already out of PXE mode */
|
|
546
|
+ gllan_rctl_0 = readl ( intelxl->regs + INTELXL_GLLAN_RCTL_0 );
|
|
547
|
+ if ( ! ( gllan_rctl_0 & INTELXL_GLLAN_RCTL_0_PXE_MODE ) ) {
|
|
548
|
+ DBGC2 ( intelxl, "INTELXL %p already in non-PXE mode\n",
|
|
549
|
+ intelxl );
|
|
550
|
+ return 0;
|
|
551
|
+ }
|
|
552
|
+
|
|
553
|
+ /* Populate descriptor */
|
|
554
|
+ cmd = intelxl_admin_command_descriptor ( intelxl );
|
|
555
|
+ cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_CLEAR_PXE );
|
|
556
|
+ pxe = &cmd->params.pxe;
|
|
557
|
+ pxe->magic = INTELXL_ADMIN_CLEAR_PXE_MAGIC;
|
|
558
|
+
|
|
559
|
+ /* Issue command */
|
|
560
|
+ if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
|
|
561
|
+ return rc;
|
|
562
|
+
|
|
563
|
+ return 0;
|
|
564
|
+}
|
|
565
|
+
|
483
|
566
|
/**
|
484
|
567
|
* Get switch configuration
|
485
|
568
|
*
|
|
@@ -1504,13 +1587,6 @@ static void intelxl_poll_rx ( struct net_device *netdev ) {
|
1504
|
1587
|
void intelxl_poll ( struct net_device *netdev ) {
|
1505
|
1588
|
struct intelxl_nic *intelxl = netdev->priv;
|
1506
|
1589
|
|
1507
|
|
- /* Acknowledge interrupts, if applicable */
|
1508
|
|
- if ( netdev_irq_enabled ( netdev ) ) {
|
1509
|
|
- writel ( ( INTELXL_INT_DYN_CTL_CLEARPBA |
|
1510
|
|
- INTELXL_INT_DYN_CTL_INTENA_MASK ),
|
1511
|
|
- ( intelxl->regs + intelxl->intr ) );
|
1512
|
|
- }
|
1513
|
|
-
|
1514
|
1590
|
/* Poll for completed packets */
|
1515
|
1591
|
intelxl_poll_tx ( netdev );
|
1516
|
1592
|
|
|
@@ -1522,19 +1598,23 @@ void intelxl_poll ( struct net_device *netdev ) {
|
1522
|
1598
|
|
1523
|
1599
|
/* Refill RX ring */
|
1524
|
1600
|
intelxl_refill_rx ( intelxl );
|
1525
|
|
-}
|
1526
|
|
-
|
1527
|
|
-/**
|
1528
|
|
- * Enable or disable interrupts
|
1529
|
|
- *
|
1530
|
|
- * @v netdev Network device
|
1531
|
|
- * @v enable Interrupts should be enabled
|
1532
|
|
- */
|
1533
|
|
-static void intelxl_irq ( struct net_device *netdev, int enable ) {
|
1534
|
|
- struct intelxl_nic *intelxl = netdev->priv;
|
1535
|
1601
|
|
1536
|
|
- writel ( ( enable ? INTELXL_INT_DYN_CTL_INTENA : 0 ),
|
1537
|
|
- ( intelxl->regs + intelxl->intr ) );
|
|
1602
|
+ /* Rearm interrupt, since otherwise receive descriptors will
|
|
1603
|
+ * be written back only after a complete cacheline (four
|
|
1604
|
+ * packets) have been received.
|
|
1605
|
+ *
|
|
1606
|
+ * There is unfortunately no efficient way to determine
|
|
1607
|
+ * whether or not rearming the interrupt is necessary. If we
|
|
1608
|
+ * are running inside a hypervisor (e.g. using a VF or PF as a
|
|
1609
|
+ * passed-through PCI device), then the MSI-X write is
|
|
1610
|
+ * redirected by the hypervisor to the real host APIC and the
|
|
1611
|
+ * host ISR then raises an interrupt within the guest. We
|
|
1612
|
+ * therefore cannot poll the nominal MSI-X target location to
|
|
1613
|
+ * watch for the value being written. We could read from the
|
|
1614
|
+ * INT_DYN_CTL register, but this is even less efficient than
|
|
1615
|
+ * just unconditionally rearming the interrupt.
|
|
1616
|
+ */
|
|
1617
|
+ writel ( INTELXL_INT_DYN_CTL_INTENA, intelxl->regs + intelxl->intr );
|
1538
|
1618
|
}
|
1539
|
1619
|
|
1540
|
1620
|
/** Network device operations */
|
|
@@ -1543,7 +1623,6 @@ static struct net_device_operations intelxl_operations = {
|
1543
|
1623
|
.close = intelxl_close,
|
1544
|
1624
|
.transmit = intelxl_transmit,
|
1545
|
1625
|
.poll = intelxl_poll,
|
1546
|
|
- .irq = intelxl_irq,
|
1547
|
1626
|
};
|
1548
|
1627
|
|
1549
|
1628
|
/******************************************************************************
|
|
@@ -1617,10 +1696,18 @@ static int intelxl_probe ( struct pci_device *pci ) {
|
1617
|
1696
|
if ( ( rc = intelxl_fetch_mac ( intelxl, netdev ) ) != 0 )
|
1618
|
1697
|
goto err_fetch_mac;
|
1619
|
1698
|
|
|
1699
|
+ /* Enable MSI-X dummy interrupt */
|
|
1700
|
+ if ( ( rc = intelxl_msix_enable ( intelxl, pci ) ) != 0 )
|
|
1701
|
+ goto err_msix;
|
|
1702
|
+
|
1620
|
1703
|
/* Open admin queues */
|
1621
|
1704
|
if ( ( rc = intelxl_open_admin ( intelxl ) ) != 0 )
|
1622
|
1705
|
goto err_open_admin;
|
1623
|
1706
|
|
|
1707
|
+ /* Clear PXE mode */
|
|
1708
|
+ if ( ( rc = intelxl_admin_clear_pxe ( intelxl ) ) != 0 )
|
|
1709
|
+ goto err_admin_clear_pxe;
|
|
1710
|
+
|
1624
|
1711
|
/* Get switch configuration */
|
1625
|
1712
|
if ( ( rc = intelxl_admin_switch ( intelxl ) ) != 0 )
|
1626
|
1713
|
goto err_admin_switch;
|
|
@@ -1667,8 +1754,11 @@ static int intelxl_probe ( struct pci_device *pci ) {
|
1667
|
1754
|
err_admin_promisc:
|
1668
|
1755
|
err_admin_vsi:
|
1669
|
1756
|
err_admin_switch:
|
|
1757
|
+ err_admin_clear_pxe:
|
1670
|
1758
|
intelxl_close_admin ( intelxl );
|
1671
|
1759
|
err_open_admin:
|
|
1760
|
+ intelxl_msix_disable ( intelxl, pci );
|
|
1761
|
+ err_msix:
|
1672
|
1762
|
err_fetch_mac:
|
1673
|
1763
|
intelxl_reset ( intelxl );
|
1674
|
1764
|
err_reset:
|
|
@@ -1695,6 +1785,9 @@ static void intelxl_remove ( struct pci_device *pci ) {
|
1695
|
1785
|
/* Close admin queues */
|
1696
|
1786
|
intelxl_close_admin ( intelxl );
|
1697
|
1787
|
|
|
1788
|
+ /* Disable MSI-X dummy interrupt */
|
|
1789
|
+ intelxl_msix_disable ( intelxl, pci );
|
|
1790
|
+
|
1698
|
1791
|
/* Reset the NIC */
|
1699
|
1792
|
intelxl_reset ( intelxl );
|
1700
|
1793
|
|