* [PATCH 8/9] Resending NetXen 1G/10G NIC driver patch
@ 2006-05-25 10:57 Linsys Contractor Amit S. Kale
2006-05-25 16:44 ` Roland Dreier
2006-05-25 17:03 ` Stephen Hemminger
0 siblings, 2 replies; 5+ messages in thread
From: Linsys Contractor Amit S. Kale @ 2006-05-25 10:57 UTC (permalink / raw)
To: netdev; +Cc: sanjeev, unmproj
diff -Naru linux-2.6.16.18.orig/drivers/net/netxen/netxen_nic_main.c linux-2.6.16.18/drivers/net/netxen/netxen_nic_main.c
--- linux-2.6.16.18.orig/drivers/net/netxen/netxen_nic_main.c 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.16.18/drivers/net/netxen/netxen_nic_main.c 2006-05-25 02:43:22.000000000 -0700
@@ -0,0 +1,1209 @@
+/*
+ * Copyright (C) 2003 - 2006 NetXen, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.
+ *
+ * Contact Information:
+ * info@netxen.com
+ * NetXen,
+ * 3965 Freedom Circle, Fourth floor,
+ * Santa Clara, CA 95054
+ *
+ *
+ * Main source file for NetXen NIC Driver on Linux
+ *
+ */
+
+#include "netxen_nic.h"
+
+#define DEFINE_GLOBAL_RECV_CRB
+#include "netxen_nic_phan_reg.h"
+#include "netxen_nic_ioctl.h"
+
+MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(NETXEN_NIC_LINUX_VERSIONID);
+
+char netxen_nic_driver_name[] = "netxen";
+char netxen_nic_driver_string[] = "NetXen Network Driver version "
+ NETXEN_NIC_LINUX_VERSIONID
+ "-" NETXEN_NIC_BUILD_NO " generated " NETXEN_NIC_TIMESTAMP;
+
+#define NETXEN_NETDEV_WEIGHT 120
+#define NETXEN_ADAPTER_UP_MAGIC 777
+
+static int netxen_nic_probe_err = 0;
+
+/* Local functions to NetXen NIC driver */
+static int __devinit netxen_nic_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+static void __devexit netxen_nic_remove(struct pci_dev *pdev);
+static int netxen_nic_open(struct net_device *netdev);
+static int netxen_nic_close(struct net_device *netdev);
+static int netxen_nic_xmit_frame(struct sk_buff *, struct net_device *);
+static void netxen_tx_timeout(struct net_device *netdev);
+static void netxen_tx_timeout_task(struct net_device *netdev);
+static void netxen_watchdog(unsigned long);
+static int netxen_handle_int(struct netxen_adapter *, struct net_device *);
+static int netxen_nic_ioctl(struct net_device *netdev,
+ struct ifreq *ifr, int cmd);
+static int netxen_nic_poll(struct net_device *dev, int *budget);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void netxen_nic_poll_controller(struct net_device *netdev);
+#endif
+static irqreturn_t netxen_intr(int irq, void *data, struct pt_regs *regs);
+
+/* PCI Device ID Table */
+static struct pci_device_id netxen_pci_tbl[] __devinitdata = {
+ NETXEN_PCI_ID(PCI_DEVICE_ID_NX_QG),
+ NETXEN_PCI_ID(PCI_DEVICE_ID_NX_XG),
+ NETXEN_PCI_ID(PCI_DEVICE_ID_NX_CX4),
+ NETXEN_PCI_ID(PCI_DEVICE_ID_NX_IMEZ),
+ NETXEN_PCI_ID(PCI_DEVICE_ID_NX_HMEZ),
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, netxen_pci_tbl);
+
+struct netxen_adapter *adapterlist[MAX_NUM_CARDS];
+
+/*
+ * netxen_nic_probe()
+ *
+ * Linux system will invoke this after identifying the vendor ID and device Id
+ * in the pci_tbl where this module will search for NetXen vendor and device ID for
+ * quad port adapter.
+ *
+ * Even though there are 4 seperate devices (functions) on the quad port NIC, but
+ * the probe will be invoked for the first device (function) only. This will
+ * initialize the adapter, and setup the global parameters along with the port's
+ * specific structure.
+ */
+static int __devinit
+netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct net_device *netdev = NULL;
+ struct netxen_adapter *adapter = NULL;
+ struct netxen_port *port = NULL;
+ u8 *mem_ptr = NULL;
+ unsigned long mem_base, mem_len;
+ int pci_using_dac, i, err;
+ int boardno = 0;
+ int ring;
+ struct netdev_list *netlist = NULL;
+ struct netxen_recv_context *recv_ctx = NULL;
+ struct netxen_rcv_desc_ctx *rcv_desc = NULL;
+ struct netxen_cmd_buffer *cmd_buf_arr = NULL;
+ static int netxen_cards_found = 0;
+ u64 mac_addr[FLASH_NUM_PORTS + 1];
+ int valid_mac;
+
+ if ((err = pci_enable_device(pdev))) {
+ netxen_nic_probe_err = err;
+ return err;
+ }
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+ err = -ENODEV;
+ goto err_out_disable_pdev;
+ }
+
+ if ((err = pci_request_regions(pdev, netxen_nic_driver_name)))
+ goto err_out_disable_pdev;
+
+ pci_set_master(pdev);
+ if ((pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) &&
+ (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) == 0))
+ pci_using_dac = 1;
+ else {
+ if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) ||
+ (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)))
+ goto err_out_free_res;
+
+ pci_using_dac = 0;
+ }
+
+ /* remap phys address */
+ mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
+ mem_len = pci_resource_len(pdev, 0);
+
+ /* 128 Meg of memory */
+ mem_ptr = ioremap(mem_base, NETXEN_PCI_MAPSIZE_BYTES);
+ if (mem_ptr == 0UL) {
+ printk(KERN_ERR "%s: Cannot ioremap adapter memory aborting."
+ ":%p\n", netxen_nic_driver_name, mem_ptr);
+ err = -EIO;
+ goto err_out_free_res;
+ }
+
+/*
+ * Allocate a adapter structure which will manage all the initialization
+ * as well as the common resources for all ports...
+ * all the ports will have pointer to this adapter as well as Adapter
+ * will have pointers of all the ports structures.
+ */
+
+ /* One adapter structure for all 4 ports.... */
+ adapter = kzalloc(sizeof(struct netxen_adapter), GFP_KERNEL);
+ if (adapter == NULL) {
+ printk(KERN_ERR "%s: Could not allocate adapter memory:%d\n",
+ netxen_nic_driver_name,
+ (int)sizeof(struct netxen_adapter));
+ err = -ENOMEM;
+ goto err_out_iounmap;
+ }
+
+ adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS;
+ adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS;
+ adapter->max_jumbo_rx_desc_count = MAX_JUMBO_RCV_DESCRIPTORS;
+
+ cmd_buf_arr = (struct netxen_cmd_buffer *)vmalloc(TX_RINGSIZE);
+ if (cmd_buf_arr == NULL) {
+ err = -ENOMEM;
+ goto err_out_free_adapter;
+ }
+ memset(cmd_buf_arr, 0, TX_RINGSIZE);
+
+ for (i = 0; i < MAX_RCV_CTX; ++i) {
+ recv_ctx = &adapter->recv_ctx[i];
+ for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) {
+ rcv_desc = &recv_ctx->rcv_desc[ring];
+ switch (RCV_DESC_TYPE(ring)) {
+ case RCV_DESC_NORMAL:
+ rcv_desc->max_rx_desc_count =
+ adapter->max_rx_desc_count;
+ rcv_desc->flags = RCV_DESC_NORMAL;
+ rcv_desc->dma_size = RX_DMA_MAP_LEN;
+ rcv_desc->skb_size = MAX_RX_BUFFER_LENGTH;
+ break;
+
+ case RCV_DESC_JUMBO:
+ rcv_desc->max_rx_desc_count =
+ adapter->max_jumbo_rx_desc_count;
+ rcv_desc->flags = RCV_DESC_JUMBO;
+ rcv_desc->dma_size = RX_JUMBO_DMA_MAP_LEN;
+ rcv_desc->skb_size = MAX_RX_JUMBO_BUFFER_LENGTH;
+ break;
+
+ default:
+ printk("%s: netxen_nic_probe: bad receive "
+ "descriptor type %d\n",
+ netxen_nic_driver_name,
+ RCV_DESC_TYPE(ring));
+ break;
+ }
+ rcv_desc->rx_buf_arr = (struct netxen_rx_buffer *)
+ pci_alloc_consistent(pdev,
+ RCV_BUFFSIZE,
+ &rcv_desc->rx_buf_phys);
+
+ if (rcv_desc->rx_buf_arr == NULL) {
+ err = -ENOMEM;
+ goto err_out_free_rx_buffer;
+ }
+ memset(rcv_desc->rx_buf_arr, 0, RCV_BUFFSIZE);
+ }
+
+ }
+
+ adapter->cmd_buf_arr = cmd_buf_arr;
+ adapter->ahw.pci_base = (unsigned long)mem_ptr;
+ adapter->ahw.pci_len = mem_len;
+ adapter->ahw.crb_base = adapter->ahw.pci_base + NETXEN_PCI_CRBSPACE;
+ rwlock_init(&adapter->adapter_lock);
+ spin_lock_init(&adapter->tx_lock);
+ spin_lock_init(&adapter->lock);
+ initialize_adapter_sw(adapter); /* initialize the buffers in adapter */
+ /*
+ * Set the CRB window to invalid. If any register in window 0 is
+ * accessed it should set the window to 0 and then reset it to 1.
+ */
+ adapter->curr_window = 255;
+ /*
+ * Adapter in our case is quad port so initialize it beofore
+ * initializing the ports
+ */
+ initialize_adapter_hw(adapter); /* initialize the adapter */
+ adapter->port = kcalloc(adapter->ahw.max_ports,
+ sizeof(struct netxen_adapter), GFP_KERNEL);
+ if (adapter->port == NULL) {
+ err = -ENOMEM;
+ goto err_out_free_rx_buffer;
+ }
+ init_timer(&adapter->watchdog_timer);
+ adapter->ahw.xg_linkup = 0;
+ adapter->watchdog_timer.function = &netxen_watchdog;
+ adapter->watchdog_timer.data = (unsigned long)adapter;
+ INIT_WORK(&adapter->watchdog_task,
+ (void (*)(void *))netxen_watchdog_task, adapter);
+ adapter->ahw.vendor_id = pdev->vendor;
+ adapter->ahw.device_id = pdev->device;
+ adapter->ahw.pdev = pdev;
+ adapter->proc_cmd_buf_counter = 0;
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &adapter->ahw.revision_id);
+ pci_read_config_word(pdev, PCI_COMMAND, &adapter->ahw.pci_cmd_word);
+
+#if defined(CONFIG_PCI_MSI)
+ adapter->flags |= NETXEN_NIC_MSI_ENABLED;
+ if (pci_enable_msi(pdev)) {
+ adapter->flags &= ~NETXEN_NIC_MSI_ENABLED;
+ printk(KERN_WARNING "%s: unable to allocate MSI interrupt"
+ " error\n", netxen_nic_driver_name);
+ }
+#endif
+
+ if (is_flash_supported(adapter) == 0 &&
+ get_flash_mac_addr(adapter, mac_addr) == 0)
+ valid_mac = 1;
+ else
+ valid_mac = 0;
+
+ /* initialize the all the ports */
+
+ for (i = 0; i < adapter->ahw.max_ports; i++) {
+ netlist = kzalloc(sizeof(struct netdev_list), GFP_KERNEL);
+ if (netlist == NULL)
+ goto err_out_free_dev;
+
+ netlist->netdev = alloc_etherdev(sizeof(struct netxen_port));
+ if (!netlist->netdev) {
+ printk(KERN_ERR "%s: could not allocate netdev for port"
+ " %d\n", netxen_nic_driver_name, i + 1);
+ kfree(netlist);
+ goto err_out_free_dev;
+ }
+ netdev = netlist->netdev;
+
+ SET_MODULE_OWNER(netdev);
+
+ port = netdev_priv(netdev);
+ port->netdev = netdev;
+ port->pdev = pdev;
+ port->hw.port = port;
+ port->adapter = adapter;
+ port->portnum = i; /* Gigabit port number starting from 0-3 */
+ port->flags &= ~NETXEN_NETDEV_STATUS;
+
+ netdev->open = netxen_nic_open;
+ netdev->stop = netxen_nic_close;
+ netdev->hard_start_xmit = netxen_nic_xmit_frame;
+ netdev->get_stats = netxen_nic_get_stats;
+ netdev->set_multicast_list = netxen_nic_set_multi;
+ netdev->set_mac_address = netxen_nic_set_mac;
+ netdev->change_mtu = netxen_nic_change_mtu;
+ netdev->do_ioctl = netxen_nic_ioctl;
+ netdev->tx_timeout = netxen_tx_timeout;
+
+ SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
+
+ netdev->irq = pdev->irq;
+ netdev->poll = netxen_nic_poll;
+ netdev->weight = NETXEN_NETDEV_WEIGHT;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ netdev->poll_controller = netxen_nic_poll_controller;
+#endif
+ /* ScatterGather support */
+ netdev->features = NETIF_F_SG;
+ netdev->features |= NETIF_F_IP_CSUM;
+ netdev->features |= NETIF_F_TSO;
+
+ if (pci_using_dac)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+ boardno = netxen_nic_get_board_num(adapter);
+ if (valid_mac) {
+ unsigned char *p = (unsigned char *)&mac_addr[i];
+ port->hw.mac_addr[0] = *(p + 5);
+ port->hw.mac_addr[1] = *(p + 4);
+ port->hw.mac_addr[2] = *(p + 3);
+ port->hw.mac_addr[3] = *(p + 2);
+ port->hw.mac_addr[4] = *(p + 1);
+ port->hw.mac_addr[5] = *(p + 0);
+
+ if (!is_valid_ether_addr(port->hw.mac_addr)) {
+ printk(KERN_ERR"%s: Bad MAC address"
+ "%02x:%02x:%02x:%02x:%02x:%02x.\n",
+ netxen_nic_driver_name,
+ port->hw.mac_addr[0],
+ port->hw.mac_addr[1],
+ port->hw.mac_addr[2],
+ port->hw.mac_addr[3],
+ port->hw.mac_addr[4],
+ port->hw.mac_addr[5]);
+ } else {
+ memcpy(netdev->dev_addr, port->hw.mac_addr,
+ netdev->addr_len);
+ netxen_nic_macaddr_set(port, port->hw.mac_addr);
+ }
+ }
+ INIT_WORK(adapter->tx_timeout_task + i,
+ (void (*)(void *))netxen_tx_timeout_task, netdev);
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ if ((err = register_netdev(netdev))) {
+ printk(KERN_ERR "%s: register_netdev failed port #%d"
+ " aborting\n", netxen_nic_driver_name, i + 1);
+ break;
+ }
+ adapter->active_ports = 0;
+ adapter->port_count++; /* number of ports allocated */
+ adapter->port[i] = port;
+ netlist->next = pci_get_drvdata(pdev);
+ pci_set_drvdata(pdev, netlist);
+ }
+
+ /*
+ * check how many ports were configured. If due to some errors,
+ * the port count == NULL, then free up the adapter structure,
+ * do iounmap() else add the adapter to the global adapter list
+ */
+
+ if (!adapter->port_count) {
+ /* unable to configure any port */
+ err = -EIO;
+ goto err_out_free_dev;
+ }
+
+ adapter->netlist = netlist;
+
+ /*
+ * Initialize all the CRB registers here.
+ */
+ /* Window = 1 */
+ read_lock(&adapter->adapter_lock);
+ writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_PRODUCER_OFFSET));
+ writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_CONSUMER_OFFSET));
+ writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO));
+ read_unlock(&adapter->adapter_lock);
+
+ phantom_init(adapter);
+ /*
+ * delay a while to ensure that the Pegs are up & running.
+ * Otherwise, we might see some flaky behaviour.
+ */
+ mdelay(1000);
+
+ switch (adapter->ahw.board_type) {
+ case NETXEN_BRDTYPE_P2_SB35_4G:
+ printk("%s: QUAD GbE board initialized\n",
+ netxen_nic_driver_name);
+ break;
+
+ case NETXEN_BRDTYPE_P2_SB31_10G:
+ case NETXEN_BRDTYPE_P2_SB31_10G_CX4:
+ case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ:
+ case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ:
+ printk("%s: XGbE board initialized\n", netxen_nic_driver_name);
+ break;
+ }
+
+ adapter->driver_mismatch = 0;
+
+ adapterlist[netxen_cards_found++] = adapter;
+ adapter->number = netxen_cards_found;
+ netxen_nic_probe_err = 0;
+ return 0;
+
+ err_out_free_dev:
+ for (netlist = pci_get_drvdata(pdev); netlist != NULL;) {
+ struct netdev_list *prev;
+ unregister_netdev(netlist->netdev);
+ free_netdev(netlist->netdev);
+ prev = netlist;
+ netlist = netlist->next;
+ kfree(prev);
+ }
+ kfree(netlist);
+ pci_set_drvdata(pdev, NULL);
+
+ err_out_free_rx_buffer:
+ for (i = 0; i < MAX_RCV_CTX; ++i) {
+ recv_ctx = &adapter->recv_ctx[i];
+ for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) {
+ rcv_desc = &recv_ctx->rcv_desc[ring];
+ if (rcv_desc->rx_buf_arr != NULL) {
+ pci_free_consistent(pdev, RCV_BUFFSIZE,
+ rcv_desc->rx_buf_arr,
+ rcv_desc->rx_buf_phys);
+ rcv_desc->rx_buf_arr = NULL;
+ }
+ }
+ }
+
+ vfree(cmd_buf_arr);
+
+ kfree(adapter->port);
+
+ err_out_free_adapter:
+ kfree(adapter);
+
+ err_out_iounmap:
+ iounmap((u8 *) mem_ptr);
+ err_out_free_res:
+ pci_release_regions(pdev);
+ err_out_disable_pdev:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ netxen_nic_probe_err = err;
+ return err;
+}
+
+static void __devexit netxen_nic_remove(struct pci_dev *pdev)
+{
+ struct netxen_adapter *adapter;
+ struct netdev_list *netlist;
+ struct netxen_rx_buffer *buffer;
+ struct netxen_recv_context *recv_ctx;
+ struct netxen_rcv_desc_ctx *rcv_desc;
+ int i;
+ int ctx, ring;
+
+ netlist = pci_get_drvdata(pdev);
+ if (netlist == NULL || netlist->netdev == NULL)
+ return;
+ adapter =
+ ((struct netxen_port *)(netdev_priv(netlist->netdev)))->adapter;
+ if (adapter == NULL)
+ return;
+
+ netxen_nic_stop_all_ports(adapter);
+ /* leave the hw in the same state as reboot */
+ pinit_from_rom(adapter, 0);
+ udelay(500);
+ load_firmware(adapter);
+
+ if ((adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
+ read_lock(&adapter->adapter_lock);
+ netxen_nic_disable_int(adapter);
+ read_unlock(&adapter->adapter_lock);
+ }
+ udelay(500); /* Delay for a while to drain the DMA engines */
+
+ netlist = pci_get_drvdata(pdev);
+ if (adapter->irq)
+ free_irq(adapter->irq, adapter);
+ if ((adapter->flags & NETXEN_NIC_MSI_ENABLED))
+ pci_disable_msi(pdev);
+ while (netlist != NULL) {
+ struct netdev_list *prev;
+
+ unregister_netdev(netlist->netdev);
+ free_netdev(netlist->netdev);
+ prev = netlist;
+ netlist = netlist->next;
+ kfree(prev);
+ }
+ adapter->netlist = NULL;
+ pci_set_drvdata(pdev, NULL);
+
+ netxen_free_hw_resources(adapter);
+
+ iounmap((u8 *) adapter->ahw.pci_base);
+
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+
+ for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
+ recv_ctx = &adapter->recv_ctx[ctx];
+ for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) {
+ rcv_desc = &recv_ctx->rcv_desc[ring];
+ for (i = 0; i < rcv_desc->max_rx_desc_count; ++i) {
+ buffer = &(rcv_desc->rx_buf_arr[i]);
+ if (buffer->state == NETXEN_BUFFER_FREE)
+ continue;
+ pci_unmap_single(pdev, buffer->dma,
+ rcv_desc->dma_size,
+ PCI_DMA_FROMDEVICE);
+ if (buffer->skb != NULL)
+ dev_kfree_skb_any(buffer->skb);
+ }
+ }
+ for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
+ recv_ctx = &adapter->recv_ctx[ctx];
+ for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) {
+ rcv_desc = &recv_ctx->rcv_desc[ring];
+ pci_free_consistent(pdev, RCV_BUFFSIZE,
+ rcv_desc->rx_buf_arr,
+ rcv_desc->rx_buf_phys);
+ }
+ }
+ }
+
+ vfree(adapter->cmd_buf_arr);
+
+ kfree(adapter->port);
+ kfree(adapter);
+}
+
+/*
+ * Called when a network interface is made active
+ * @returns 0 on success, negative value on failure
+ */
+static int netxen_nic_open(struct net_device *netdev)
+{
+ struct netxen_port *port = netdev_priv(netdev);
+ struct netxen_adapter *adapter = port->adapter;
+ struct netxen_rcv_desc_ctx *rcv_desc;
+ int err = 0;
+ int ctx, ring;
+ static int opencount = 0;
+
+ if (!try_module_get(THIS_MODULE))
+ return -ENODEV;
+
+ if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) {
+ err = init_firmware(adapter);
+ if (err != 0) {
+ printk(KERN_ERR "Failed to init firmware\n");
+ module_put(THIS_MODULE);
+ return -EIO;
+ }
+ netxen_nic_flash_print(adapter);
+
+ printk("NetXen adapter %d\n", opencount);
+ adapter->is_up = NETXEN_ADAPTER_UP_MAGIC;
+ /* setup all the resources for the Phantom... */
+ /* this include the descriptors for rcv, tx, and status */
+ netxen_nic_clear_stats(adapter);
+ err = netxen_nic_hw_resources(adapter);
+ if (err) {
+ printk(KERN_ERR "Error in setting hw resources:%d\n",
+ err);
+ module_put(THIS_MODULE);
+ return err;
+ }
+ if (netxen_nic_init_port(port) != 0) {
+ printk(KERN_ERR "%s: Failed to initialize port %d\n",
+ netxen_nic_driver_name, port->portnum);
+ module_put(THIS_MODULE);
+ netxen_free_hw_resources(adapter);
+ return -EIO;
+ }
+ netxen_nic_init_niu(adapter);
+ for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
+ for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) {
+ rcv_desc =
+ &adapter->recv_ctx[ctx].rcv_desc[ring];
+ netxen_post_rx_buffers(adapter, ctx, ring);
+ }
+ }
+
+ err = request_irq(netdev->irq, &netxen_intr,
+ SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name,
+ adapter);
+ if (err) {
+ printk(KERN_ERR "request_irq failed with: %d\n", err);
+ netxen_free_hw_resources(adapter);
+ module_put(THIS_MODULE);
+ return err;
+ }
+ adapter->irq = netdev->irq;
+ mod_timer(&adapter->watchdog_timer, jiffies);
+ }
+ ++opencount;
+ adapter->active_ports++;
+ if (adapter->active_ports == 1) {
+ read_lock(&adapter->adapter_lock);
+ netxen_nic_enable_int(adapter);
+ read_unlock(&adapter->adapter_lock);
+ }
+
+ spin_lock_init(&port->stats_lock);
+
+ /* Done here again so that even if phantom sw overwrote it,
+ we set it */
+ netxen_nic_macaddr_set(port, port->hw.mac_addr);
+ netxen_nic_set_link_parameters(port);
+
+ netxen_nic_set_multi(netdev);
+ if (!adapter->driver_mismatch)
+ netif_start_queue(netdev);
+
+ port->state = NETXEN_PORT_UP;
+ return 0;
+}
+
+/**
+ * netxen_nic_close - Disables a network interface entry point
+ **/
+static int netxen_nic_close(struct net_device *netdev)
+{
+ struct netxen_port *port = netdev_priv(netdev);
+
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ netxen_nic_down(port);
+
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct netxen_port *port = netdev_priv(netdev);
+ unsigned int nr_frags = 0;
+ struct netxen_adapter *adapter = port->adapter;
+ struct netxen_hardware_context *hw = &adapter->ahw;
+ struct pci_dev *pdev;
+ unsigned int first_seg_len = skb->len - skb->data_len;
+ struct netxen_skb_frag *buffrag;
+ unsigned int i;
+
+ u32 producer = 0;
+ u32 saved_producer = 0;
+ struct cmd_desc_type0_t *hwdesc;
+ int k;
+ struct netxen_cmd_buffer *pbuf = NULL;
+ unsigned int tries = 0;
+ static int dropped_packet = 0;
+ struct netxen_skb_frag *frag;
+ int frag_count;
+ u32 local_producer = 0;
+ u32 max_tx_desc_count = 0;
+ u32 last_cmd_consumer = 0;
+ int no_of_desc;
+
+ port->stats.xmitcalled++;
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ frag_count = 1 + nr_frags;
+
+ if (unlikely(skb->len <= 0)) {
+ dev_kfree_skb_any(skb);
+ port->stats.badskblen++;
+ return 0;
+ }
+
+ if (frag_count > MAX_BUFFERS_PER_CMD) {
+ printk
+ ("%s: %s netxen_nic_xmit_frame: frag_count (%d) too large, "
+ "can handle only %d frags\n", netxen_nic_driver_name,
+ netdev->name, frag_count, MAX_BUFFERS_PER_CMD);
+ goto drop_packet;
+ }
+
+ /*
+ * Everything is set up. Now, we just need to transmit it out.
+ * Note that we have to copy the contents of buffer over to
+ * right place. Later on, this can be optimized out by de-coupling the
+ * producer index from the buffer index.
+ */
+ retry_getting_window:
+ spin_lock_bh(&adapter->tx_lock);
+ if (adapter->total_threads == MAX_XMIT_PRODUCERS) {
+ spin_unlock_bh(&adapter->tx_lock);
+ /*
+ * Yield CPU
+ */
+ if (!in_atomic())
+ schedule();
+ else {
+ for (i = 0; i < 20; i++)
+ cpu_relax(); /*This a nop instr on i386 */
+ }
+ goto retry_getting_window;
+ }
+ local_producer = adapter->cmd_producer;
+ /* There 4 fragments per descriptor */
+ no_of_desc = (frag_count + 3) >> 2;
+ if (skb_shinfo(skb)->tso_size > 0) {
+ no_of_desc++;
+ if (((skb->nh.iph)->ihl * sizeof(u32)) +
+ ((skb->h.th)->doff * sizeof(u32)) +
+ sizeof(struct ethhdr) >
+ (sizeof(struct cmd_desc_type0_t) - IP_ALIGNMENT_BYTES)) {
+ no_of_desc++;
+ }
+ }
+ k = adapter->cmd_producer;
+ max_tx_desc_count = adapter->max_tx_desc_count;
+ last_cmd_consumer = adapter->last_cmd_consumer;
+ if ((k + no_of_desc) >=
+ ((last_cmd_consumer <= k) ? last_cmd_consumer + max_tx_desc_count :
+ last_cmd_consumer)) {
+ spin_unlock_bh(&adapter->tx_lock);
+ if (tries == 0) {
+ local_bh_disable();
+ netxen_process_cmd_ring((unsigned long)adapter);
+ local_bh_enable();
+ ++tries;
+ goto retry_getting_window;
+ } else {
+ port->stats.nocmddescriptor++;
+ DPRINTK(ERR, "No command descriptors available,"
+ " producer = %d, consumer = %d count=%llu,"
+ " dropping packet\n", producer,
+ adapter->last_cmd_consumer,
+ port->stats.nocmddescriptor);
+ goto requeue_packet;
+ }
+ }
+ k = get_index_range(k, max_tx_desc_count, no_of_desc);
+ adapter->cmd_producer = k;
+ adapter->total_threads++;
+ adapter->num_threads++;
+
+ spin_unlock_bh(&adapter->tx_lock);
+ /* Copy the descriptors into the hardware */
+ producer = local_producer;
+ saved_producer = producer;
+ hwdesc = &hw->cmd_desc_head[producer];
+ memset(hwdesc, 0, sizeof(struct cmd_desc_type0_t));
+ /* Take skb->data itself */
+ pbuf = &adapter->cmd_buf_arr[producer];
+ if (skb_shinfo(skb)->tso_size > 0) {
+ pbuf->mss = skb_shinfo(skb)->tso_size;
+ hwdesc->mss = skb_shinfo(skb)->tso_size;
+ } else {
+ pbuf->mss = 0;
+ hwdesc->mss = 0;
+ }
+ pbuf->no_of_descriptors = no_of_desc;
+ pbuf->total_length = skb->len;
+ pbuf->skb = skb;
+ pbuf->cmd = TX_ETHER_PKT;
+ pbuf->frag_count = frag_count;
+ pbuf->port = port->portnum;
+ buffrag = &pbuf->frag_array[0];
+ buffrag->dma = pci_map_single(port->pdev, skb->data, first_seg_len,
+ PCI_DMA_TODEVICE);
+ buffrag->length = first_seg_len;
+ hwdesc->total_length = skb->len;
+ hwdesc->num_of_buffers = frag_count;
+ hwdesc->opcode = TX_ETHER_PKT;
+
+ hwdesc->port = port->portnum;
+ hwdesc->buffer1_length = first_seg_len;
+ hwdesc->addr_buffer1 = buffrag->dma;
+
+ for (i = 1, k = 1; i < frag_count; i++, k++) {
+ struct skb_frag_struct *frag;
+ int len, temp_len;
+ unsigned long offset;
+ dma_addr_t temp_dma;
+
+ /* move to next desc. if there is a need */
+ if ((i & 0x3) == 0) {
+ k = 0;
+ producer = get_next_index(producer,
+ adapter->max_tx_desc_count);
+ hwdesc = &hw->cmd_desc_head[producer];
+ memset(hwdesc, 0, sizeof(struct cmd_desc_type0_t));
+ }
+ frag = &skb_shinfo(skb)->frags[i - 1];
+ len = frag->size;
+ offset = frag->page_offset;
+
+ temp_len = len;
+ temp_dma = pci_map_page(port->pdev, frag->page, offset,
+ len, PCI_DMA_TODEVICE);
+
+ buffrag++;
+ buffrag->dma = temp_dma;
+ buffrag->length = temp_len;
+
+ DPRINTK(INFO, "for loop. i=%d k=%d\n", i, k);
+ switch (k) {
+ case 0:
+ hwdesc->buffer1_length = temp_len;
+ hwdesc->addr_buffer1 = temp_dma;
+ break;
+ case 1:
+ hwdesc->buffer2_length = temp_len;
+ hwdesc->addr_buffer2 = temp_dma;
+ break;
+ case 2:
+ hwdesc->buffer3_length = temp_len;
+ hwdesc->addr_buffer3 = temp_dma;
+ break;
+ case 3:
+ hwdesc->buffer4_length = temp_len;
+ hwdesc->addr_buffer4 = temp_dma;
+ break;
+ }
+ frag++;
+ }
+ producer = get_next_index(producer, adapter->max_tx_desc_count);
+
+ /* might change opcode to TX_TCP_LSO */
+ netxen_tso_check(adapter, &hw->cmd_desc_head[saved_producer], skb);
+
+ /* For LSO, we need to copy the MAC/IP/TCP headers into
+ * the descriptor ring
+ */
+ if (hw->cmd_desc_head[saved_producer].opcode == TX_TCP_LSO) {
+ int hdr_len, first_hdr_len, more_hdr;
+ hdr_len = hw->cmd_desc_head[saved_producer].total_hdr_length;
+ if (hdr_len >
+ (sizeof(struct cmd_desc_type0_t) - IP_ALIGNMENT_BYTES)) {
+ first_hdr_len =
+ sizeof(struct cmd_desc_type0_t) -
+ IP_ALIGNMENT_BYTES;
+ more_hdr = 1;
+ } else {
+ first_hdr_len = hdr_len;
+ more_hdr = 0;
+ }
+ /* copy the MAC/IP/TCP headers to the cmd descriptor list */
+ hwdesc = &hw->cmd_desc_head[producer];
+
+ /* copy the first 64 bytes */
+ memcpy(((void *)hwdesc) + IP_ALIGNMENT_BYTES,
+ (void *)(skb->data), first_hdr_len);
+ producer = get_next_index(producer, max_tx_desc_count);
+
+ if (more_hdr) {
+ hwdesc = &hw->cmd_desc_head[producer];
+ /* copy the next 64 bytes - should be enough except
+ * for pathological case
+ */
+ memcpy((void *)hwdesc, (void *)(skb->data) +
+ first_hdr_len, hdr_len - first_hdr_len);
+ producer = get_next_index(producer, max_tx_desc_count);
+ }
+ }
+ spin_lock_bh(&adapter->tx_lock);
+ port->stats.txbytes += hw->cmd_desc_head[saved_producer].total_length;
+ /* Code to update the adapter considering how many producer threads
+ are currently working */
+ if ((--adapter->num_threads) == 0) {
+ /* This is the last thread */
+ u32 crb_producer = adapter->cmd_producer;
+ hw->cmd_producer = adapter->cmd_producer;
+ read_lock(&adapter->adapter_lock);
+ writel(crb_producer,
+ NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_PRODUCER_OFFSET));
+ read_unlock(&adapter->adapter_lock);
+
+ adapter->total_threads = 0;
+ } else {
+ u32 crb_producer = 0;
+ read_lock(&adapter->adapter_lock);
+ crb_producer =
+ readl(NETXEN_CRB_NORMALIZE
+ (adapter, CRB_CMD_PRODUCER_OFFSET));
+ read_unlock(&adapter->adapter_lock);
+
+ if (crb_producer == local_producer) {
+ crb_producer = get_index_range(crb_producer,
+ max_tx_desc_count,
+ no_of_desc);
+ read_lock(&adapter->adapter_lock);
+ writel(crb_producer,
+ NETXEN_CRB_NORMALIZE(adapter,
+ CRB_CMD_PRODUCER_OFFSET));
+ read_unlock(&adapter->adapter_lock);
+
+ hw->cmd_producer = crb_producer;
+ }
+ }
+
+ port->stats.xmitfinished++;
+ spin_unlock_bh(&adapter->tx_lock);
+
+ netdev->trans_start = jiffies;
+
+ DPRINTK(INFO, "wrote CMD producer %x to phantom\n", producer);
+
+ DPRINTK(INFO, "Done. Send\n");
+ goto netxen_nic_xmit_success;
+
+ requeue_packet:
+ spin_lock_bh(&adapter->tx_lock);
+ netif_stop_queue(netdev);
+ port->flags |= NETXEN_NETDEV_STATUS;
+ spin_unlock_bh(&adapter->tx_lock);
+ return NETDEV_TX_BUSY;
+
+ drop_packet:
+ pbuf = &adapter->cmd_buf_arr[producer];
+ frag = &pbuf->frag_array[0];
+ pdev = port->pdev;
+ pci_unmap_single(pdev, frag->dma, frag->length, PCI_DMA_TODEVICE);
+ for (i = 1; i < frag_count; i++) {
+ frag++; /* Get the next frag */
+ pci_unmap_page(pdev, frag->dma, frag->length, PCI_DMA_TODEVICE);
+ }
+
+ port->stats.txdropped++;
+ dev_kfree_skb_any(pbuf->skb);
+ pbuf->skb = NULL;
+ if ((++dropped_packet & 0xff) == 0xff)
+ printk("%s: %s droppped packets = %d\n", netxen_nic_driver_name,
+ netdev->name, dropped_packet);
+
+ netxen_nic_xmit_success:
+ return NETDEV_TX_OK;
+}
+
+static void netxen_watchdog(unsigned long v)
+{
+ struct netxen_adapter *adapter = (struct netxen_adapter *)v;
+ schedule_work(&adapter->watchdog_task);
+}
+
+static void netxen_tx_timeout(struct net_device *netdev)
+{
+ struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev);
+ struct netxen_adapter *adapter = port->adapter;
+
+ schedule_work(adapter->tx_timeout_task + port->portnum);
+}
+
+static void netxen_tx_timeout_task(struct net_device *netdev)
+{
+ struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev);
+ unsigned long flags;
+
+ printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
+ netxen_nic_driver_name, netdev->name);
+
+ spin_lock_irqsave(&port->adapter->lock, flags);
+ netxen_nic_close(netdev);
+ netxen_nic_open(netdev);
+ spin_unlock_irqrestore(&port->adapter->lock, flags);
+ netdev->trans_start = jiffies;
+ netif_wake_queue(netdev);
+}
+
+static int
+netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev)
+{
+ u32 ret = 0;
+
+ DPRINTK(INFO, "Entered handle ISR\n");
+
+ adapter->stats.ints++;
+
+ if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
+ int count = 0;
+ u32 mask;
+ read_lock(&adapter->adapter_lock);
+ netxen_nic_disable_int(adapter);
+ /* Window = 0 or 1 */
+ do {
+ writel(0xffffffff, (void *)
+ (adapter->ahw.pci_base + ISR_INT_TARGET_STATUS));
+ mask = readl((void *)
+ (adapter->ahw.pci_base + ISR_INT_VECTOR));
+ } while (((mask & 0x80) != 0) && (++count < 32));
+ if ((mask & 0x80) != 0)
+ printk("Could not disable interrupt completely\n");
+
+ read_unlock(&adapter->adapter_lock);
+ }
+ adapter->stats.hostints++;
+
+ if (netxen_nic_rx_has_work(adapter) || netxen_nic_tx_has_work(adapter)) {
+ if (netif_rx_schedule_prep(netdev)) {
+ /*
+ * Interrupts are already disabled.
+ */
+ __netif_rx_schedule(netdev);
+ } else {
+ static unsigned int intcount = 0;
+ if ((++intcount & 0xfff) == 0xfff)
+ printk(KERN_ERR
+ "%s: %s interrupt %d while in poll\n",
+ netxen_nic_driver_name, netdev->name,
+ intcount);
+ }
+ ret = 1;
+ }
+
+ if (ret == 0) {
+ read_lock(&adapter->adapter_lock);
+ netxen_nic_enable_int(adapter);
+ read_unlock(&adapter->adapter_lock);
+ }
+
+ return ret;
+}
+
+/**
+ * netxen_intr - Interrupt Handler
+ * @irq: interrupt number
+ * data points to adapter stucture (which may be handling more than 1 port
+ **/
+irqreturn_t netxen_intr(int irq, void *data, struct pt_regs * regs)
+{
+ struct netxen_adapter *adapter;
+ struct netxen_port *port;
+ struct net_device *netdev;
+
+ if (unlikely(!irq)) {
+ return IRQ_NONE; /* Not our interrupt */
+ }
+
+ adapter = (struct netxen_adapter *)data;
+ port = adapter->port[0];
+ netdev = port->netdev;
+
+ /* process our status queue (for all 4 ports) */
+ netxen_handle_int(adapter, netdev);
+
+ return IRQ_HANDLED;
+}
+
+static int netxen_nic_poll(struct net_device *netdev, int *budget)
+{
+ struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev);
+ struct netxen_adapter *adapter = port->adapter;
+ int work_to_do = min(*budget, netdev->quota);
+ int done = 1;
+ int ctx;
+ int this_work_done;
+
+ DPRINTK(INFO, "polling for %d descriptors\n", *budget);
+ port->stats.polled++;
+
+ adapter->work_done = 0;
+ for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
+ /*
+ * Fairness issue. This will give undue weight to the
+ * receive context 0.
+ */
+
+ /*
+ * To avoid starvation, we give each of our receivers,
+ * a fraction of the quota. Sometimes, it might happen that we
+ * have enough quota to process every packet, but since all the
+ * packets are on one context, it gets only half of the quota,
+ * and ends up not processing it.
+ */
+ this_work_done = netxen_process_rcv_ring(adapter, ctx,
+ work_to_do /
+ MAX_RCV_CTX);
+ adapter->work_done += this_work_done;
+ }
+
+ netdev->quota -= adapter->work_done;
+ *budget -= adapter->work_done;
+
+ if (adapter->work_done >= work_to_do
+ && netxen_nic_rx_has_work(adapter) != 0)
+ done = 0;
+
+ netxen_process_cmd_ring((unsigned long)adapter);
+
+ DPRINTK(INFO, "new work_done: %d work_to_do: %d\n",
+ adapter->work_done, work_to_do);
+ if (done) {
+ netif_rx_complete(netdev);
+ read_lock(&adapter->adapter_lock);
+ netxen_nic_enable_int(adapter);
+ read_unlock(&adapter->adapter_lock);
+ }
+
+ return (done ? 0 : 1);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void netxen_nic_poll_controller(struct net_device *netdev)
+{
+ struct netxen_port *port = netdev_priv(netdev);
+ struct netxen_adapter *adapter = port->adapter;
+ disable_irq(netdev->irq);
+ netxen_intr(netdev->irq, adapter, NULL);
+ enable_irq(netdev->irq);
+}
+#endif
+
+/*
+ * netxen_nic_ioctl () We provide the tcl/phanmon support through these
+ * ioctls.
+ */
+static int
+netxen_nic_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ int err = 0;
+ struct netxen_port *port = netdev_priv(netdev);
+ struct netxen_adapter *adapter = port->adapter;
+
+ DPRINTK(INFO, "doing ioctl for %s\n", netdev->name);
+ switch (cmd) {
+ case NETXEN_NIC_CMD:
+ err = netxen_nic_do_ioctl(adapter, (void *)ifr->ifr_data, port);
+ break;
+
+ case NETXEN_NIC_NAME:
+ DPRINTK(INFO, "ioctl cmd for NetXen\n");
+ if (ifr->ifr_data) {
+ put_user(port->portnum, (u16 *) ifr->ifr_data);
+ }
+ break;
+
+ default:
+ DPRINTK(INFO, "ioctl cmd %x not supported\n", cmd);
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ return err;
+}
+
+static struct pci_driver netxen_driver = {
+ .name = netxen_nic_driver_name,
+ .id_table = netxen_pci_tbl,
+ .probe = netxen_nic_probe,
+ .remove = __devexit_p(netxen_nic_remove),
+ .suspend = netxen_nic_suspend,
+ .resume = netxen_nic_resume
+};
+
+/* Driver Registration on NetXen card */
+
+static int __init netxen_init_module(void)
+{
+ printk(KERN_INFO "%s \n", netxen_nic_driver_string);
+
+ pci_module_init(&netxen_driver);
+
+ return netxen_nic_probe_err;
+}
+
+module_init(netxen_init_module);
+
+static void __exit netxen_exit_module(void)
+{
+ int i;
+ struct netxen_adapter *adapter;
+
+ for (i = 0; i < MAX_NUM_CARDS; i++) {
+ adapter = adapterlist[i];
+ if (adapter == NULL)
+ continue;
+ if (adapter->netlist != NULL
+ && adapter->netlist->netdev != NULL) {
+ read_lock(&adapter->adapter_lock);
+ netxen_nic_disable_int(adapter);
+ read_unlock(&adapter->adapter_lock);
+ pinit_from_rom(adapter, 0);
+ }
+ }
+
+ /*
+ * Wait for some time to allow the dma to drain, if any.
+ */
+ mdelay(5);
+ pci_unregister_driver(&netxen_driver);
+}
+
+module_exit(netxen_exit_module);
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 8/9] Resending NetXen 1G/10G NIC driver patch
2006-05-25 10:57 [PATCH 8/9] Resending NetXen 1G/10G NIC driver patch Linsys Contractor Amit S. Kale
@ 2006-05-25 16:44 ` Roland Dreier
2006-05-25 17:03 ` Stephen Hemminger
1 sibling, 0 replies; 5+ messages in thread
From: Roland Dreier @ 2006-05-25 16:44 UTC (permalink / raw)
To: Linsys Contractor Amit S. Kale; +Cc: netdev, sanjeev, unmproj
> +static int __devinit
> +netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
> +#if defined(CONFIG_PCI_MSI)
> + adapter->flags |= NETXEN_NIC_MSI_ENABLED;
> + if (pci_enable_msi(pdev)) {
> + adapter->flags &= ~NETXEN_NIC_MSI_ENABLED;
> + printk(KERN_WARNING "%s: unable to allocate MSI interrupt"
> + " error\n", netxen_nic_driver_name);
> + }
> +#endif
No need for the #ifdef -- pci_enable_msi() is stubbed out so it will
always just return failure if CONFIG_PCI_MSI is not set.
> + adapterlist[netxen_cards_found++] = adapter;
> + adapter->number = netxen_cards_found;
Having a static array of adapters is a bad idea. Just allocate a
data structure for each card as you probe it.
- R.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 8/9] Resending NetXen 1G/10G NIC driver patch
2006-05-25 10:57 [PATCH 8/9] Resending NetXen 1G/10G NIC driver patch Linsys Contractor Amit S. Kale
2006-05-25 16:44 ` Roland Dreier
@ 2006-05-25 17:03 ` Stephen Hemminger
2006-05-26 14:26 ` Pradeep Dalvi
1 sibling, 1 reply; 5+ messages in thread
From: Stephen Hemminger @ 2006-05-25 17:03 UTC (permalink / raw)
To: Linsys Contractor Amit S. Kale; +Cc: netdev, sanjeev, unmproj
The object factoring is a mess here. You have too many allocations
and indirections. My expectation would be:
1. One PCI device maps to one board and that is the adapter structure
allocated with kzalloc. (You are doing this right)
2. An adapter can have up to four ports. Each of these should be a
netdevice and any port specific memory should be part of netdev_priv().
3. Have an array of pointers in the adapter structure for the maximum
possible value, if the board has less the memory waste for three
extra pointers is less than cost of dynamically sized array.
Something like
pci_prvdata -> adapter --> dev[0] -> netdevice { private data }
--> dev[1] ...
or
pci_privdata -> adapter -> port[0] -> private data
-> port[1]
In the later case, you need to have port->netdev pointer back to the
start of the net_device data structure.
If you do it this way, you won't need:
> + adapter->port = kcalloc(adapter->ahw.max_ports,
> + sizeof(struct netxen_adapter), GFP_KERNEL);
and
> + netlist = kzalloc(sizeof(struct netdev_list), GFP_KERNEL);
> + if (netlist == NULL)
> + goto err_out_free_dev;
Also, do you really need to have such a big TX ring that it requires
a vmalloc?
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 8/9] Resending NetXen 1G/10G NIC driver patch
2006-05-25 17:03 ` Stephen Hemminger
@ 2006-05-26 14:26 ` Pradeep Dalvi
2006-05-26 16:08 ` Stephen Hemminger
0 siblings, 1 reply; 5+ messages in thread
From: Pradeep Dalvi @ 2006-05-26 14:26 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Linsys Contractor Amit S. Kale, Kernel Netdev Mailing List,
Sanjeev Jorapur, UNM Project Staff
diff -u linux-2.6.16.18/drivers/net/netxen/netxen_nic_main.c
linux-2.6.16.18/drivers/net/netxen/netxen_nic_main.c
--- linux-2.6.16.18/drivers/net/netxen/netxen_nic_main.c
2006-05-25 02:43:22.000000000 -0700
+++ linux-2.6.16.18/drivers/net/netxen/netxen_nic_main.c
2006-05-26 04:05:34.000000000 -0700
@@ -259,14 +259,12 @@
pci_read_config_byte(pdev, PCI_REVISION_ID, &adapter-
>ahw.revision_id);
pci_read_config_word(pdev, PCI_COMMAND, &adapter-
>ahw.pci_cmd_word);
-#if defined(CONFIG_PCI_MSI)
- adapter->flags |= NETXEN_NIC_MSI_ENABLED;
if (pci_enable_msi(pdev)) {
adapter->flags &= ~NETXEN_NIC_MSI_ENABLED;
printk(KERN_WARNING "%s: unable to allocate MSI
interrupt"
" error\n", netxen_nic_driver_name);
- }
-#endif
+ } else
+ adapter->flags |= NETXEN_NIC_MSI_ENABLED;
if (is_flash_supported(adapter) == 0 &&
get_flash_mac_addr(adapter, mac_addr) == 0)
@@ -295,7 +293,6 @@
port = netdev_priv(netdev);
port->netdev = netdev;
port->pdev = pdev;
- port->hw.port = port;
port->adapter = adapter;
port->portnum = i; /* Gigabit port number starting
from 0-3 */
port->flags &= ~NETXEN_NETDEV_STATUS;
@@ -329,27 +326,25 @@
boardno = netxen_nic_get_board_num(adapter);
if (valid_mac) {
unsigned char *p = (unsigned char *)&mac_addr
[i];
- port->hw.mac_addr[0] = *(p + 5);
- port->hw.mac_addr[1] = *(p + 4);
- port->hw.mac_addr[2] = *(p + 3);
- port->hw.mac_addr[3] = *(p + 2);
- port->hw.mac_addr[4] = *(p + 1);
- port->hw.mac_addr[5] = *(p + 0);
-
- if (!is_valid_ether_addr(port->hw.mac_addr)) {
- printk(KERN_ERR"%s: Bad MAC address"
- "%02x:%02x:%02x:%02x:%02x:%
02x.\n",
+ netdev->dev_addr[0] = *(p + 5);
+ netdev->dev_addr[1] = *(p + 4);
+ netdev->dev_addr[2] = *(p + 3);
+ netdev->dev_addr[3] = *(p + 2);
+ netdev->dev_addr[4] = *(p + 1);
+ netdev->dev_addr[5] = *(p + 0);
+
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
+ printk(KERN_ERR
+ "%s: Bad MAC address %02x:%02x:%
02x:%02x:%02x:%02x.\n",
netxen_nic_driver_name,
- port->hw.mac_addr[0],
- port->hw.mac_addr[1],
- port->hw.mac_addr[2],
- port->hw.mac_addr[3],
- port->hw.mac_addr[4],
- port->hw.mac_addr[5]);
+ netdev->dev_addr[0],
+ netdev->dev_addr[1],
+ netdev->dev_addr[2],
+ netdev->dev_addr[3],
+ netdev->dev_addr[4],
+ netdev->dev_addr[5]);
} else {
- memcpy(netdev->dev_addr, port-
>hw.mac_addr,
- netdev->addr_len);
- netxen_nic_macaddr_set(port, port-
>hw.mac_addr);
+ netxen_nic_macaddr_set(port, netdev-
>dev_addr);
}
}
INIT_WORK(adapter->tx_timeout_task + i,
@@ -629,14 +624,13 @@
/* Done here again so that even if phantom sw overwrote it,
we set it */
- netxen_nic_macaddr_set(port, port->hw.mac_addr);
+ netxen_nic_macaddr_set(port, netdev->dev_addr);
netxen_nic_set_link_parameters(port);
netxen_nic_set_multi(netdev);
if (!adapter->driver_mismatch)
netif_start_queue(netdev);
- port->state = NETXEN_PORT_UP;
return 0;
}
@@ -728,7 +722,7 @@
if (((skb->nh.iph)->ihl * sizeof(u32)) +
((skb->h.th)->doff * sizeof(u32)) +
sizeof(struct ethhdr) >
- (sizeof(struct cmd_desc_type0_t) -
IP_ALIGNMENT_BYTES)) {
+ (sizeof(struct cmd_desc_type0_t) - NET_IP_ALIGN)) {
no_of_desc++;
}
}
@@ -852,10 +846,10 @@
int hdr_len, first_hdr_len, more_hdr;
hdr_len = hw->cmd_desc_head
[saved_producer].total_hdr_length;
if (hdr_len >
- (sizeof(struct cmd_desc_type0_t) -
IP_ALIGNMENT_BYTES)) {
+ (sizeof(struct cmd_desc_type0_t) - NET_IP_ALIGN)) {
first_hdr_len =
sizeof(struct cmd_desc_type0_t) -
- IP_ALIGNMENT_BYTES;
+ NET_IP_ALIGN;
more_hdr = 1;
} else {
first_hdr_len = hdr_len;
@@ -865,7 +859,7 @@
hwdesc = &hw->cmd_desc_head[producer];
/* copy the first 64 bytes */
- memcpy(((void *)hwdesc) + IP_ALIGNMENT_BYTES,
+ memcpy(((void *)hwdesc) + NET_IP_ALIGN,
(void *)(skb->data), first_hdr_len);
producer = get_next_index(producer, max_tx_desc_count);
On Thu, 2006-05-25 at 10:03 -0700, Stephen Hemminger wrote:
> The object factoring is a mess here. You have too many allocations
> and indirections. My expectation would be:
>
> 1. One PCI device maps to one board and that is the adapter structure
> allocated with kzalloc. (You are doing this right)
>
> 2. An adapter can have up to four ports. Each of these should be a
> netdevice and any port specific memory should be part of netdev_priv().
>
> 3. Have an array of pointers in the adapter structure for the maximum
> possible value, if the board has less the memory waste for three
> extra pointers is less than cost of dynamically sized array.
>
> Something like
>
> pci_prvdata -> adapter --> dev[0] -> netdevice { private data }
> --> dev[1] ...
> or
> pci_privdata -> adapter -> port[0] -> private data
> -> port[1]
>
> In the later case, you need to have port->netdev pointer back to the
> start of the net_device data structure.
>
> If you do it this way, you won't need:
>
> > + adapter->port = kcalloc(adapter->ahw.max_ports,
> > + sizeof(struct netxen_adapter), GFP_KERNEL);
>
> and
>
> > + netlist = kzalloc(sizeof(struct netdev_list), GFP_KERNEL);
> > + if (netlist == NULL)
> > + goto err_out_free_dev;
>
> Also, do you really need to have such a big TX ring that it requires
> a vmalloc?
>
>
--
pradeep
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 8/9] Resending NetXen 1G/10G NIC driver patch
2006-05-26 14:26 ` Pradeep Dalvi
@ 2006-05-26 16:08 ` Stephen Hemminger
0 siblings, 0 replies; 5+ messages in thread
From: Stephen Hemminger @ 2006-05-26 16:08 UTC (permalink / raw)
To: pradeep
Cc: Linsys Contractor Amit S. Kale, Kernel Netdev Mailing List,
Sanjeev Jorapur, UNM Project Staff
You might also want to add support for setting
dev->perm_addr
and using ethtool_op_get_perm_addr() in ethtool_ops
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2006-05-26 16:08 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-25 10:57 [PATCH 8/9] Resending NetXen 1G/10G NIC driver patch Linsys Contractor Amit S. Kale
2006-05-25 16:44 ` Roland Dreier
2006-05-25 17:03 ` Stephen Hemminger
2006-05-26 14:26 ` Pradeep Dalvi
2006-05-26 16:08 ` Stephen Hemminger
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).