|
@@ -87,6 +87,470 @@ static int fm10k_hw_ready(struct fm10k_intfc *interface)
|
|
|
return FM10K_REMOVED(hw->hw_addr) ? -ENODEV : 0;
|
|
|
}
|
|
|
|
|
|
+static void fm10k_napi_enable_all(struct fm10k_intfc *interface)
|
|
|
+{
|
|
|
+ struct fm10k_q_vector *q_vector;
|
|
|
+ int q_idx;
|
|
|
+
|
|
|
+ for (q_idx = 0; q_idx < interface->num_q_vectors; q_idx++) {
|
|
|
+ q_vector = interface->q_vector[q_idx];
|
|
|
+ napi_enable(&q_vector->napi);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static irqreturn_t fm10k_msix_clean_rings(int irq, void *data)
|
|
|
+{
|
|
|
+ struct fm10k_q_vector *q_vector = data;
|
|
|
+
|
|
|
+ if (q_vector->rx.count || q_vector->tx.count)
|
|
|
+ napi_schedule(&q_vector->napi);
|
|
|
+
|
|
|
+ return IRQ_HANDLED;
|
|
|
+}
|
|
|
+
|
|
|
+#define FM10K_ERR_MSG(type) case (type): error = #type; break
|
|
|
+static void fm10k_print_fault(struct fm10k_intfc *interface, int type,
|
|
|
+ struct fm10k_fault *fault)
|
|
|
+{
|
|
|
+ struct pci_dev *pdev = interface->pdev;
|
|
|
+ char *error;
|
|
|
+
|
|
|
+ switch (type) {
|
|
|
+ case FM10K_PCA_FAULT:
|
|
|
+ switch (fault->type) {
|
|
|
+ default:
|
|
|
+ error = "Unknown PCA error";
|
|
|
+ break;
|
|
|
+ FM10K_ERR_MSG(PCA_NO_FAULT);
|
|
|
+ FM10K_ERR_MSG(PCA_UNMAPPED_ADDR);
|
|
|
+ FM10K_ERR_MSG(PCA_BAD_QACCESS_PF);
|
|
|
+ FM10K_ERR_MSG(PCA_BAD_QACCESS_VF);
|
|
|
+ FM10K_ERR_MSG(PCA_MALICIOUS_REQ);
|
|
|
+ FM10K_ERR_MSG(PCA_POISONED_TLP);
|
|
|
+ FM10K_ERR_MSG(PCA_TLP_ABORT);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case FM10K_THI_FAULT:
|
|
|
+ switch (fault->type) {
|
|
|
+ default:
|
|
|
+ error = "Unknown THI error";
|
|
|
+ break;
|
|
|
+ FM10K_ERR_MSG(THI_NO_FAULT);
|
|
|
+ FM10K_ERR_MSG(THI_MAL_DIS_Q_FAULT);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case FM10K_FUM_FAULT:
|
|
|
+ switch (fault->type) {
|
|
|
+ default:
|
|
|
+ error = "Unknown FUM error";
|
|
|
+ break;
|
|
|
+ FM10K_ERR_MSG(FUM_NO_FAULT);
|
|
|
+ FM10K_ERR_MSG(FUM_UNMAPPED_ADDR);
|
|
|
+ FM10K_ERR_MSG(FUM_BAD_VF_QACCESS);
|
|
|
+ FM10K_ERR_MSG(FUM_ADD_DECODE_ERR);
|
|
|
+ FM10K_ERR_MSG(FUM_RO_ERROR);
|
|
|
+ FM10K_ERR_MSG(FUM_QPRC_CRC_ERROR);
|
|
|
+ FM10K_ERR_MSG(FUM_CSR_TIMEOUT);
|
|
|
+ FM10K_ERR_MSG(FUM_INVALID_TYPE);
|
|
|
+ FM10K_ERR_MSG(FUM_INVALID_LENGTH);
|
|
|
+ FM10K_ERR_MSG(FUM_INVALID_BE);
|
|
|
+ FM10K_ERR_MSG(FUM_INVALID_ALIGN);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ error = "Undocumented fault";
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ dev_warn(&pdev->dev,
|
|
|
+ "%s Address: 0x%llx SpecInfo: 0x%x Func: %02x.%0x\n",
|
|
|
+ error, fault->address, fault->specinfo,
|
|
|
+ PCI_SLOT(fault->func), PCI_FUNC(fault->func));
|
|
|
+}
|
|
|
+
|
|
|
+static void fm10k_report_fault(struct fm10k_intfc *interface, u32 eicr)
|
|
|
+{
|
|
|
+ struct fm10k_hw *hw = &interface->hw;
|
|
|
+ struct fm10k_fault fault = { 0 };
|
|
|
+ int type, err;
|
|
|
+
|
|
|
+ for (eicr &= FM10K_EICR_FAULT_MASK, type = FM10K_PCA_FAULT;
|
|
|
+ eicr;
|
|
|
+ eicr >>= 1, type += FM10K_FAULT_SIZE) {
|
|
|
+ /* only check if there is an error reported */
|
|
|
+ if (!(eicr & 0x1))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ /* retrieve fault info */
|
|
|
+ err = hw->mac.ops.get_fault(hw, type, &fault);
|
|
|
+ if (err) {
|
|
|
+ dev_err(&interface->pdev->dev,
|
|
|
+ "error reading fault\n");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ fm10k_print_fault(interface, type, &fault);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void fm10k_reset_drop_on_empty(struct fm10k_intfc *interface, u32 eicr)
|
|
|
+{
|
|
|
+ struct fm10k_hw *hw = &interface->hw;
|
|
|
+ const u32 rxdctl = FM10K_RXDCTL_WRITE_BACK_MIN_DELAY;
|
|
|
+ u32 maxholdq;
|
|
|
+ int q;
|
|
|
+
|
|
|
+ if (!(eicr & FM10K_EICR_MAXHOLDTIME))
|
|
|
+ return;
|
|
|
+
|
|
|
+ maxholdq = fm10k_read_reg(hw, FM10K_MAXHOLDQ(7));
|
|
|
+ if (maxholdq)
|
|
|
+ fm10k_write_reg(hw, FM10K_MAXHOLDQ(7), maxholdq);
|
|
|
+ for (q = 255;;) {
|
|
|
+ if (maxholdq & (1 << 31)) {
|
|
|
+ if (q < FM10K_MAX_QUEUES_PF) {
|
|
|
+ interface->rx_overrun_pf++;
|
|
|
+ fm10k_write_reg(hw, FM10K_RXDCTL(q), rxdctl);
|
|
|
+ } else {
|
|
|
+ interface->rx_overrun_vf++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ maxholdq *= 2;
|
|
|
+ if (!maxholdq)
|
|
|
+ q &= ~(32 - 1);
|
|
|
+
|
|
|
+ if (!q)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (q-- % 32)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ maxholdq = fm10k_read_reg(hw, FM10K_MAXHOLDQ(q / 32));
|
|
|
+ if (maxholdq)
|
|
|
+ fm10k_write_reg(hw, FM10K_MAXHOLDQ(q / 32), maxholdq);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static irqreturn_t fm10k_msix_mbx_pf(int irq, void *data)
|
|
|
+{
|
|
|
+ struct fm10k_intfc *interface = data;
|
|
|
+ struct fm10k_hw *hw = &interface->hw;
|
|
|
+ struct fm10k_mbx_info *mbx = &hw->mbx;
|
|
|
+ u32 eicr;
|
|
|
+
|
|
|
+ /* unmask any set bits related to this interrupt */
|
|
|
+ eicr = fm10k_read_reg(hw, FM10K_EICR);
|
|
|
+ fm10k_write_reg(hw, FM10K_EICR, eicr & (FM10K_EICR_MAILBOX |
|
|
|
+ FM10K_EICR_SWITCHREADY |
|
|
|
+ FM10K_EICR_SWITCHNOTREADY));
|
|
|
+
|
|
|
+ /* report any faults found to the message log */
|
|
|
+ fm10k_report_fault(interface, eicr);
|
|
|
+
|
|
|
+ /* reset any queues disabled due to receiver overrun */
|
|
|
+ fm10k_reset_drop_on_empty(interface, eicr);
|
|
|
+
|
|
|
+ /* service mailboxes */
|
|
|
+ if (fm10k_mbx_trylock(interface)) {
|
|
|
+ mbx->ops.process(hw, mbx);
|
|
|
+ fm10k_mbx_unlock(interface);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* re-enable mailbox interrupt and indicate 20us delay */
|
|
|
+ fm10k_write_reg(hw, FM10K_ITR(FM10K_MBX_VECTOR),
|
|
|
+ FM10K_ITR_ENABLE | FM10K_MBX_INT_DELAY);
|
|
|
+
|
|
|
+ return IRQ_HANDLED;
|
|
|
+}
|
|
|
+
|
|
|
+void fm10k_mbx_free_irq(struct fm10k_intfc *interface)
|
|
|
+{
|
|
|
+ struct msix_entry *entry = &interface->msix_entries[FM10K_MBX_VECTOR];
|
|
|
+ struct fm10k_hw *hw = &interface->hw;
|
|
|
+ int itr_reg;
|
|
|
+
|
|
|
+ /* disconnect the mailbox */
|
|
|
+ hw->mbx.ops.disconnect(hw, &hw->mbx);
|
|
|
+
|
|
|
+ /* disable Mailbox cause */
|
|
|
+ if (hw->mac.type == fm10k_mac_pf) {
|
|
|
+ fm10k_write_reg(hw, FM10K_EIMR,
|
|
|
+ FM10K_EIMR_DISABLE(PCA_FAULT) |
|
|
|
+ FM10K_EIMR_DISABLE(FUM_FAULT) |
|
|
|
+ FM10K_EIMR_DISABLE(MAILBOX) |
|
|
|
+ FM10K_EIMR_DISABLE(SWITCHREADY) |
|
|
|
+ FM10K_EIMR_DISABLE(SWITCHNOTREADY) |
|
|
|
+ FM10K_EIMR_DISABLE(SRAMERROR) |
|
|
|
+ FM10K_EIMR_DISABLE(VFLR) |
|
|
|
+ FM10K_EIMR_DISABLE(MAXHOLDTIME));
|
|
|
+ itr_reg = FM10K_ITR(FM10K_MBX_VECTOR);
|
|
|
+ }
|
|
|
+
|
|
|
+ fm10k_write_reg(hw, itr_reg, FM10K_ITR_MASK_SET);
|
|
|
+
|
|
|
+ free_irq(entry->vector, interface);
|
|
|
+}
|
|
|
+
|
|
|
+/* generic error handler for mailbox issues */
|
|
|
+static s32 fm10k_mbx_error(struct fm10k_hw *hw, u32 **results,
|
|
|
+ struct fm10k_mbx_info *mbx)
|
|
|
+{
|
|
|
+ struct fm10k_intfc *interface;
|
|
|
+ struct pci_dev *pdev;
|
|
|
+
|
|
|
+ interface = container_of(hw, struct fm10k_intfc, hw);
|
|
|
+ pdev = interface->pdev;
|
|
|
+
|
|
|
+ dev_err(&pdev->dev, "Unknown message ID %u\n",
|
|
|
+ **results & FM10K_TLV_ID_MASK);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static s32 fm10k_lport_map(struct fm10k_hw *hw, u32 **results,
|
|
|
+ struct fm10k_mbx_info *mbx)
|
|
|
+{
|
|
|
+ struct fm10k_intfc *interface;
|
|
|
+ u32 dglort_map = hw->mac.dglort_map;
|
|
|
+ s32 err;
|
|
|
+
|
|
|
+ err = fm10k_msg_lport_map_pf(hw, results, mbx);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ interface = container_of(hw, struct fm10k_intfc, hw);
|
|
|
+
|
|
|
+ /* we need to reset if port count was just updated */
|
|
|
+ if (dglort_map != hw->mac.dglort_map)
|
|
|
+ interface->flags |= FM10K_FLAG_RESET_REQUESTED;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static s32 fm10k_update_pvid(struct fm10k_hw *hw, u32 **results,
|
|
|
+ struct fm10k_mbx_info *mbx)
|
|
|
+{
|
|
|
+ struct fm10k_intfc *interface;
|
|
|
+ u16 glort, pvid;
|
|
|
+ u32 pvid_update;
|
|
|
+ s32 err;
|
|
|
+
|
|
|
+ err = fm10k_tlv_attr_get_u32(results[FM10K_PF_ATTR_ID_UPDATE_PVID],
|
|
|
+ &pvid_update);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ /* extract values from the pvid update */
|
|
|
+ glort = FM10K_MSG_HDR_FIELD_GET(pvid_update, UPDATE_PVID_GLORT);
|
|
|
+ pvid = FM10K_MSG_HDR_FIELD_GET(pvid_update, UPDATE_PVID_PVID);
|
|
|
+
|
|
|
+ /* if glort is not valid return error */
|
|
|
+ if (!fm10k_glort_valid_pf(hw, glort))
|
|
|
+ return FM10K_ERR_PARAM;
|
|
|
+
|
|
|
+ /* verify VID is valid */
|
|
|
+ if (pvid >= FM10K_VLAN_TABLE_VID_MAX)
|
|
|
+ return FM10K_ERR_PARAM;
|
|
|
+
|
|
|
+ interface = container_of(hw, struct fm10k_intfc, hw);
|
|
|
+
|
|
|
+ /* we need to reset if default VLAN was just updated */
|
|
|
+ if (pvid != hw->mac.default_vid)
|
|
|
+ interface->flags |= FM10K_FLAG_RESET_REQUESTED;
|
|
|
+
|
|
|
+ hw->mac.default_vid = pvid;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static const struct fm10k_msg_data pf_mbx_data[] = {
|
|
|
+ FM10K_PF_MSG_ERR_HANDLER(XCAST_MODES, fm10k_msg_err_pf),
|
|
|
+ FM10K_PF_MSG_ERR_HANDLER(UPDATE_MAC_FWD_RULE, fm10k_msg_err_pf),
|
|
|
+ FM10K_PF_MSG_LPORT_MAP_HANDLER(fm10k_lport_map),
|
|
|
+ FM10K_PF_MSG_ERR_HANDLER(LPORT_CREATE, fm10k_msg_err_pf),
|
|
|
+ FM10K_PF_MSG_ERR_HANDLER(LPORT_DELETE, fm10k_msg_err_pf),
|
|
|
+ FM10K_PF_MSG_UPDATE_PVID_HANDLER(fm10k_update_pvid),
|
|
|
+ FM10K_TLV_MSG_ERROR_HANDLER(fm10k_mbx_error),
|
|
|
+};
|
|
|
+
|
|
|
+static int fm10k_mbx_request_irq_pf(struct fm10k_intfc *interface)
|
|
|
+{
|
|
|
+ struct msix_entry *entry = &interface->msix_entries[FM10K_MBX_VECTOR];
|
|
|
+ struct net_device *dev = interface->netdev;
|
|
|
+ struct fm10k_hw *hw = &interface->hw;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ /* Use timer0 for interrupt moderation on the mailbox */
|
|
|
+ u32 mbx_itr = FM10K_INT_MAP_TIMER0 | entry->entry;
|
|
|
+ u32 other_itr = FM10K_INT_MAP_IMMEDIATE | entry->entry;
|
|
|
+
|
|
|
+ /* register mailbox handlers */
|
|
|
+ err = hw->mbx.ops.register_handlers(&hw->mbx, pf_mbx_data);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ /* request the IRQ */
|
|
|
+ err = request_irq(entry->vector, fm10k_msix_mbx_pf, 0,
|
|
|
+ dev->name, interface);
|
|
|
+ if (err) {
|
|
|
+ netif_err(interface, probe, dev,
|
|
|
+ "request_irq for msix_mbx failed: %d\n", err);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Enable interrupts w/ no moderation for "other" interrupts */
|
|
|
+ fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_PCIeFault), other_itr);
|
|
|
+ fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_SwitchUpDown), other_itr);
|
|
|
+ fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_SRAM), other_itr);
|
|
|
+ fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_MaxHoldTime), other_itr);
|
|
|
+ fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_VFLR), other_itr);
|
|
|
+
|
|
|
+ /* Enable interrupts w/ moderation for mailbox */
|
|
|
+ fm10k_write_reg(hw, FM10K_INT_MAP(fm10k_int_Mailbox), mbx_itr);
|
|
|
+
|
|
|
+ /* Enable individual interrupt causes */
|
|
|
+ fm10k_write_reg(hw, FM10K_EIMR, FM10K_EIMR_ENABLE(PCA_FAULT) |
|
|
|
+ FM10K_EIMR_ENABLE(FUM_FAULT) |
|
|
|
+ FM10K_EIMR_ENABLE(MAILBOX) |
|
|
|
+ FM10K_EIMR_ENABLE(SWITCHREADY) |
|
|
|
+ FM10K_EIMR_ENABLE(SWITCHNOTREADY) |
|
|
|
+ FM10K_EIMR_ENABLE(SRAMERROR) |
|
|
|
+ FM10K_EIMR_ENABLE(VFLR) |
|
|
|
+ FM10K_EIMR_ENABLE(MAXHOLDTIME));
|
|
|
+
|
|
|
+ /* enable interrupt */
|
|
|
+ fm10k_write_reg(hw, FM10K_ITR(entry->entry), FM10K_ITR_ENABLE);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+int fm10k_mbx_request_irq(struct fm10k_intfc *interface)
|
|
|
+{
|
|
|
+ struct fm10k_hw *hw = &interface->hw;
|
|
|
+ int err;
|
|
|
+
|
|
|
+ /* enable Mailbox cause */
|
|
|
+ err = fm10k_mbx_request_irq_pf(interface);
|
|
|
+
|
|
|
+ /* connect mailbox */
|
|
|
+ if (!err)
|
|
|
+ err = hw->mbx.ops.connect(hw, &hw->mbx);
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * fm10k_qv_free_irq - release interrupts associated with queue vectors
|
|
|
+ * @interface: board private structure
|
|
|
+ *
|
|
|
+ * Release all interrupts associated with this interface
|
|
|
+ **/
|
|
|
+void fm10k_qv_free_irq(struct fm10k_intfc *interface)
|
|
|
+{
|
|
|
+ int vector = interface->num_q_vectors;
|
|
|
+ struct fm10k_hw *hw = &interface->hw;
|
|
|
+ struct msix_entry *entry;
|
|
|
+
|
|
|
+ entry = &interface->msix_entries[NON_Q_VECTORS(hw) + vector];
|
|
|
+
|
|
|
+ while (vector) {
|
|
|
+ struct fm10k_q_vector *q_vector;
|
|
|
+
|
|
|
+ vector--;
|
|
|
+ entry--;
|
|
|
+ q_vector = interface->q_vector[vector];
|
|
|
+
|
|
|
+ if (!q_vector->tx.count && !q_vector->rx.count)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ /* disable interrupts */
|
|
|
+
|
|
|
+ writel(FM10K_ITR_MASK_SET, q_vector->itr);
|
|
|
+
|
|
|
+ free_irq(entry->vector, q_vector);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * fm10k_qv_request_irq - initialize interrupts for queue vectors
|
|
|
+ * @interface: board private structure
|
|
|
+ *
|
|
|
+ * Attempts to configure interrupts using the best available
|
|
|
+ * capabilities of the hardware and kernel.
|
|
|
+ **/
|
|
|
+int fm10k_qv_request_irq(struct fm10k_intfc *interface)
|
|
|
+{
|
|
|
+ struct net_device *dev = interface->netdev;
|
|
|
+ struct fm10k_hw *hw = &interface->hw;
|
|
|
+ struct msix_entry *entry;
|
|
|
+ int ri = 0, ti = 0;
|
|
|
+ int vector, err;
|
|
|
+
|
|
|
+ entry = &interface->msix_entries[NON_Q_VECTORS(hw)];
|
|
|
+
|
|
|
+ for (vector = 0; vector < interface->num_q_vectors; vector++) {
|
|
|
+ struct fm10k_q_vector *q_vector = interface->q_vector[vector];
|
|
|
+
|
|
|
+ /* name the vector */
|
|
|
+ if (q_vector->tx.count && q_vector->rx.count) {
|
|
|
+ snprintf(q_vector->name, sizeof(q_vector->name) - 1,
|
|
|
+ "%s-TxRx-%d", dev->name, ri++);
|
|
|
+ ti++;
|
|
|
+ } else if (q_vector->rx.count) {
|
|
|
+ snprintf(q_vector->name, sizeof(q_vector->name) - 1,
|
|
|
+ "%s-rx-%d", dev->name, ri++);
|
|
|
+ } else if (q_vector->tx.count) {
|
|
|
+ snprintf(q_vector->name, sizeof(q_vector->name) - 1,
|
|
|
+ "%s-tx-%d", dev->name, ti++);
|
|
|
+ } else {
|
|
|
+ /* skip this unused q_vector */
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Assign ITR register to q_vector */
|
|
|
+ q_vector->itr = &interface->uc_addr[FM10K_ITR(entry->entry)];
|
|
|
+
|
|
|
+ /* request the IRQ */
|
|
|
+ err = request_irq(entry->vector, &fm10k_msix_clean_rings, 0,
|
|
|
+ q_vector->name, q_vector);
|
|
|
+ if (err) {
|
|
|
+ netif_err(interface, probe, dev,
|
|
|
+ "request_irq failed for MSIX interrupt Error: %d\n",
|
|
|
+ err);
|
|
|
+ goto err_out;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Enable q_vector */
|
|
|
+ writel(FM10K_ITR_ENABLE, q_vector->itr);
|
|
|
+
|
|
|
+ entry++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+err_out:
|
|
|
+ /* wind through the ring freeing all entries and vectors */
|
|
|
+ while (vector) {
|
|
|
+ struct fm10k_q_vector *q_vector;
|
|
|
+
|
|
|
+ entry--;
|
|
|
+ vector--;
|
|
|
+ q_vector = interface->q_vector[vector];
|
|
|
+
|
|
|
+ if (!q_vector->tx.count && !q_vector->rx.count)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ /* disable interrupts */
|
|
|
+
|
|
|
+ writel(FM10K_ITR_MASK_SET, q_vector->itr);
|
|
|
+
|
|
|
+ free_irq(entry->vector, q_vector);
|
|
|
+ }
|
|
|
+
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
void fm10k_up(struct fm10k_intfc *interface)
|
|
|
{
|
|
|
struct fm10k_hw *hw = &interface->hw;
|
|
@@ -100,6 +564,9 @@ void fm10k_up(struct fm10k_intfc *interface)
|
|
|
/* clear down bit to indicate we are ready to go */
|
|
|
clear_bit(__FM10K_DOWN, &interface->state);
|
|
|
|
|
|
+ /* enable polling cleanups */
|
|
|
+ fm10k_napi_enable_all(interface);
|
|
|
+
|
|
|
/* re-establish Rx filters */
|
|
|
fm10k_restore_rx_state(interface);
|
|
|
|
|
@@ -107,6 +574,17 @@ void fm10k_up(struct fm10k_intfc *interface)
|
|
|
netif_tx_start_all_queues(interface->netdev);
|
|
|
}
|
|
|
|
|
|
+static void fm10k_napi_disable_all(struct fm10k_intfc *interface)
|
|
|
+{
|
|
|
+ struct fm10k_q_vector *q_vector;
|
|
|
+ int q_idx;
|
|
|
+
|
|
|
+ for (q_idx = 0; q_idx < interface->num_q_vectors; q_idx++) {
|
|
|
+ q_vector = interface->q_vector[q_idx];
|
|
|
+ napi_disable(&q_vector->napi);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void fm10k_down(struct fm10k_intfc *interface)
|
|
|
{
|
|
|
struct net_device *netdev = interface->netdev;
|
|
@@ -128,6 +606,9 @@ void fm10k_down(struct fm10k_intfc *interface)
|
|
|
/* allow 10ms for device to quiesce */
|
|
|
usleep_range(10000, 20000);
|
|
|
|
|
|
+ /* disable polling routines */
|
|
|
+ fm10k_napi_disable_all(interface);
|
|
|
+
|
|
|
/* Disable DMA engine for Tx/Rx */
|
|
|
hw->mac.ops.stop_hw(hw);
|
|
|
}
|
|
@@ -226,6 +707,10 @@ static int fm10k_sw_init(struct fm10k_intfc *interface,
|
|
|
netdev->hw_features &= ~NETIF_F_GSO_UDP_TUNNEL;
|
|
|
}
|
|
|
|
|
|
+ /* set default interrupt moderation */
|
|
|
+ interface->tx_itr = FM10K_ITR_10K;
|
|
|
+ interface->rx_itr = FM10K_ITR_ADAPTIVE | FM10K_ITR_20K;
|
|
|
+
|
|
|
/* initialize vxlan_port list */
|
|
|
INIT_LIST_HEAD(&interface->vxlan_port);
|
|
|
|
|
@@ -341,6 +826,14 @@ static int fm10k_probe(struct pci_dev *pdev,
|
|
|
if (err)
|
|
|
goto err_sw_init;
|
|
|
|
|
|
+ err = fm10k_init_queueing_scheme(interface);
|
|
|
+ if (err)
|
|
|
+ goto err_sw_init;
|
|
|
+
|
|
|
+ err = fm10k_mbx_request_irq(interface);
|
|
|
+ if (err)
|
|
|
+ goto err_mbx_interrupt;
|
|
|
+
|
|
|
/* final check of hardware state before registering the interface */
|
|
|
err = fm10k_hw_ready(interface);
|
|
|
if (err)
|
|
@@ -377,6 +870,9 @@ static int fm10k_probe(struct pci_dev *pdev,
|
|
|
return 0;
|
|
|
|
|
|
err_register:
|
|
|
+ fm10k_mbx_free_irq(interface);
|
|
|
+err_mbx_interrupt:
|
|
|
+ fm10k_clear_queueing_scheme(interface);
|
|
|
err_sw_init:
|
|
|
iounmap(interface->uc_addr);
|
|
|
err_ioremap:
|
|
@@ -408,6 +904,12 @@ static void fm10k_remove(struct pci_dev *pdev)
|
|
|
if (netdev->reg_state == NETREG_REGISTERED)
|
|
|
unregister_netdev(netdev);
|
|
|
|
|
|
+ /* disable mailbox interrupt */
|
|
|
+ fm10k_mbx_free_irq(interface);
|
|
|
+
|
|
|
+ /* free interrupts */
|
|
|
+ fm10k_clear_queueing_scheme(interface);
|
|
|
+
|
|
|
iounmap(interface->uc_addr);
|
|
|
|
|
|
free_netdev(netdev);
|