diff options
Diffstat (limited to 'drivers/net/myri10ge/myri10ge.c')
-rw-r--r-- | drivers/net/myri10ge/myri10ge.c | 103 |
1 files changed, 79 insertions, 24 deletions
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index d771d1650d60..8524cc40ec57 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -225,6 +225,7 @@ struct myri10ge_priv { struct msix_entry *msix_vectors; #ifdef CONFIG_MYRI10GE_DCA int dca_enabled; + int relaxed_order; #endif u32 link_state; unsigned int rdma_tags_available; @@ -239,6 +240,7 @@ struct myri10ge_priv { int watchdog_resets; int watchdog_pause; int pause; + bool fw_name_allocated; char *fw_name; char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE]; char *product_code_string; @@ -271,6 +273,7 @@ MODULE_FIRMWARE("myri10ge_eth_z8e.dat"); MODULE_FIRMWARE("myri10ge_rss_ethp_z8e.dat"); MODULE_FIRMWARE("myri10ge_rss_eth_z8e.dat"); +/* Careful: must be accessed under kparam_block_sysfs_write */ static char *myri10ge_fw_name = NULL; module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name"); @@ -376,6 +379,14 @@ static inline void put_be32(__be32 val, __be32 __iomem * p) static struct net_device_stats *myri10ge_get_stats(struct net_device *dev); +static void set_fw_name(struct myri10ge_priv *mgp, char *name, bool allocated) +{ + if (mgp->fw_name_allocated) + kfree(mgp->fw_name); + mgp->fw_name = name; + mgp->fw_name_allocated = allocated; +} + static int myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd, struct myri10ge_cmd *data, int atomic) @@ -747,7 +758,7 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp, int adopt) dev_warn(&mgp->pdev->dev, "via hotplug\n"); } - mgp->fw_name = "adopted"; + set_fw_name(mgp, "adopted", false); mgp->tx_boundary = 2048; myri10ge_dummy_rdma(mgp, 1); status = myri10ge_get_firmware_capabilities(mgp); @@ -980,7 +991,7 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) * RX queues, so if we get an error, first retry using a * single TX queue before giving up */ if (status != 0 && mgp->dev->real_num_tx_queues > 1) { - mgp->dev->real_num_tx_queues = 1; + netif_set_real_num_tx_queues(mgp->dev, 1); cmd.data0 = mgp->num_slices; cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE; status = myri10ge_send_cmd(mgp, @@ -1064,10 +1075,28 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) } #ifdef CONFIG_MYRI10GE_DCA +static int myri10ge_toggle_relaxed(struct pci_dev *pdev, int on) +{ + int ret, cap, err; + u16 ctl; + + cap = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (!cap) + return 0; + + err = pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &ctl); + ret = (ctl & PCI_EXP_DEVCTL_RELAX_EN) >> 4; + if (ret != on) { + ctl &= ~PCI_EXP_DEVCTL_RELAX_EN; + ctl |= (on << 4); + pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, ctl); + } + return ret; +} + static void myri10ge_write_dca(struct myri10ge_slice_state *ss, int cpu, int tag) { - ss->cpu = cpu; ss->cached_dca_tag = tag; put_be32(htonl(tag), ss->dca_tag); } @@ -1078,9 +1107,10 @@ static inline void myri10ge_update_dca(struct myri10ge_slice_state *ss) int tag; if (cpu != ss->cpu) { - tag = dca_get_tag(cpu); + tag = dca3_get_tag(&ss->mgp->pdev->dev, cpu); if (ss->cached_dca_tag != tag) myri10ge_write_dca(ss, cpu, tag); + ss->cpu = cpu; } put_cpu(); } @@ -1103,9 +1133,13 @@ static void myri10ge_setup_dca(struct myri10ge_priv *mgp) "dca_add_requester() failed, err=%d\n", err); return; } + mgp->relaxed_order = myri10ge_toggle_relaxed(pdev, 0); mgp->dca_enabled = 1; - for (i = 0; i < mgp->num_slices; i++) - myri10ge_write_dca(&mgp->ss[i], -1, 0); + for (i = 0; i < mgp->num_slices; i++) { + mgp->ss[i].cpu = -1; + mgp->ss[i].cached_dca_tag = -1; + myri10ge_update_dca(&mgp->ss[i]); + } } static void myri10ge_teardown_dca(struct myri10ge_priv *mgp) @@ -1116,6 +1150,8 @@ static void myri10ge_teardown_dca(struct myri10ge_priv *mgp) if (!mgp->dca_enabled) return; mgp->dca_enabled = 0; + if (mgp->relaxed_order) + myri10ge_toggle_relaxed(pdev, 1); err = dca_remove_requester(&pdev->dev); } @@ -1545,12 +1581,12 @@ static irqreturn_t myri10ge_intr(int irq, void *arg) * valid since MSI-X irqs are not shared */ if ((mgp->dev->real_num_tx_queues == 1) && (ss != mgp->ss)) { napi_schedule(&ss->napi); - return (IRQ_HANDLED); + return IRQ_HANDLED; } /* make sure it is our IRQ, and that the DMA has finished */ if (unlikely(!stats->valid)) - return (IRQ_NONE); + return IRQ_NONE; /* low bit indicates receives are present, so schedule * napi poll handler */ @@ -1589,7 +1625,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg) myri10ge_check_statblock(mgp); put_be32(htonl(3), ss->irq_claim + 1); - return (IRQ_HANDLED); + return IRQ_HANDLED; } static int @@ -3233,7 +3269,7 @@ static void myri10ge_firmware_probe(struct myri10ge_priv *mgp) * load the optimized firmware (which assumes aligned PCIe * completions) in order to see if it works on this host. */ - mgp->fw_name = myri10ge_fw_aligned; + set_fw_name(mgp, myri10ge_fw_aligned, false); status = myri10ge_load_firmware(mgp, 1); if (status != 0) { goto abort; @@ -3261,7 +3297,7 @@ static void myri10ge_firmware_probe(struct myri10ge_priv *mgp) abort: /* fall back to using the unaligned firmware */ mgp->tx_boundary = 2048; - mgp->fw_name = myri10ge_fw_unaligned; + set_fw_name(mgp, myri10ge_fw_unaligned, false); } @@ -3284,7 +3320,7 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp) dev_info(&mgp->pdev->dev, "PCIE x%d Link\n", link_width); mgp->tx_boundary = 4096; - mgp->fw_name = myri10ge_fw_aligned; + set_fw_name(mgp, myri10ge_fw_aligned, false); } else { myri10ge_firmware_probe(mgp); } @@ -3293,22 +3329,29 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp) dev_info(&mgp->pdev->dev, "Assuming aligned completions (forced)\n"); mgp->tx_boundary = 4096; - mgp->fw_name = myri10ge_fw_aligned; + set_fw_name(mgp, myri10ge_fw_aligned, false); } else { dev_info(&mgp->pdev->dev, "Assuming unaligned completions (forced)\n"); mgp->tx_boundary = 2048; - mgp->fw_name = myri10ge_fw_unaligned; + set_fw_name(mgp, myri10ge_fw_unaligned, false); } } + + kparam_block_sysfs_write(myri10ge_fw_name); if (myri10ge_fw_name != NULL) { - overridden = 1; - mgp->fw_name = myri10ge_fw_name; + char *fw_name = kstrdup(myri10ge_fw_name, GFP_KERNEL); + if (fw_name) { + overridden = 1; + set_fw_name(mgp, fw_name, true); + } } + kparam_unblock_sysfs_write(myri10ge_fw_name); + if (mgp->board_number < MYRI10GE_MAX_BOARDS && myri10ge_fw_names[mgp->board_number] != NULL && strlen(myri10ge_fw_names[mgp->board_number])) { - mgp->fw_name = myri10ge_fw_names[mgp->board_number]; + set_fw_name(mgp, myri10ge_fw_names[mgp->board_number], false); overridden = 1; } if (overridden) @@ -3660,6 +3703,7 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp) struct myri10ge_cmd cmd; struct pci_dev *pdev = mgp->pdev; char *old_fw; + bool old_allocated; int i, status, ncpus, msix_cap; mgp->num_slices = 1; @@ -3672,17 +3716,23 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp) /* try to load the slice aware rss firmware */ old_fw = mgp->fw_name; + old_allocated = mgp->fw_name_allocated; + /* don't free old_fw if we override it. */ + mgp->fw_name_allocated = false; + if (myri10ge_fw_name != NULL) { dev_info(&mgp->pdev->dev, "overriding rss firmware to %s\n", myri10ge_fw_name); - mgp->fw_name = myri10ge_fw_name; + set_fw_name(mgp, myri10ge_fw_name, false); } else if (old_fw == myri10ge_fw_aligned) - mgp->fw_name = myri10ge_fw_rss_aligned; + set_fw_name(mgp, myri10ge_fw_rss_aligned, false); else - mgp->fw_name = myri10ge_fw_rss_unaligned; + set_fw_name(mgp, myri10ge_fw_rss_unaligned, false); status = myri10ge_load_firmware(mgp, 0); if (status != 0) { dev_info(&pdev->dev, "Rss firmware not found\n"); + if (old_allocated) + kfree(old_fw); return; } @@ -3729,8 +3779,8 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp) * slices. We give up on MSI-X if we can only get a single * vector. */ - mgp->msix_vectors = kzalloc(mgp->num_slices * - sizeof(*mgp->msix_vectors), GFP_KERNEL); + mgp->msix_vectors = kcalloc(mgp->num_slices, sizeof(*mgp->msix_vectors), + GFP_KERNEL); if (mgp->msix_vectors == NULL) goto disable_msix; for (i = 0; i < mgp->num_slices; i++) { @@ -3747,6 +3797,8 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp) mgp->num_slices); if (status == 0) { pci_disable_msix(pdev); + if (old_allocated) + kfree(old_fw); return; } if (status > 0) @@ -3763,7 +3815,7 @@ disable_msix: abort_with_fw: mgp->num_slices = 1; - mgp->fw_name = old_fw; + set_fw_name(mgp, old_fw, old_allocated); myri10ge_load_firmware(mgp, 0); } @@ -3897,7 +3949,8 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) dev_err(&pdev->dev, "failed to alloc slice state\n"); goto abort_with_firmware; } - netdev->real_num_tx_queues = mgp->num_slices; + netif_set_real_num_tx_queues(netdev, mgp->num_slices); + netif_set_real_num_rx_queues(netdev, mgp->num_slices); status = myri10ge_reset(mgp); if (status != 0) { dev_err(&pdev->dev, "failed reset\n"); @@ -3993,6 +4046,7 @@ abort_with_enabled: pci_disable_device(pdev); abort_with_netdev: + set_fw_name(mgp, NULL, false); free_netdev(netdev); return status; } @@ -4037,6 +4091,7 @@ static void myri10ge_remove(struct pci_dev *pdev) dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd), mgp->cmd, mgp->cmd_bus); + set_fw_name(mgp, NULL, false); free_netdev(netdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); |