|
@@ -1928,6 +1928,76 @@ myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+#if 0
|
|
|
+static int myri10ge_get_txrx(struct myri10ge_priv *mgp, int slice)
|
|
|
+{
|
|
|
+ struct myri10ge_cmd cmd;
|
|
|
+ struct myri10ge_slice_state *ss;
|
|
|
+ int status;
|
|
|
+
|
|
|
+ ss = &mgp->ss[slice];
|
|
|
+ cmd.data0 = 0; /* single slice for now */
|
|
|
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, &cmd, 0);
|
|
|
+ ss->tx.lanai = (struct mcp_kreq_ether_send __iomem *)
|
|
|
+ (mgp->sram + cmd.data0);
|
|
|
+
|
|
|
+ cmd.data0 = slice;
|
|
|
+ status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET,
|
|
|
+ &cmd, 0);
|
|
|
+ ss->rx_small.lanai = (struct mcp_kreq_ether_recv __iomem *)
|
|
|
+ (mgp->sram + cmd.data0);
|
|
|
+
|
|
|
+ cmd.data0 = slice;
|
|
|
+ status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd, 0);
|
|
|
+ ss->rx_big.lanai = (struct mcp_kreq_ether_recv __iomem *)
|
|
|
+ (mgp->sram + cmd.data0);
|
|
|
+
|
|
|
+ if (myri10ge_wcfifo && mgp->wc_enabled) {
|
|
|
+ ss->tx.wc_fifo = (u8 __iomem *)
|
|
|
+ mgp->sram + MXGEFW_ETH_SEND_4 + 64 * slice;
|
|
|
+ ss->rx_small.wc_fifo = (u8 __iomem *)
|
|
|
+ mgp->sram + MXGEFW_ETH_RECV_SMALL + 64 * slice;
|
|
|
+ ss->rx_big.wc_fifo = (u8 __iomem *)
|
|
|
+ mgp->sram + MXGEFW_ETH_RECV_BIG + 64 * slice;
|
|
|
+ } else {
|
|
|
+ ss->tx.wc_fifo = NULL;
|
|
|
+ ss->rx_small.wc_fifo = NULL;
|
|
|
+ ss->rx_big.wc_fifo = NULL;
|
|
|
+ }
|
|
|
+ return status;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+static int myri10ge_set_stats(struct myri10ge_priv *mgp, int slice)
|
|
|
+{
|
|
|
+ struct myri10ge_cmd cmd;
|
|
|
+ struct myri10ge_slice_state *ss;
|
|
|
+ int status;
|
|
|
+
|
|
|
+ ss = &mgp->ss[slice];
|
|
|
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(ss->fw_stats_bus);
|
|
|
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(ss->fw_stats_bus);
|
|
|
+ cmd.data2 = sizeof(struct mcp_irq_data);
|
|
|
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0);
|
|
|
+ if (status == -ENOSYS) {
|
|
|
+ dma_addr_t bus = ss->fw_stats_bus;
|
|
|
+ if (slice != 0)
|
|
|
+ return -EINVAL;
|
|
|
+ bus += offsetof(struct mcp_irq_data, send_done_count);
|
|
|
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus);
|
|
|
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus);
|
|
|
+ status = myri10ge_send_cmd(mgp,
|
|
|
+ MXGEFW_CMD_SET_STATS_DMA_OBSOLETE,
|
|
|
+ &cmd, 0);
|
|
|
+ /* Firmware cannot support multicast without STATS_DMA_V2 */
|
|
|
+ mgp->fw_multicast_support = 0;
|
|
|
+ } else {
|
|
|
+ mgp->fw_multicast_support = 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
static int myri10ge_open(struct net_device *dev)
|
|
|
{
|
|
|
struct myri10ge_priv *mgp = netdev_priv(dev);
|
|
@@ -3106,6 +3176,192 @@ static void myri10ge_watchdog_timer(unsigned long arg)
|
|
|
mgp->watchdog_pause = rx_pause_cnt;
|
|
|
}
|
|
|
|
|
|
+#if 0
|
|
|
+static void myri10ge_free_slices(struct myri10ge_priv *mgp)
|
|
|
+{
|
|
|
+ struct myri10ge_slice_state *ss;
|
|
|
+ struct pci_dev *pdev = mgp->pdev;
|
|
|
+ size_t bytes;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ if (mgp->ss == NULL)
|
|
|
+ return;
|
|
|
+
|
|
|
+ for (i = 0; i < mgp->num_slices; i++) {
|
|
|
+ ss = &mgp->ss[i];
|
|
|
+ if (ss->rx_done.entry != NULL) {
|
|
|
+ bytes = mgp->max_intr_slots *
|
|
|
+ sizeof(*ss->rx_done.entry);
|
|
|
+ dma_free_coherent(&pdev->dev, bytes,
|
|
|
+ ss->rx_done.entry, ss->rx_done.bus);
|
|
|
+ ss->rx_done.entry = NULL;
|
|
|
+ }
|
|
|
+ if (ss->fw_stats != NULL) {
|
|
|
+ bytes = sizeof(*ss->fw_stats);
|
|
|
+ dma_free_coherent(&pdev->dev, bytes,
|
|
|
+ ss->fw_stats, ss->fw_stats_bus);
|
|
|
+ ss->fw_stats = NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ kfree(mgp->ss);
|
|
|
+ mgp->ss = NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static int myri10ge_alloc_slices(struct myri10ge_priv *mgp)
|
|
|
+{
|
|
|
+ struct myri10ge_slice_state *ss;
|
|
|
+ struct pci_dev *pdev = mgp->pdev;
|
|
|
+ size_t bytes;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ bytes = sizeof(*mgp->ss) * mgp->num_slices;
|
|
|
+ mgp->ss = kzalloc(bytes, GFP_KERNEL);
|
|
|
+ if (mgp->ss == NULL) {
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < mgp->num_slices; i++) {
|
|
|
+ ss = &mgp->ss[i];
|
|
|
+ bytes = mgp->max_intr_slots * sizeof(*ss->rx_done.entry);
|
|
|
+ ss->rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes,
|
|
|
+ &ss->rx_done.bus,
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (ss->rx_done.entry == NULL)
|
|
|
+ goto abort;
|
|
|
+ memset(ss->rx_done.entry, 0, bytes);
|
|
|
+ bytes = sizeof(*ss->fw_stats);
|
|
|
+ ss->fw_stats = dma_alloc_coherent(&pdev->dev, bytes,
|
|
|
+ &ss->fw_stats_bus,
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (ss->fw_stats == NULL)
|
|
|
+ goto abort;
|
|
|
+ ss->mgp = mgp;
|
|
|
+ ss->dev = mgp->dev;
|
|
|
+ netif_napi_add(ss->dev, &ss->napi, myri10ge_poll,
|
|
|
+ myri10ge_napi_weight);
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+abort:
|
|
|
+ myri10ge_free_slices(mgp);
|
|
|
+ return -ENOMEM;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * This function determines the number of slices supported.
|
|
|
+ * The number slices is the minumum of the number of CPUS,
|
|
|
+ * the number of MSI-X irqs supported, the number of slices
|
|
|
+ * supported by the firmware
|
|
|
+ */
|
|
|
+static void myri10ge_probe_slices(struct myri10ge_priv *mgp)
|
|
|
+{
|
|
|
+ struct myri10ge_cmd cmd;
|
|
|
+ struct pci_dev *pdev = mgp->pdev;
|
|
|
+ char *old_fw;
|
|
|
+ int i, status, ncpus, msix_cap;
|
|
|
+
|
|
|
+ mgp->num_slices = 1;
|
|
|
+ msix_cap = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
|
|
|
+ ncpus = num_online_cpus();
|
|
|
+
|
|
|
+ if (myri10ge_max_slices == 1 || msix_cap == 0 ||
|
|
|
+ (myri10ge_max_slices == -1 && ncpus < 2))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* try to load the slice aware rss firmware */
|
|
|
+ old_fw = mgp->fw_name;
|
|
|
+ if (old_fw == myri10ge_fw_aligned)
|
|
|
+ mgp->fw_name = myri10ge_fw_rss_aligned;
|
|
|
+ else
|
|
|
+ mgp->fw_name = myri10ge_fw_rss_unaligned;
|
|
|
+ status = myri10ge_load_firmware(mgp, 0);
|
|
|
+ if (status != 0) {
|
|
|
+ dev_info(&pdev->dev, "Rss firmware not found\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* hit the board with a reset to ensure it is alive */
|
|
|
+ memset(&cmd, 0, sizeof(cmd));
|
|
|
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_RESET, &cmd, 0);
|
|
|
+ if (status != 0) {
|
|
|
+ dev_err(&mgp->pdev->dev, "failed reset\n");
|
|
|
+ goto abort_with_fw;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ mgp->max_intr_slots = cmd.data0 / sizeof(struct mcp_slot);
|
|
|
+
|
|
|
+ /* tell it the size of the interrupt queues */
|
|
|
+ cmd.data0 = mgp->max_intr_slots * sizeof(struct mcp_slot);
|
|
|
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0);
|
|
|
+ if (status != 0) {
|
|
|
+ dev_err(&mgp->pdev->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n");
|
|
|
+ goto abort_with_fw;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* ask the maximum number of slices it supports */
|
|
|
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd, 0);
|
|
|
+ if (status != 0)
|
|
|
+ goto abort_with_fw;
|
|
|
+ else
|
|
|
+ mgp->num_slices = cmd.data0;
|
|
|
+
|
|
|
+ /* Only allow multiple slices if MSI-X is usable */
|
|
|
+ if (!myri10ge_msi) {
|
|
|
+ goto abort_with_fw;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* if the admin did not specify a limit to how many
|
|
|
+ * slices we should use, cap it automatically to the
|
|
|
+ * number of CPUs currently online */
|
|
|
+ if (myri10ge_max_slices == -1)
|
|
|
+ myri10ge_max_slices = ncpus;
|
|
|
+
|
|
|
+ if (mgp->num_slices > myri10ge_max_slices)
|
|
|
+ mgp->num_slices = myri10ge_max_slices;
|
|
|
+
|
|
|
+ /* Now try to allocate as many MSI-X vectors as we have
|
|
|
+ * 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);
|
|
|
+ if (mgp->msix_vectors == NULL)
|
|
|
+ goto disable_msix;
|
|
|
+ for (i = 0; i < mgp->num_slices; i++) {
|
|
|
+ mgp->msix_vectors[i].entry = i;
|
|
|
+ }
|
|
|
+
|
|
|
+ while (mgp->num_slices > 1) {
|
|
|
+ /* make sure it is a power of two */
|
|
|
+ while (!is_power_of_2(mgp->num_slices))
|
|
|
+ mgp->num_slices--;
|
|
|
+ if (mgp->num_slices == 1)
|
|
|
+ goto disable_msix;
|
|
|
+ status = pci_enable_msix(pdev, mgp->msix_vectors,
|
|
|
+ mgp->num_slices);
|
|
|
+ if (status == 0) {
|
|
|
+ pci_disable_msix(pdev);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (status > 0)
|
|
|
+ mgp->num_slices = status;
|
|
|
+ else
|
|
|
+ goto disable_msix;
|
|
|
+ }
|
|
|
+
|
|
|
+disable_msix:
|
|
|
+ if (mgp->msix_vectors != NULL) {
|
|
|
+ kfree(mgp->msix_vectors);
|
|
|
+ mgp->msix_vectors = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+abort_with_fw:
|
|
|
+ mgp->num_slices = 1;
|
|
|
+ mgp->fw_name = old_fw;
|
|
|
+ myri10ge_load_firmware(mgp, 0);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
|
{
|
|
|
struct net_device *netdev;
|