* [PATCH 8/9] NetXen 1G/10G ethernet driver patch with corrections
From: Linsys Contractor Amit S. Kale @ 2006-06-07 9:55 UTC (permalink / raw)
To: netdev; +Cc: sanjeev, unmproj
2006-06-07 Amit S. Kale <amitkale@unminc.com>
* Add netxen driver main routines: module initialization, probe,
xmit, receive, interrupt handler
diff -Naru linux-2.6.16.20.orig/drivers/net/netxen/netxen_nic_main.c linux-2.6.16.20/drivers/net/netxen/netxen_nic_main.c
--- linux-2.6.16.20.orig/drivers/net/netxen/netxen_nic_main.c 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.16.20/drivers/net/netxen/netxen_nic_main.c 2006-06-06 06:58:11.000000000 -0700
@@ -0,0 +1,1228 @@
+/*
+ * 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;
+ u8 *db_ptr = NULL;
+ unsigned long mem_base, mem_len, db_base, db_len;
+ int pci_using_dac, i, err;
+ int boardno = 0;
+ int ring;
+ struct netxen_recv_context *recv_ctx = NULL;
+ struct netxen_rcv_desc_ctx *rcv_desc = NULL;
+ struct netxen_cmd_buffer *cmd_buf_arr[MAX_RING_CTX] = { NULL };
+ struct netxen_ring_context *ctx;
+ 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;
+ }
+ db_base = pci_resource_start(pdev, 4); /* doorbell is on bar 4 */
+ db_len = pci_resource_len(pdev, 4);
+
+ if (db_len == 0) {
+ printk(KERN_ERR "%s: doorbell is disabled\n",
+ netxen_nic_driver_name);
+ err = -EIO;
+ goto err_out_free_res;
+ }
+
+ DPRINTK(1, INFO, "doorbell ioremap from %lx a size of %lx\n", db_base,
+ db_len);
+
+ db_ptr = ioremap(db_base, NETXEN_DB_MAPSIZE_BYTES);
+ if (db_ptr == 0UL) {
+ printk(KERN_ERR "%s: Failed to allocate doorbell map.",
+ netxen_nic_driver_name);
+ err = -EIO;
+ goto err_out_free_res;
+ }
+ DPRINTK(1, INFO, "doorbell ioremaped at %p\n", db_ptr);
+
+/*
+ * 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;
+ }
+
+ netxen_check_options(adapter);
+ for (i = 0; i < MAX_RING_CTX; i++) {
+ cmd_buf_arr[i] =
+ (struct netxen_cmd_buffer *)vmalloc(TX_RINGSIZE(i));
+ if (cmd_buf_arr[i] == NULL) {
+ printk(KERN_ERR "%s: Failed to allocate memory for the"
+ "device block.Check system memory resource "
+ "usage.\n", netxen_nic_driver_name);
+ err = -ENOMEM;
+ goto err_out_free_adapter;
+ }
+ memset(cmd_buf_arr[i], 0, TX_RINGSIZE(i));
+ }
+
+ for (i = 0; i < MAX_RING_CTX; ++i) {
+ ctx = &adapter->ring_ctx[i];
+ recv_ctx = &ctx->recv_ctx;
+ 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 =
+ ctx->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 =
+ ctx->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);
+ }
+
+ }
+
+ for (i = 0; i < MAX_RING_CTX; ++i) {
+ ctx = &adapter->ring_ctx[i];
+ ctx->cmd_buf_arr = cmd_buf_arr[i];
+ }
+ 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;
+ adapter->ahw.db_base = (unsigned long)db_ptr;
+ adapter->ahw.db_len = db_len;
+ 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;
+ for (i = 0; i < MAX_RING_CTX; i++) {
+ adapter->ring_ctx[i].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 (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);
+ } else
+ adapter->flags |= NETXEN_NIC_MSI_ENABLED;
+
+ 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++) {
+ netdev = alloc_etherdev(sizeof(struct netxen_port));
+ if (netdev) {
+ printk(KERN_ERR "%s: could not allocate netdev for port"
+ " %d\n", netxen_nic_driver_name, i + 1);
+ goto err_out_free_dev;
+ }
+
+ SET_MODULE_OWNER(netdev);
+
+ port = netdev_priv(netdev);
+ port->netdev = netdev;
+ port->pdev = pdev;
+ 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];
+ 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);
+
+ memcpy(netdev->perm_addr, netdev->dev_addr,
+ netdev->addr_len);
+ if (!is_valid_ether_addr(netdev->perm_addr)) {
+ printk(KERN_ERR "%s: Bad MAC address "
+ "%02x:%02x:%02x:%02x:%02x:%02x.\n",
+ netxen_nic_driver_name,
+ 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 {
+ netxen_nic_macaddr_set(port, netdev->dev_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;
+ pci_set_drvdata(pdev, port);
+ }
+
+ /*
+ * 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;
+ }
+
+ 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 (port = pci_get_drvdata(pdev); port != NULL;) {
+ unregister_netdev(port->netdev);
+ free_netdev(port->netdev);
+ if (port->portnum <= 0)
+ break;
+ port = adapter->port[port->portnum - 1];
+ }
+ pci_set_drvdata(pdev, NULL);
+
+ err_out_free_rx_buffer:
+ for (i = 0; i < MAX_RING_CTX; ++i) {
+ ctx = &adapter->ring_ctx[i];
+ recv_ctx = &ctx->recv_ctx;
+ 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:
+ for (i = 0; i < MAX_RING_CTX; i++) {
+ if (cmd_buf_arr[i] != NULL)
+ vfree(cmd_buf_arr[i]);
+ }
+
+ 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 netxen_port *port;
+ struct netxen_rx_buffer *buffer;
+ struct netxen_recv_context *recv_ctx;
+ struct netxen_rcv_desc_ctx *rcv_desc;
+ struct netxen_ring_context *ctx;
+ int i;
+ int ctxid, ring;
+
+ port = pci_get_drvdata(pdev);
+ if (port == NULL || port->netdev == NULL)
+ return;
+ adapter = ((struct netxen_port *)(netdev_priv(port->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 */
+
+ port = pci_get_drvdata(pdev);
+ if (adapter->irq)
+ free_irq(adapter->irq, adapter);
+ if ((adapter->flags & NETXEN_NIC_MSI_ENABLED))
+ pci_disable_msi(pdev);
+ while (port != NULL) {
+ unregister_netdev(port->netdev);
+ free_netdev(port->netdev);
+ if (port->portnum <= 0)
+ break;
+ port = adapter->port[port->portnum - 1];
+ }
+ 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 (ctxid = 0; ctxid < MAX_RING_CTX; ++ctxid) {
+ ctx = &adapter->ring_ctx[ctxid];
+ recv_ctx = &ctx->recv_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);
+ }
+ pci_free_consistent(pdev, RCV_BUFFSIZE,
+ rcv_desc->rx_buf_arr,
+ rcv_desc->rx_buf_phys);
+ }
+ vfree(ctx->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;
+ int err = 0;
+ int ctxid, 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 (ctxid = 0; ctxid < MAX_RING_CTX; ++ctxid) {
+ for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) {
+ netxen_post_rx_buffers(adapter, ctxid, 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, netdev->dev_addr);
+ netxen_nic_set_link_parameters(port);
+
+ netxen_nic_set_multi(netdev);
+ if (!adapter->driver_mismatch)
+ netif_start_queue(netdev);
+
+ 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 pci_dev *pdev;
+ unsigned int first_seg_len = skb->len - skb->data_len;
+ struct netxen_skb_frag *buffrag;
+ unsigned int i;
+ int ctxid = 0;
+ 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;
+ struct netxen_ring_context *ctx = &adapter->ring_ctx[0];
+ struct netxen_hardware_ring_context *hw_ring_ctx = &(ctx->hw_ring_ctx);
+ 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 = ctx->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) - NET_IP_ALIGN)) {
+ no_of_desc++;
+ }
+ }
+ k = ctx->cmd_producer;
+ max_tx_desc_count = ctx->max_tx_desc_count;
+ last_cmd_consumer = ctx->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();
+ for (ctxid = 0; ctxid < MAX_RING_CTX; ++ctxid) {
+ netxen_process_cmd_ring((unsigned long)adapter,
+ ctxid);
+ }
+ 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,
+ ctx->last_cmd_consumer,
+ port->stats.nocmddescriptor);
+ goto requeue_packet;
+ }
+ }
+ k = get_index_range(k, max_tx_desc_count, no_of_desc);
+ ctx->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 = &ctx->hw_ring_ctx.cmd_desc_head[producer];
+ memset(hwdesc, 0, sizeof(struct cmd_desc_type0_t));
+ /* Take skb->data itself */
+ pbuf = &ctx->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,
+ ctx->max_tx_desc_count);
+ hwdesc = &ctx->hw_ring_ctx.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, ctx->max_tx_desc_count);
+
+ /* might change opcode to TX_TCP_LSO */
+ netxen_tso_check(adapter, &hw_ring_ctx->cmd_desc_head[saved_producer],
+ skb);
+
+ /* For LSO, we need to copy the MAC/IP/TCP headers into
+ * the descriptor ring
+ */
+ if (hw_ring_ctx->cmd_desc_head[saved_producer].opcode == TX_TCP_LSO) {
+ int hdr_len, first_hdr_len, more_hdr;
+ hdr_len =
+ hw_ring_ctx->cmd_desc_head[saved_producer].total_hdr_length;
+ if (hdr_len > (sizeof(struct cmd_desc_type0_t) - NET_IP_ALIGN)) {
+ first_hdr_len =
+ sizeof(struct cmd_desc_type0_t) - NET_IP_ALIGN;
+ 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_ring_ctx->cmd_desc_head[producer];
+
+ /* copy the first 64 bytes */
+ memcpy(((void *)hwdesc) + NET_IP_ALIGN,
+ (void *)(skb->data), first_hdr_len);
+ producer = get_next_index(producer, max_tx_desc_count);
+
+ if (more_hdr) {
+ hwdesc = &hw_ring_ctx->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_ring_ctx->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 = ctx->cmd_producer;
+ struct ctx_msg msg = { 0 };
+ hw_ring_ctx->cmd_producer = ctx->cmd_producer;
+ msg.PegId = NETXEN_XMIT_PEG_DB_ID;
+ msg.Count = crb_producer;
+ msg.CtxId = 0;
+ msg.Opcode = NETXEN_CMD_PRODUCER;
+ read_lock(&adapter->adapter_lock);
+ writel(*(u32 *) & msg,
+ DB_NORMALIZE(adapter, NETXEN_CMD_PRODUCER_OFFSET(0)));
+ read_unlock(&adapter->adapter_lock);
+
+ adapter->total_threads = 0;
+ } else {
+ u32 crb_producer = 0;
+ struct ctx_msg msg = { 0 };
+ read_lock(&adapter->adapter_lock);
+ *(u32 *) & msg =
+ readl(DB_NORMALIZE(adapter, NETXEN_CMD_PRODUCER_OFFSET(0)));
+ read_unlock(&adapter->adapter_lock);
+ crb_producer = msg.Count;
+
+ if (crb_producer == local_producer) {
+ crb_producer = get_index_range(crb_producer,
+ max_tx_desc_count,
+ no_of_desc);
+ msg.PegId = NETXEN_XMIT_PEG_DB_ID;
+ msg.Count = crb_producer;
+ msg.CtxId = 0;
+ msg.Opcode = NETXEN_CMD_PRODUCER;
+ read_lock(&adapter->adapter_lock);
+ writel(*(u32 *) & msg,
+ DB_NORMALIZE(adapter,
+ NETXEN_CMD_PRODUCER_OFFSET(0)));
+ read_unlock(&adapter->adapter_lock);
+
+ hw_ring_ctx->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 = &ctx->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 ctxid;
+ int this_work_done;
+
+ DPRINTK(INFO, "polling for %d descriptors\n", *budget);
+ port->stats.polled++;
+
+ adapter->work_done = 0;
+ for (ctxid = 0; ctxid < MAX_RING_CTX; ++ctxid) {
+ /*
+ * 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, ctxid,
+ work_to_do /
+ MAX_RING_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;
+
+ for (ctxid = 0; ctxid < MAX_RING_CTX; ++ctxid) {
+ netxen_process_cmd_ring((unsigned long)adapter, ctxid);
+ }
+
+ 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);
+
+ netxen_check_cmdline_params();
+ 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->port != NULL && adapter->port[0]->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
* [PATCH 9/9] NetXen 1G/10G ethernet driver patch with corrections
From: Linsys Contractor Amit S. Kale @ 2006-06-07 9:59 UTC (permalink / raw)
To: netdev; +Cc: sanjeev, unmproj
2006-06-07 Amit S. Kale <amitkale@unminc.com>
* Add netxen driver niu (hardware phy interface component)
handling routines
* Add netxen hardware CRB register definitions
diff -Naru linux-2.6.16.20.orig/drivers/net/netxen/netxen_nic_niu.c linux-2.6.16.20/drivers/net/netxen/netxen_nic_niu.c
--- linux-2.6.16.20.orig/drivers/net/netxen/netxen_nic_niu.c 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.16.20/drivers/net/netxen/netxen_nic_niu.c 2006-06-06 06:58:11.000000000 -0700
@@ -0,0 +1,761 @@
+/*
+ * 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
+ *
+ *
+ * Provides access to the Network Interface Unit h/w block.
+ *
+ */
+
+#include "netxen_nic.h"
+#include <linux/delay.h>
+
+/**
+ * netxen_niu_gbe_phy_read - read a register from the GbE PHY via
+ * mii management interface.
+ *
+ * Note: The MII management interface goes through port 0.
+ * Individual phys are addressed as follows:
+ * @param phy [15:8] phy id
+ * @param reg [7:0] register number
+ *
+ * @returns 0 on success
+ * -1 on error
+ *
+ **/
+long netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy,
+ long reg, netxen_crbword_t * readval)
+{
+ long timeout = 0;
+ long result = 0;
+ long restore = 0;
+ struct netxen_niu_gb_mii_mgmt_address address;
+ struct netxen_niu_gb_mii_mgmt_command command;
+ struct netxen_niu_gb_mii_mgmt_indicators status;
+ struct netxen_niu_gb_mii_mgmt_config mii_cfg;
+ struct netxen_niu_gb_mac_config_0_t mac_cfg0;
+
+ /* MII mgmt all goes through port 0 MAC interface, so it cannot be in reset */
+ if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0),
+ &mac_cfg0, 4))
+ return -EIO;
+ if (mac_cfg0.soft_reset) {
+ struct netxen_niu_gb_mac_config_0_t temp;
+ *(netxen_crbword_t *) & temp = 0;
+ temp.tx_reset_pb = 1;
+ temp.rx_reset_pb = 1;
+ temp.tx_reset_mac = 1;
+ temp.rx_reset_mac = 1;
+ if (netxen_nic_hw_write_wx(adapter,
+ NETXEN_NIU_GB_MAC_CONFIG_0(0),
+ &temp, 4))
+ return -EIO;
+ restore = 1;
+ }
+
+ /* reset MII management interface */
+ *(netxen_crbword_t *) & mii_cfg = 0;
+ mii_cfg.clockselect = 7;
+ mii_cfg.reset = 1;
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(0),
+ &mii_cfg, 4))
+ return -EIO;
+ mii_cfg.reset = 0;
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(0),
+ &mii_cfg, 4))
+ return -EIO;
+
+ *(netxen_crbword_t *) & address = 0;
+ address.reg_addr = reg;
+ address.phy_addr = phy;
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0),
+ &address, 4))
+ return -EIO;
+ *(netxen_crbword_t *) & command = 0; /* turn off any prior activity */
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0),
+ &command, 4))
+ return -EIO;
+ /* send read command */
+ command.read_cycle = 1;
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0),
+ &command, 4))
+ return -EIO;
+
+ *(netxen_crbword_t *) & status = 0;
+ do {
+ if (netxen_nic_hw_read_wx(adapter,
+ NETXEN_NIU_GB_MII_MGMT_INDICATE(0),
+ &status, 4))
+ return -EIO;
+ timeout++;
+ } while ((status.busy || status.notvalid)
+ && (timeout++ < NETXEN_NIU_PHY_WAITMAX));
+
+ if (timeout < NETXEN_NIU_PHY_WAITMAX) {
+ if (netxen_nic_hw_read_wx(adapter,
+ NETXEN_NIU_GB_MII_MGMT_STATUS(0),
+ readval, 4))
+ return -EIO;
+ result = 0;
+ } else
+ result = -1;
+
+ if (restore)
+ if (netxen_nic_hw_write_wx(adapter,
+ NETXEN_NIU_GB_MAC_CONFIG_0(0),
+ &mac_cfg0, 4))
+ return -EIO;
+
+ return result;
+}
+
+/**
+ * netxen_niu_gbe_phy_write - write a register to the GbE PHY via
+ * mii management interface.
+ *
+ * Note: The MII management interface goes through port 0.
+ * Individual phys are addressed as follows:
+ * @param phy [15:8] phy id
+ * @param reg [7:0] register number
+ *
+ * @returns 0 on success
+ * -1 on error
+ *
+ **/
+long netxen_niu_gbe_phy_write(struct netxen_adapter *adapter,
+ long phy, long reg, netxen_crbword_t val)
+{
+ long timeout = 0;
+ long result = 0;
+ long restore = 0;
+ struct netxen_niu_gb_mii_mgmt_address address;
+ struct netxen_niu_gb_mii_mgmt_command command;
+ struct netxen_niu_gb_mii_mgmt_indicators status;
+ struct netxen_niu_gb_mac_config_0_t mac_cfg0;
+
+ /* MII mgmt all goes through port 0 MAC interface, so it cannot be in reset */
+ if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(0),
+ &mac_cfg0, 4))
+ return -EIO;
+ if (mac_cfg0.soft_reset) {
+ struct netxen_niu_gb_mac_config_0_t temp;
+ *(netxen_crbword_t *) & temp = 0;
+ temp.tx_reset_pb = 1;
+ temp.rx_reset_pb = 1;
+ temp.tx_reset_mac = 1;
+ temp.rx_reset_mac = 1;
+ if (netxen_nic_hw_write_wx(adapter,
+ NETXEN_NIU_GB_MAC_CONFIG_0(0),
+ &temp, 4))
+ return -EIO;
+ restore = 1;
+ }
+
+ *(netxen_crbword_t *) & command = 0; /* turn off any prior activity */
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_COMMAND(0),
+ &command, 4))
+ return -EIO;
+
+ *(netxen_crbword_t *) & address = 0;
+ address.reg_addr = reg;
+ address.phy_addr = phy;
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_ADDR(0),
+ &address, 4))
+ return -EIO;
+
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_CTRL(0),
+ &val, 4))
+ return -EIO;
+
+ *(netxen_crbword_t *) & status = 0;
+ do {
+ if (netxen_nic_hw_read_wx(adapter,
+ NETXEN_NIU_GB_MII_MGMT_INDICATE(0),
+ &status, 4))
+ return -EIO;
+ timeout++;
+ } while ((status.busy) && (timeout++ < NETXEN_NIU_PHY_WAITMAX));
+
+ if (timeout < NETXEN_NIU_PHY_WAITMAX)
+ result = 0;
+ else
+ result = -EIO;
+
+ /* restore the state of port 0 MAC in case we tampered with it */
+ if (restore)
+ if (netxen_nic_hw_write_wx(adapter,
+ NETXEN_NIU_GB_MAC_CONFIG_0(0),
+ &mac_cfg0, 4))
+ return -EIO;
+
+ return result;
+}
+
+long netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter,
+ long port)
+{
+ long result = 0;
+ struct netxen_niu_phy_interrupt enable;
+ *(netxen_crbword_t *) & enable = 0;
+ enable.link_status_changed = 1;
+ enable.autoneg_completed = 1;
+ enable.speed_changed = 1;
+
+ if (0 !=
+ netxen_niu_gbe_phy_write(adapter, port,
+ NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE,
+ *(netxen_crbword_t *) & enable))
+ result = -EIO;
+
+ return result;
+}
+
+long netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter,
+ long port)
+{
+ long result = 0;
+ if (0 !=
+ netxen_niu_gbe_phy_write(adapter, port,
+ NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, 0))
+ result = -EIO;
+
+ return result;
+}
+
+long netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter,
+ long port)
+{
+ long result = 0;
+ if (0 !=
+ netxen_niu_gbe_phy_write(adapter, port,
+ NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
+ -EIO))
+ result = -EIO;
+
+ return result;
+}
+
+/**
+ * netxen_niu_gbe_set_mii_mode- Set 10/100 Mbit Mode for GbE MAC
+ *
+ **/
+void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter,
+ long port, long enable)
+{
+ netxen_crb_writelit_adapter(adapter, NETXEN_NIU_MODE, 0x2);
+ netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
+ 0x80000000);
+ netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
+ 0x0000f0025);
+ netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port),
+ 0xf1ff);
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_NIU_GB0_GMII_MODE + (port << 3), 0);
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_NIU_GB0_MII_MODE + (port << 3), 1);
+ netxen_crb_writelit_adapter(adapter,
+ (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0);
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7);
+
+ if (enable) {
+ /*
+ * Do NOT enable flow control until a suitable solution for
+ * shutting down pause frames is found.
+ */
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_NIU_GB_MAC_CONFIG_0(port),
+ 0x5);
+ }
+
+ if (netxen_niu_gbe_enable_phy_interrupts(adapter, port))
+ printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n");
+ if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+ printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n");
+}
+
+/**
+ * netxen_niu_gbe_set_gmii_mode- Set GbE Mode for GbE MAC
+ **/
+void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter,
+ long port, long enable)
+{
+ netxen_crb_writelit_adapter(adapter, NETXEN_NIU_MODE, 0x2);
+ netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
+ 0x80000000);
+ netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
+ 0x0000f0025);
+ netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB_MAC_CONFIG_1(port),
+ 0xf2ff);
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_NIU_GB0_MII_MODE + (port << 3), 0);
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_NIU_GB0_GMII_MODE + (port << 3), 1);
+ netxen_crb_writelit_adapter(adapter,
+ (NETXEN_NIU_GB0_HALF_DUPLEX + port * 4), 0);
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_NIU_GB_MII_MGMT_CONFIG(port), 0x7);
+
+ if (enable) {
+ /*
+ * Do NOT enable flow control until a suitable solution for
+ * shutting down pause frames is found.
+ */
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_NIU_GB_MAC_CONFIG_0(port),
+ 0x5);
+ }
+
+ if (netxen_niu_gbe_enable_phy_interrupts(adapter, port))
+ printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n");
+ if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+ printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n");
+}
+
+long netxen_niu_gbe_init_port(struct netxen_adapter *adapter, long port)
+{
+ long result = 0;
+ struct netxen_niu_phy_status status;
+
+ if (0 ==
+ netxen_niu_gbe_phy_read(adapter, port,
+ NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
+ (netxen_crbword_t *) & status)) {
+ if (status.link) {
+ if (status.speed == 2) {
+ netxen_niu_gbe_set_gmii_mode(adapter, port, 1);
+ } else if ((status.speed == 1) || (status.speed == 0)) {
+ netxen_niu_gbe_set_mii_mode(adapter, port, 1);
+ } else {
+ result = -1;
+ }
+
+ } else {
+ /* We don't have link. Cable must be unconnected. */
+ /* Enable phy interrupts so we take action when plugged in */
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_NIU_GB_MAC_CONFIG_0
+ (port), 0x80000000);
+ netxen_crb_writelit_adapter(adapter,
+ NETXEN_NIU_GB_MAC_CONFIG_0
+ (port), 0x0000f0025);
+ if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+ printk(KERN_ERR PFX
+ "ERROR clearing PHY interrupts\n");
+ if (netxen_niu_gbe_enable_phy_interrupts(adapter, port))
+ printk(KERN_ERR PFX
+ "ERROR enabling PHY interrupts\n");
+ if (netxen_niu_gbe_clear_phy_interrupts(adapter, port))
+ printk(KERN_ERR PFX
+ "ERROR clearing PHY interrupts\n");
+ result = -1;
+ }
+ } else {
+ result = -EIO;
+ }
+ return result;
+}
+
+/**
+ * netxen_niu_gbe_handle_phy_interrupt - Handles GbE PHY interrupts
+ * @param enable 0 means don't enable the port
+ * 1 means enable (or re-enable) the port
+ **/
+long netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter,
+ long port, long enable)
+{
+ long result = 0;
+ struct netxen_niu_phy_interrupt int_src;
+
+ printk(KERN_INFO PFX "NETXEN: Handling PHY interrupt on port %d"
+ " (device enable = %d)\n", (int)port, (int)enable);
+
+ /* The read of the PHY INT status will clear the pending interrupt status */
+ if (netxen_niu_gbe_phy_read(adapter, port,
+ NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
+ (netxen_crbword_t *) & int_src) != 0)
+ result = -EINVAL;
+ else {
+ printk(KERN_INFO PFX "PHY Interrupt source = 0x%x \n",
+ *(u32 *) & int_src);
+ if (int_src.jabber)
+ printk(KERN_INFO PFX "jabber Interrupt ");
+ if (int_src.polarity_changed)
+ printk(KERN_INFO PFX "polarity changed ");
+ if (int_src.energy_detect)
+ printk(KERN_INFO PFX "energy detect \n");
+ if (int_src.downshift)
+ printk(KERN_INFO PFX "downshift \n");
+ if (int_src.mdi_xover_changed)
+ printk(KERN_INFO PFX "mdi_xover_changed ");
+ if (int_src.fifo_over_underflow)
+ printk(KERN_INFO PFX "fifo_over_underflow ");
+ if (int_src.false_carrier)
+ printk(KERN_INFO PFX "false_carrier ");
+ if (int_src.symbol_error)
+ printk(KERN_INFO PFX "symbol_error ");
+ if (int_src.autoneg_completed)
+ printk(KERN_INFO PFX "autoneg_completed ");
+ if (int_src.page_received)
+ printk(KERN_INFO PFX "page_received ");
+ if (int_src.duplex_changed)
+ printk(KERN_INFO PFX "duplex_changed ");
+ if (int_src.autoneg_error)
+ printk(KERN_INFO PFX "autoneg_error ");
+ if ((int_src.speed_changed) || (int_src.link_status_changed)) {
+ struct netxen_niu_phy_status status;
+
+ printk(KERN_INFO PFX
+ "speed_changed or link status changed");
+ if (netxen_niu_gbe_phy_read
+ (adapter, port,
+ NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
+ (netxen_crbword_t *) & status) == 0) {
+ if (status.speed == 2) {
+ printk
+ (KERN_INFO PFX "Link speed changed"
+ " to 1000 Mbps\n");
+ netxen_niu_gbe_set_gmii_mode(adapter,
+ port,
+ enable);
+ } else if (status.speed == 1) {
+ printk
+ (KERN_INFO PFX "Link speed changed"
+ " to 100 Mbps\n");
+ netxen_niu_gbe_set_mii_mode(adapter,
+ port,
+ enable);
+ } else if (status.speed == 0) {
+ printk
+ (KERN_INFO PFX "Link speed changed"
+ " to 10 Mbps\n");
+ netxen_niu_gbe_set_mii_mode(adapter,
+ port,
+ enable);
+ } else {
+ printk(KERN_ERR PFX "ERROR reading"
+ "PHY status. Illegal speed.\n");
+ result = -1;
+ }
+ } else {
+ printk(KERN_ERR PFX
+ "ERROR reading PHY status.\n");
+ result = -1;
+ }
+
+ }
+ printk(KERN_INFO "\n");
+ }
+ return result;
+}
+
+/**
+ * Return the current station MAC address.
+ * Note that the passed-in value must already be in network byte order.
+ **/
+int netxen_niu_macaddr_get(struct netxen_adapter *adapter,
+ int phy, netxen_ethernet_macaddr_t * addr)
+{
+ u64 result = 0;
+ struct netxen_niu_gb_station_address_high stationhigh;
+ struct netxen_niu_gb_station_address_low stationlow;
+
+ if (addr == NULL)
+ return -EINVAL;
+ if ((phy < 0) || (phy > 3))
+ return -EINVAL;
+
+ if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy),
+ &stationhigh, 4))
+ return -EIO;
+ if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy),
+ &stationlow, 4))
+ return -EIO;
+
+ result = (u64) stationlow.address;
+ result |= (u64) stationhigh.address << 16;
+ memcpy(*addr, &result, sizeof(netxen_ethernet_macaddr_t));
+
+ return 0;
+}
+
+/**
+ * Set the station MAC address.
+ * Note that the passed-in value must already be in network byte order.
+ **/
+int netxen_niu_macaddr_set(struct netxen_adapter *adapter, int phy,
+ netxen_ethernet_macaddr_t addr)
+{
+ netxen_crbword_t temp = 0;
+
+ if ((phy < 0) || (phy > 3))
+ return -EINVAL;
+
+ memcpy(&temp, addr, 2);
+ temp <<= 16;
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_STATION_ADDR_1(phy),
+ &temp, 4))
+ return -EIO;
+
+ temp = 0;
+
+ memcpy(&temp, ((u8 *) addr) + 2, sizeof(netxen_crbword_t));
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy),
+ &temp, 4))
+ return -2;
+
+ return 0;
+}
+
+/* Enable a GbE interface */
+long netxen_niu_enable_gbe_port(struct netxen_adapter *adapter,
+ long port, netxen_niu_gbe_ifmode_t mode)
+{
+ struct netxen_niu_gb_mac_config_0_t mac_cfg0;
+ struct netxen_niu_gb_mac_config_1_t mac_cfg1;
+ struct netxen_niu_gb_mii_mgmt_config mii_cfg;
+
+ if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+ return -EINVAL;
+
+ *(netxen_crbword_t *) & mac_cfg0 = 0;
+ mac_cfg0.soft_reset = 1;
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
+ &mac_cfg0, 4))
+ return -EIO;
+ *(netxen_crbword_t *) & mac_cfg0 = 0;
+ mac_cfg0.tx_enable = 1;
+ mac_cfg0.rx_enable = 1;
+ mac_cfg0.rx_flowctl = 0;
+ mac_cfg0.tx_reset_pb = 1;
+ mac_cfg0.rx_reset_pb = 1;
+ mac_cfg0.tx_reset_mac = 1;
+ mac_cfg0.rx_reset_mac = 1;
+
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
+ &mac_cfg0, 4))
+ return -EIO;
+ *(netxen_crbword_t *) & mac_cfg1 = 0;
+ mac_cfg1.preamblelen = 0xf;
+ mac_cfg1.duplex = 1;
+ mac_cfg1.crc_enable = 1;
+ mac_cfg1.padshort = 1;
+ mac_cfg1.checklength = 1;
+ mac_cfg1.hugeframes = 1;
+
+ if (mode == NETXEN_NIU_10_100_MB) {
+ mac_cfg1.intfmode = 1;
+ if (netxen_nic_hw_write_wx(adapter,
+ NETXEN_NIU_GB_MAC_CONFIG_1(port),
+ &mac_cfg1, 4))
+ return -EIO;
+
+ /* set mii mode */
+ netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB0_GMII_MODE +
+ (port << 3), 0);
+ netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB0_MII_MODE +
+ (port << 3), 1);
+
+ } else if (mode == NETXEN_NIU_1000_MB) {
+ mac_cfg1.intfmode = 2;
+ if (netxen_nic_hw_write_wx(adapter,
+ NETXEN_NIU_GB_MAC_CONFIG_1(port),
+ &mac_cfg1, 4))
+ return -EIO;
+ /* set gmii mode */
+ netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB0_MII_MODE +
+ (port << 3), 0);
+ netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB0_GMII_MODE +
+ (port << 3), 1);
+ }
+ *(netxen_crbword_t *) & mii_cfg = 0;
+ mii_cfg.clockselect = 7;
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(port),
+ &mii_cfg, 4))
+ return -EIO;
+
+ *(netxen_crbword_t *) & mac_cfg0 = 0;
+ mac_cfg0.tx_enable = 1;
+ mac_cfg0.rx_enable = 1;
+ mac_cfg0.tx_flowctl = 0;
+ mac_cfg0.rx_flowctl = 0;
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
+ &mac_cfg0, 4))
+ return -EIO;
+ return 0;
+}
+
+/* Disable a GbE interface */
+long netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, long port)
+{
+ struct netxen_niu_gb_mac_config_0_t mac_cfg0;
+
+ if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+ return -EINVAL;
+
+ *(netxen_crbword_t *) & mac_cfg0 = 0;
+ mac_cfg0.soft_reset = 1;
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
+ &mac_cfg0, 4))
+ return -EIO;
+ return 0;
+}
+
+/* Disable an XG interface */
+long netxen_niu_disable_xg_port(struct netxen_adapter *adapter, long port)
+{
+ struct netxen_niu_xg_mac_config_0_t mac_cfg;
+
+ if (port != 0)
+ return -EINVAL;
+
+ *(netxen_crbword_t *) & mac_cfg = 0;
+ mac_cfg.soft_reset = 1;
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_CONFIG_0,
+ &mac_cfg, 4))
+ return -EIO;
+ return 0;
+}
+
+/* Set promiscuous mode for a GbE interface */
+long netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, long port,
+ netxen_niu_prom_mode_t mode)
+{
+ struct netxen_niu_gb_drop_crc reg;
+ long data;
+
+ if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+ return -EINVAL;
+
+ if (mode == NETXEN_NIU_PROMISCOUS_MODE)
+ data = 0;
+ else
+ data = 1;
+
+ /* save previous contents */
+ if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_GB_DROP_WRONGADDR,
+ ®, 4))
+ return -EIO;
+ switch (port) {
+ case 0:
+ reg.drop_gb0 = data;
+ break;
+ case 1:
+ reg.drop_gb0 = data;
+ break;
+ case 2:
+ reg.drop_gb0 = data;
+ break;
+ case 3:
+ reg.drop_gb0 = data;
+ break;
+ default:
+ return -EIO;
+ }
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_DROP_WRONGADDR,
+ ®, 4))
+ return -EIO;
+ return 0;
+}
+
+/**
+ * Set the MAC address for an XG port
+ * Note that the passed-in value must already be in network byte order.
+ **/
+int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter, int phy,
+ netxen_ethernet_macaddr_t addr)
+{
+ netxen_crbword_t temp = 0;
+
+ if ((phy < 0) || (phy > 3))
+ return -EINVAL;
+
+ memcpy(&temp, addr, 2);
+ temp <<= 16;
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1,
+ &temp, 4))
+ return -EIO;
+
+ temp = 0;
+
+ memcpy(&temp, ((u8 *) addr) + 2, sizeof(netxen_crbword_t));
+ if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI,
+ &temp, 4))
+ return -EIO;
+
+ return 0;
+}
+
+/**
+ * Return the current station MAC address.
+ * Note that the passed-in value must already be in network byte order.
+ **/
+int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy,
+ netxen_ethernet_macaddr_t * addr)
+{
+ netxen_crbword_t stationhigh;
+ netxen_crbword_t stationlow;
+ u64 result;
+
+ if (addr == NULL)
+ return -EINVAL;
+ if (phy != 0)
+ return -EINVAL;
+
+ if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI,
+ &stationhigh, 4))
+ return -EIO;
+ if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1,
+ &stationlow, 4))
+ return -EIO;
+
+ result = ((u64) stationlow) >> 16;
+ result |= (u64) stationhigh << 16;
+ memcpy(*addr, &result, sizeof(netxen_ethernet_macaddr_t));
+
+ return 0;
+}
+
+long netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter,
+ long port, netxen_niu_prom_mode_t mode)
+{
+ long reg;
+
+ if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
+ return -EINVAL;
+
+ if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_XGE_CONFIG_1, ®, 4))
+ return -EIO;
+ if (mode == NETXEN_NIU_PROMISCOUS_MODE)
+ reg = (reg | 0x2000UL);
+ else
+ reg = (reg & ~0x2000UL);
+
+ netxen_crb_writelit_adapter(adapter, NETXEN_NIU_XGE_CONFIG_1, reg);
+
+ return 0;
+}
diff -Naru linux-2.6.16.20.orig/drivers/net/netxen/netxen_nic_phan_reg.h linux-2.6.16.20/drivers/net/netxen/netxen_nic_phan_reg.h
--- linux-2.6.16.20.orig/drivers/net/netxen/netxen_nic_phan_reg.h 1969-12-31 16:00:00.000000000 -0800
+++ linux-2.6.16.20/drivers/net/netxen/netxen_nic_phan_reg.h 2006-06-06 06:58:11.000000000 -0700
@@ -0,0 +1,293 @@
+/*
+ * 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
+ */
+
+#ifndef __NIC_PHAN_REG_H_
+#define __NIC_PHAN_REG_H_
+
+/**
+ * CRB Registers or queue message done only at initialization time....
+ **/
+
+/**
+ * The following 2 are the base adresses for the CRB registers and their
+ * offsets will be added to get addresses for the index addresses.......
+ **/
+#define NIC_CRB_BASE_PORT1 NETXEN_CAM_RAM(0x200)
+#define NIC_CRB_BASE_PORT2 NETXEN_CAM_RAM(0x250)
+
+#define NETXEN_NIC_REG(X) (NIC_CRB_BASE_PORT1+(X))
+
+/**
+ * CrbPortPhanCntrHi/Lo is used to pass the address of HostPhantomIndex address
+ * which can be read by the Phantom host to get producer/consumer indexes from
+ * Phantom/Casper. If it is not HOST_SHARED_MEMORY, then the following
+ * registers will be used for the addresses of the ring's shared memory
+ * on the Phantom.
+ **/
+
+#define CRB_PHAN_CNTRL_LO_OFFSET NETXEN_NIC_REG(0x00)
+#define CRB_PHAN_CNTRL_HI_OFFSET NETXEN_NIC_REG(0x04)
+
+/* point to the indexes */
+#define CRB_CMD_PRODUCER_OFFSET NETXEN_NIC_REG(0x08)
+#define CRB_CMD_CONSUMER_OFFSET NETXEN_NIC_REG(0x0c)
+
+/* address of command descriptors in the host memory */
+#define CRB_HOST_CMD_ADDR_HI NETXEN_NIC_REG(0x30)
+#define CRB_HOST_CMD_ADDR_LO NETXEN_NIC_REG(0x34)
+
+/* The following 4 CRB registers are for doing performance coal */
+#define CRB_CMD_INTR_LOOP NETXEN_NIC_REG(0x38)
+#define CRB_CMD_DMA_LOOP NETXEN_NIC_REG(0x3c)
+#define CRB_RCV_INTR_LOOP NETXEN_NIC_REG(0x40)
+#define CRB_RCV_DMA_LOOP NETXEN_NIC_REG(0x44)
+
+/* Needed by the host to find out the state of Phantom's initialization */
+#define CRB_ENABLE_TX_INTR NETXEN_NIC_REG(0x4c)
+#define CRB_CMDPEG_STATE NETXEN_NIC_REG(0x50)
+#define CRB_CMDPEG_CMDRING NETXEN_NIC_REG(0x54)
+
+/* Interrupt coalescing parameters */
+#define CRB_GLOBAL_INT_COAL NETXEN_NIC_REG(0x80)
+#define CRB_INT_COAL_MODE NETXEN_NIC_REG(0x84)
+#define CRB_MAX_RCV_BUFS NETXEN_NIC_REG(0x88)
+#define CRB_TX_INT_THRESHOLD NETXEN_NIC_REG(0x8c)
+#define CRB_RX_PKT_TIMER NETXEN_NIC_REG(0x90)
+#define CRB_TX_PKT_TIMER NETXEN_NIC_REG(0x94)
+#define CRB_RX_PKT_CNT NETXEN_NIC_REG(0x98)
+#define CRB_RX_TMR_CNT NETXEN_NIC_REG(0x9c)
+
+/* Register for communicating XG link status */
+#define CRB_XG_STATE NETXEN_NIC_REG(0xa0)
+
+/* Debug registers for controlling NIC pkt gen agent */
+#define CRB_AGENT_GO NETXEN_NIC_REG(0xb0)
+#define CRB_AGENT_TX_SIZE NETXEN_NIC_REG(0xb4)
+#define CRB_AGENT_TX_TYPE NETXEN_NIC_REG(0xb8)
+#define CRB_AGENT_TX_ADDR NETXEN_NIC_REG(0xbc)
+#define CRB_AGENT_TX_MSS NETXEN_NIC_REG(0xc0)
+
+/* Debug registers for observing NIC performance */
+#define CRB_TX_STATE NETXEN_NIC_REG(0xd0)
+#define CRB_TX_COUNT NETXEN_NIC_REG(0xd4)
+#define CRB_RX_STATE NETXEN_NIC_REG(0xd8)
+#define CRB_CMD_RING_SIZE NETXEN_NIC_REG(0xe0)
+#define CRB_CTX_ADDR_REG NETXEN_NIC_REG(0xd0)
+#define CRB_CTX_SIGNATURE_REG NETXEN_NIC_REG(0xd4)
+
+#define NETXEN_CMD_PRODUCER_DB_PAGE(ctx) ((ctx) * 4)
+#define NETXEN_RCV_STATUS_CONSUMER_DB_PAGE(ctx) (1 + ((ctx) * 4))
+#define NETXEN_RCV_PRODUCER_DB_PAGE(ctx,ring) (2 + (ring) + ((ctx) * 4))
+
+/* CRB registers per Rcv Descriptor ring */
+struct netxen_rcv_desc_crb {
+ u32 crb_rcv_producer_offset __attribute__ ((aligned(512)));
+ u32 crb_rcv_consumer_offset;
+ u32 crb_globalrcv_ring;
+ u32 crb_rcv_ring_size;
+};
+
+/*
+ * CRB registers used by the receive peg logic. One instance of these
+ * needs to be instantiated per instance of the receive peg.
+ */
+
+struct netxen_recv_crb {
+ struct netxen_rcv_desc_crb rcv_desc_crb[NUM_RCV_DESC_RINGS];
+ u32 crb_rcvstatus_ring;
+ u32 crb_rcv_status_producer;
+ u32 crb_rcv_status_consumer;
+ u32 crb_rcvpeg_state;
+ u32 crb_status_ring_size;
+};
+
+#if defined(DEFINE_GLOBAL_RECV_CRB)
+struct netxen_recv_crb recv_crb_registers[] = {
+ /*
+ * Instance 0.
+ */
+ {
+ /* rcv_desc_crb: */
+ {
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x18),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x1c),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x20),
+ /* crb_rcv_ring_size: */
+ NETXEN_NIC_REG(0xe4),
+ },
+ /* Jumbo frames */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x100),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x104),
+ /* crb_gloablrcv_ring: */
+ NETXEN_NIC_REG(0x108),
+ /* crb_rcv_ring_size: */
+ NETXEN_NIC_REG(0xe8),
+ }
+ },
+ /* crb_rcvstatus_ring: */
+ NETXEN_NIC_REG(0x24),
+ /* crb_rcv_status_producer: */
+ NETXEN_NIC_REG(0x28),
+ /* crb_rcv_status_consumer: */
+ NETXEN_NIC_REG(0x2c),
+ /* crb_rcvpeg_state: */
+ NETXEN_NIC_REG(0x48),
+ /* crb_status_ring_size: */
+ NETXEN_NIC_REG(0xec),
+ },
+ /*
+ * Instance 1,
+ */
+ {
+ /* rcv_desc_crb: */
+ {
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x80),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x84),
+ /* crb_globalrcv_ring: */
+ NETXEN_NIC_REG(0x88),
+ /* crb_rcv_ring_size: */
+ NETXEN_NIC_REG(0xf0),
+ },
+ /* Jumbo frames */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x10C),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x110),
+ /* crb_globalrcv_ring: */
+ NETXEN_NIC_REG(0x114),
+ /* crb_rcv_ring_size: */
+ NETXEN_NIC_REG(0xf4),
+ }
+ },
+ /* crb_rcvstatus_ring: */
+ NETXEN_NIC_REG(0x8c),
+ /* crb_rcv_status_producer: */
+ NETXEN_NIC_REG(0x90),
+ /* crb_rcv_status_consumer: */
+ NETXEN_NIC_REG(0x94),
+ /* crb_rcvpeg_state: */
+ NETXEN_NIC_REG(0x98),
+ /* crb_status_ring_size: */
+ NETXEN_NIC_REG(0xf8),
+ },
+ /*
+ * Instance 2.
+ */
+ {
+ /* rcv_desc_crb: */
+ {
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x18),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x1c),
+ /* crb_globalrcv_ring: */
+ NETXEN_NIC_REG(0x20),
+ /* crb_rcv_ring_size: */
+ NETXEN_NIC_REG(0xe4),
+ },
+ /* Jumbo frames */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x100),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x104),
+ /* crb_globalrcv_ring: */
+ NETXEN_NIC_REG(0x108),
+ /* crb_rcv_ring_size: */
+ NETXEN_NIC_REG(0xe8),
+ }
+ },
+ /* crb_rcvstatus_ring: */
+ NETXEN_NIC_REG(0x24),
+ /* crb_rcv_status_producer: */
+ NETXEN_NIC_REG(0x28),
+ /* crb_rcv_status_consumer: */
+ NETXEN_NIC_REG(0x2c),
+ /* crb_rcvpeg_state: */
+ NETXEN_NIC_REG(0x48),
+ /* crb_status_ring_size: */
+ NETXEN_NIC_REG(0xec),
+ },
+ /*
+ * Instance 3,
+ */
+ {
+ /* rcv_desc_crb: */
+ {
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x80),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x84),
+ /* crb_globalrcv_ring: */
+ NETXEN_NIC_REG(0x88),
+ /* crb_rcv_ring_size: */
+ NETXEN_NIC_REG(0xf0),
+ },
+ /* Jumbo frames */
+ {
+ /* crb_rcv_producer_offset: */
+ NETXEN_NIC_REG(0x10C),
+ /* crb_rcv_consumer_offset: */
+ NETXEN_NIC_REG(0x110),
+ /* crb_globalrcv_ring: */
+ NETXEN_NIC_REG(0x114),
+ /* crb_rcv_ring_size: */
+ NETXEN_NIC_REG(0xf4),
+ }
+ },
+ /* crb_rcvstatus_ring: */
+ NETXEN_NIC_REG(0x8c),
+ /* crb_rcv_status_producer: */
+ NETXEN_NIC_REG(0x90),
+ /* crb_rcv_status_consumer: */
+ NETXEN_NIC_REG(0x94),
+ /* crb_rcvpeg_state */
+ NETXEN_NIC_REG(0x98),
+ /* crb_status_ring_size: */
+ NETXEN_NIC_REG(0xf8),
+ },
+};
+#else
+extern struct netxen_recv_crb recv_crb_registers[];
+#endif /* DEFINE_GLOBAL_RECEIVE_CRB */
+
+#endif /* __NIC_PHAN_REG_H_ */
^ permalink raw reply
* Re: [PATCH] Right prototype of __raw_v4_lookup()
From: Alexey Dobriyan @ 2006-06-07 11:38 UTC (permalink / raw)
To: David Miller; +Cc: netdev
In-Reply-To: <20060605.210707.39159307.davem@davemloft.net>
On Mon, Jun 05, 2006 at 09:07:07PM -0700, David Miller wrote:
> From: Alexey Dobriyan <adobriyan@gmail.com>
> Date: Sun, 28 May 2006 01:09:32 +0400
>
> > All users pass 32-bit values as addresses and internally they're compared with
> > 32-bit entities. So, change "laddr" and "raddr" types to __be32.
> Applied.
>
> Doesn't this mean that, at least eventually, we should change
> the address members of inet_sock to __be32 as well?
I think, yes. Al Viro is sitting on terabytes of endian annotations in
networking code. See net-endian.b* branches at
git://git.kernel.org/pub/scm/linux/kernel/git/viro/bird.git
I don't know if he considers them ready.
^ permalink raw reply
* Re: Problem authenticating using WPA with bcm43xx-softmac
From: Johannes Berg @ 2006-06-07 12:10 UTC (permalink / raw)
To: Larry Finger; +Cc: netdev
In-Reply-To: <4485D66B.7080108@lwfinger.net>
[-- Attachment #1: Type: text/plain, Size: 490 bytes --]
On Tue, 2006-06-06 at 14:24 -0500, Larry Finger wrote:
> Jun 6 13:34:10 larrylap kernel: SoftMAC: generic IE set to
> ffffffdd160050fffffff20101000050fffffff20201000050fffffff20201000050fffffff202
> Why does SoftMAC set a generic IE rather than get one from wpa_supplicant? I would appreciate help
> with this problem.
generic IE is what the wext is called, it is the IE that wpa_supplicant
sets. Not sure what's going on though, I know next to nothing about wpa.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 793 bytes --]
^ permalink raw reply
* [patch] workaround zd1201 interference problem
From: Pavel Machek @ 2006-06-07 14:00 UTC (permalink / raw)
To: linville, kernel list, netdev, Jirka Lenost Benc
zd1201 likes to start up shouting, interfering with all wifis in
range. It is capable of stopping ipw2200 up-to few meters away, and
stops other cards at smaller distances, too.
This works around it. Only forcing ZD1201_CMDCODE_DISABLE is not
enough to prevent interference.
From: Jirka Benc <jbenc@suse.cz>
Signed-off-by: Pavel Machek <pavel@suse.cz>
--- linux-good/drivers/net/wireless/zd1201.c 2006-03-30 13:51:58.000000000 +0200
+++ linux/drivers/net/wireless/zd1201.c 2006-06-07 15:55:01.000000000 +0200
@@ -1835,6 +1835,8 @@
zd->dev->name);
usb_set_intfdata(interface, zd);
+ zd1201_enable(zd); /* zd1201 likes to startup shouting, interfering */
+ zd1201_disable(zd); /* with all the wifis in range */
return 0;
err_net:
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
* Re: [patch] workaround zd1201 interference problem
From: Jiri Benc @ 2006-06-07 14:08 UTC (permalink / raw)
To: Pavel Machek; +Cc: linville, kernel list, netdev
In-Reply-To: <20060607140045.GB1936@elf.ucw.cz>
On Wed, 7 Jun 2006 16:00:45 +0200, Pavel Machek wrote:
> + zd1201_enable(zd); /* zd1201 likes to startup shouting, interfering */
> + zd1201_disable(zd); /* with all the wifis in range */
I would prefer to track it down and find out where exactly is the
problem instead of this quick hack.
Jiri
--
Jiri Benc
SUSE Labs
^ permalink raw reply
* Re: [patch] workaround zd1201 interference problem
From: Pavel Machek @ 2006-06-07 14:15 UTC (permalink / raw)
To: Jiri Benc; +Cc: linville, kernel list, netdev
In-Reply-To: <20060607160828.0045e7f5@griffin.suse.cz>
On St 07-06-06 16:08:28, Jiri Benc wrote:
> On Wed, 7 Jun 2006 16:00:45 +0200, Pavel Machek wrote:
> > + zd1201_enable(zd); /* zd1201 likes to startup shouting, interfering */
> > + zd1201_disable(zd); /* with all the wifis in range */
>
> I would prefer to track it down and find out where exactly is the
> problem instead of this quick hack.
Well, I'll try _enable() alone, but it seems to me that _enable()
command is needed to initialize radio properly. I do not think we can
get much further without firmware sources...
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
* Re: [PATCH 3/4] Make Intel e1000 driver legacy I/O port free
From: Auke Kok @ 2006-06-07 14:40 UTC (permalink / raw)
To: Kenji Kaneshige
Cc: Auke Kok, Greg KH, akpm, Rajesh Shah, Grant Grundler, bibo,mao,
linux-kernel, linux-pci, netdev, Jesse Brandeburg, Ronciak, John
In-Reply-To: <448682B6.5010302@jp.fujitsu.com>
Kenji Kaneshige wrote:
> Auke Kok wrote:
>> Kenji Kaneshige wrote:
>>
>>> This patch makes Intel e1000 driver legacy I/O port free.
>>>
>>> Signed-off-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
>>
>> (adding netdev and the other e1000 maintainers to cc:)
>>
>> without sending this to any of the listed e1000 maintainers???? *and*
>> not even including netdev???
>>
>
> I'm sorry about that.
I also didn't see that you were sending this to Greg-KH. I think I got thrown
off by that as I wasn't following lkml until yesterday in the first place.
I'll toss the patches around over here and see what comes up.
Cheers,
Auke
^ permalink raw reply
* Re: [PATCH 1/2] e1000: fix netpoll with NAPI
From: Neil Horman @ 2006-06-07 15:05 UTC (permalink / raw)
To: Matt Mackall
Cc: Jeff Moyer, Auke Kok, Garzik, Jeff, Mitch Williams, netdev,
Brandeburg, Jesse, Kok, Auke
In-Reply-To: <20060606231727.GK24227@waste.org>
>
> > Matt, any ideas on this?
>
> Not at the moment.
how about this for a solution? It doesn't make netpoll any more robust, but I
think in the interests of efficiency it would be fair to require that, when
netpolled, a driver must receive frames on the same net device for which it was
polled. With this patch we detect that condition and handle it accordingly in
e1000_intr. This eliminates the need for us to call the clean_rx method from
the poll_controller when napi is configured, instead allowing the poll method to
be called from napi_poll, as the netpoll model currently does. This fixes the
netdump regression, and eliminates the layering violation and the potential race
that we've been discussing. I've just tested it with netdump here and it works
quite well.
Thoughts appreciated.
Thanks & Regards
Neil
Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
e1000_main.c | 54 +++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 45 insertions(+), 9 deletions(-)
--- linux-2.6.9/drivers/net/e1000/e1000_main.c.neil 2006-06-06 10:37:42.000000000 -0400
+++ linux-2.6.9/drivers/net/e1000/e1000_main.c 2006-06-07 10:48:22.000000000 -0400
@@ -3207,8 +3207,9 @@
* @pt_regs: CPU registers structure
**/
+
static irqreturn_t
-e1000_intr(int irq, void *data, struct pt_regs *regs)
+__e1000_intr(int irq, void *data, struct pt_regs *regs, int netpoll_op)
{
struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -3217,6 +3218,7 @@
#ifndef CONFIG_E1000_NAPI
int i;
#else
+ struct net_device *dev_to_sched;
/* Interrupt Auto-Mask...upon reading ICR,
* interrupts are masked. No need for the
* IMC write, but it does mean we should
@@ -3255,8 +3257,22 @@
E1000_WRITE_REG(hw, IMC, ~0);
E1000_WRITE_FLUSH(hw);
}
- if (likely(netif_rx_schedule_prep(&adapter->polling_netdev[0])))
- __netif_rx_schedule(&adapter->polling_netdev[0]);
+
+ /*
+ * netpoll operations, in the interests of efficiency
+ * only do napi polling on the device passed to the
+ * poll_controller. Therefore, if we are preforming
+ * a netpoll operation, then we can't schedule a receive
+ * to one of the dummy net devices that exist for sole
+ * purpose of spreading out rx schedules
+ */
+ if (netpoll_op)
+ dev_to_sched = netdev;
+ else
+ dev_to_sched = &adapter->polling_netdev[0];
+
+ if (likely(netif_rx_schedule_prep(dev_to_sched)))
+ __netif_rx_schedule(dev_to_sched);
else
e1000_irq_enable(adapter);
#else
@@ -3288,6 +3304,13 @@
return IRQ_HANDLED;
}
+static irqreturn_t
+e1000_intr(int irq, void *data, struct pt_regs *regs)
+{
+ return __e1000_intr(irq, data, regs, 0);
+}
+
+
#ifdef CONFIG_E1000_NAPI
/**
* e1000_clean - NAPI Rx polling callback
@@ -3300,7 +3323,6 @@
struct e1000_adapter *adapter;
int work_to_do = min(*budget, poll_dev->quota);
int tx_cleaned = 0, i = 0, work_done = 0;
-
/* Must NOT use netdev_priv macro here. */
adapter = poll_dev->priv;
@@ -3308,10 +3330,24 @@
if (!netif_carrier_ok(adapter->netdev))
goto quit_polling;
- while (poll_dev != &adapter->polling_netdev[i]) {
- i++;
- if (unlikely(i == adapter->num_rx_queues))
- BUG();
+ /*
+ * only search for a matching polling_netdev in the event
+ * that this isn't a real registered net_device
+ * A real net device can be passed in here in the event
+ * that netdump has been activated (this comes through
+ * netpoll_poll_dev). We detect this by virtue of the
+ * fact that each polling_netdev->priv points to the private
+ * data of its parent (registered) netdev. So if:
+ * poll_dev->priv == netdev_priv(poll_dev), its a real device
+ * otherwise its a polling_netdev.
+ */
+ if (adapter != netdev_priv(poll_dev)) {
+ while (poll_dev != &adapter->polling_netdev[i]) {
+ i++;
+ if (unlikely(i == adapter->num_rx_queues))
+ BUG();
+ }
+
}
if (likely(adapter->num_tx_queues == 1)) {
@@ -4624,7 +4660,7 @@
{
struct e1000_adapter *adapter = netdev_priv(netdev);
disable_irq(adapter->pdev->irq);
- e1000_intr(adapter->pdev->irq, netdev, NULL);
+ __e1000_intr(adapter->pdev->irq, netdev, NULL, 1);
e1000_clean_tx_irq(adapter, adapter->tx_ring);
#ifndef CONFIG_E1000_NAPI
adapter->clean_rx(adapter, adapter->rx_ring);
--
/***************************************************
*Neil Horman
*Software Engineer
*gpg keyid: 1024D / 0x92A74FA1 - http://pgp.mit.edu
***************************************************/
^ permalink raw reply
* [PATCH 0/4] ehea: IBM eHEA Ethernet Device Driver
From: Jan-Bernd Themann @ 2006-06-07 15:12 UTC (permalink / raw)
To: netdev; +Cc: raisch, themann, tklein, meder, schickhj
Hello,
this is the first version of the IBM eHEA Ethernet Device Driver.
It supports a new IBM ethernet chip on System p.
Main functionality including broadcast multicast and some parts of
ethtool already work.
Things we're still working on:
- vlan support
- performance improvements in SMP systems
- kernel coding style
This code is not ready for kernel inclusion as is, but we definetly
want to get there.
The patch series consists of 4 patches
01: interfaces to network stack and headers
02: pHYP interface
03: queue managment
04: Kconfig and Makefile
Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
drivers/net/ehea/Kconfig | 6
drivers/net/ehea/Makefile | 45
drivers/net/ehea/ehea.h | 434 +++++++
drivers/net/ehea/ehea_hw.h | 319 +++++
drivers/net/ehea/ehea_main.c | 2571
+++++++++++++++++++++++++++++++++++++++++++
drivers/net/ehea/ehea_phyp.c | 1026 +++++++++++++++++
drivers/net/ehea/ehea_phyp.h | 625 ++++++++++
drivers/net/ehea/ehea_qmr.c | 719 ++++++++++++
drivers/net/ehea/ehea_qmr.h | 390 ++++++
9 files changed, 6135 insertions(+)
^ permalink raw reply
* HELP! Slip Interface losing packets. Looking for contractor to fix.
From: Butler, Gerald @ 2006-06-07 15:22 UTC (permalink / raw)
To: netdev, linux-kernel, linux-serial
Hello,
We have a custom compiled Linux Kernel running oh RHEL 3.1
[root@st0056_1 root]# uname -a
Linux st0056_1 2.4.21-32.0.1.ELcustom #12 SMP Wed Sep 14 11:55:22 EDT 2005 i686 i686 i386 GNU/Linux
We compiled in SLIP support using the standard RHEL kernel supplied by Redhat. Unfortunately, RH does not support SLIP. We are experiencing problems that we believe are a kernel issue (either SLIP or SERIAL) and are interested in hiring a contractor to diagnose the problem and provide a kernel patch to the kernel we are using (if necessary). We do not want to upgrade or change distributions at this time (business/practicality reasons).
If you are interested, please send an e-mail with your resume (doc, odf, or plain text) to 'gerald.edward.butler@gmail.com' (I'll provide a private e-mail address to interested parties).
The company website is here: http://www.sterlingjewelers.com/
Thank You,
Gerald Butler
Project Manager - Store Systems
Sterling Inc
The information contained in this e-mail message is privileged and/or
confidential and is intended only for the use of the individual or entity
named above. If the reader of this message is not the intended
recipient, or the employee or agent responsible to deliver it to the
intended recipient, you are hereby notified that any dissemination,
distribution or copying of this communication is strictly prohibited.
If you have received this communication in error, please immediately
notify us by telephone (330-668-5000), and destroy the original
message. Thank you.
^ permalink raw reply
* Re: Problem authenticating using WPA with bcm43xx-softmac
From: Larry Finger @ 2006-06-07 15:47 UTC (permalink / raw)
To: Johannes Berg; +Cc: netdev
In-Reply-To: <1149682213.3999.14.camel@johannes>
Johannes Berg wrote:
>
> generic IE is what the wext is called, it is the IE that wpa_supplicant
> sets. Not sure what's going on though, I know next to nothing about wpa.
I have a little more information on what is happening. In IEEE Std 802.11i-2004, which defines the
WPA protocol, Figure 11a shows the sequence of exchanges needed to associate. Both bcm43xx-softmac
and ndiswrapper go through the "Open System Authentication" process. Where they seem to diverge is
in the STA's "Association Request (Security Parameters)" step. With ndiswrapper, the AP responds
with a WPA EAPOL-Key message; whereas with softmac, the AP sends back the "invalid pairwise cipher
message" and rejects the association.
Can anyone point to a reference that states what the content of the Association Request should be to
get the AP to respond with the EAPOL-Key message? Unfortunately, I have no possibility of
implementing a sniffer to see what a "correct" message contains.
Larry
^ permalink raw reply
* Re: Problem authenticating using WPA with bcm43xx-softmac
From: Johannes Berg @ 2006-06-07 15:51 UTC (permalink / raw)
To: Larry Finger; +Cc: netdev
In-Reply-To: <4486F513.5050906@lwfinger.net>
[-- Attachment #1: Type: text/plain, Size: 1038 bytes --]
On Wed, 2006-06-07 at 10:47 -0500, Larry Finger wrote:
> I have a little more information on what is happening.
Great.
> In IEEE Std 802.11i-2004, which defines the
> WPA protocol, Figure 11a shows the sequence of exchanges needed to associate. Both bcm43xx-softmac
> and ndiswrapper go through the "Open System Authentication" process.
Right, you always have to do that.
> Where they seem to diverge is
> in the STA's "Association Request (Security Parameters)" step. With ndiswrapper, the AP responds
> with a WPA EAPOL-Key message; whereas with softmac, the AP sends back the "invalid pairwise cipher
> message" and rejects the association.
Interesting. That's strange.
> Can anyone point to a reference that states what the content of the Association Request should be to
> get the AP to respond with the EAPOL-Key message? Unfortunately, I have no possibility of
> implementing a sniffer to see what a "correct" message contains.
Well, it should be shown in the 802.11i spec too.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 793 bytes --]
^ permalink raw reply
* Re: [PATCH 2/7] AMSO1100 Low Level Driver.
From: Steve Wise @ 2006-06-07 15:56 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: rdreier, mshefty, linux-kernel, netdev, openib-general
In-Reply-To: <20060531115906.30f4bbda@localhost.localdomain>
On Wed, 2006-05-31 at 11:59 -0700, Stephen Hemminger wrote:
> The following should be replaced with BUG_ON() or WARN_ON().
> and pr_debug()
>
> +#ifdef C2_DEBUG
> +#define assert(expr) \
> + if(!(expr)) { \
> + printk(KERN_ERR PFX "Assertion failed! %s, %s, %s, line %d\n",\
> + #expr, __FILE__, __FUNCTION__, __LINE__); \
> + }
> +#define dprintk(fmt, args...) do {printk(KERN_INFO PFX fmt, ##args);} while (0)
> +#else
> +#define assert(expr) do {} while (0)
> +#define dprintk(fmt, args...) do {} while (0)
> +#endif /* C2_DEBUG */
>
> --------------------
> Also, you tend to use assert() as a bogus NULL pointer check.
> If you get passed a NULL, it is a bug, and the deref will fail
> and cause a pretty stack dump...
>
done.
>
> +static void c2_set_rxbufsize(struct c2_port *c2_port)
> +{
> + struct net_device *netdev = c2_port->netdev;
> +
> + assert(netdev != NULL);
>
> Bogus, you will just fail on the deref below
>
done.
> +
> + if (netdev->mtu > RX_BUF_SIZE)
> + c2_port->rx_buf_size =
> + netdev->mtu + ETH_HLEN + sizeof(struct c2_rxp_hdr) +
> + NET_IP_ALIGN;
> + else
> + c2_port->rx_buf_size = sizeof(struct c2_rxp_hdr) + RX_BUF_SIZE;
> +}
>
>
> +static void c2_rx_interrupt(struct net_device *netdev)
> +{
> + struct c2_port *c2_port = netdev_priv(netdev);
> + struct c2_dev *c2dev = c2_port->c2dev;
> + struct c2_ring *rx_ring = &c2_port->rx_ring;
> + struct c2_element *elem;
> + struct c2_rx_desc *rx_desc;
> + struct c2_rxp_hdr *rxp_hdr;
> + struct sk_buff *skb;
> + dma_addr_t mapaddr;
> + u32 maplen, buflen;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&c2dev->lock, flags);
> +
> + /* Begin where we left off */
> + rx_ring->to_clean = rx_ring->start + c2dev->cur_rx;
> +
> + for (elem = rx_ring->to_clean; elem->next != rx_ring->to_clean;
> + elem = elem->next) {
> + rx_desc = elem->ht_desc;
> + mapaddr = elem->mapaddr;
> + maplen = elem->maplen;
> + skb = elem->skb;
> + rxp_hdr = (struct c2_rxp_hdr *) skb->data;
> +
> + if (rxp_hdr->flags != RXP_HRXD_DONE)
> + break;
> + buflen = rxp_hdr->len;
> +
> + /* Sanity check the RXP header */
> + if (rxp_hdr->status != RXP_HRXD_OK ||
> + buflen > (rx_desc->len - sizeof(*rxp_hdr))) {
> + c2_rx_error(c2_port, elem);
> + continue;
> + }
> +
> + /*
> + * Allocate and map a new skb for replenishing the host
> + * RX desc
> + */
> + if (c2_rx_alloc(c2_port, elem)) {
> + c2_rx_error(c2_port, elem);
> + continue;
> + }
> +
> + /* Unmap the old skb */
> + pci_unmap_single(c2dev->pcidev, mapaddr, maplen,
> + PCI_DMA_FROMDEVICE);
> +
>
> prefetch(skb->data) here will help performance.
>
>
good. ok.
> + /*
> + * Skip past the leading 8 bytes comprising of the
> + * "struct c2_rxp_hdr", prepended by the adapter
> + * to the usual Ethernet header ("struct ethhdr"),
> + * to the start of the raw Ethernet packet.
> + *
> + * Fix up the various fields in the sk_buff before
> + * passing it up to netif_rx(). The transfer size
> + * (in bytes) specified by the adapter len field of
> + * the "struct rxp_hdr_t" does NOT include the
> + * "sizeof(struct c2_rxp_hdr)".
> + */
> + skb->data += sizeof(*rxp_hdr);
> + skb->tail = skb->data + buflen;
> + skb->len = buflen;
> + skb->dev = netdev;
> + skb->protocol = eth_type_trans(skb, netdev);
> +
> + /* Drop arp requests to the pseudo nic ip addr */
> + if (unlikely(ntohs(skb->protocol) == ETH_P_ARP)) {
> + u8 *tpa;
> +
> + /* pull out the tgt ip addr */
> + tpa = skb->data /* beginning of the arp packet */
> + + 8 /* arp addr fmts, lens, and opcode */
> + + 6 /* arp src hw addr */
> + + 4 /* arp src proto addr */
> + + 6; /* arp tgt hw addr */
> + if (is_rnic_addr(c2dev->pseudo_netdev, *((u32 *)tpa))) {
> + dprintk("Dropping arp req for"
> + " %03d.%03d.%03d.%03d\n",
> + tpa[0], tpa[1], tpa[2], tpa[3]);
> + kfree_skb(skb);
> + continue;
> + }
> + }
>
> This is looks like a mess, please do it at a higher level or
> code it with proper structure headers
>
This code can be removed entirely. It can be avoided having the c2
driver set in_dev->cnf.arp_ignore to 1 when loaded.
> +
> + netif_rx(skb);
> +
> + netdev->last_rx = jiffies;
> + c2_port->netstats.rx_packets++;
> + c2_port->netstats.rx_bytes += buflen;
> + }
> +
> + /* Save where we left off */
> + rx_ring->to_clean = elem;
> + c2dev->cur_rx = elem - rx_ring->start;
> + C2_SET_CUR_RX(c2dev, c2dev->cur_rx);
> +
> + spin_unlock_irqrestore(&c2dev->lock, flags);
> +}
> +
> +/*
> + * Handle netisr0 TX & RX interrupts.
> + */
> +static irqreturn_t c2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
> +{
> + unsigned int netisr0, dmaisr;
> + int handled = 0;
> + struct c2_dev *c2dev = (struct c2_dev *) dev_id;
> +
> + assert(c2dev != NULL);
> +
> + /* Process CCILNET interrupts */
> + netisr0 = readl(c2dev->regs + C2_NISR0);
> + if (netisr0) {
> +
> + /*
> + * There is an issue with the firmware that always
> + * provides the status of RX for both TX & RX
> + * interrupts. So process both queues here.
> + */
> + c2_rx_interrupt(c2dev->netdev);
> + c2_tx_interrupt(c2dev->netdev);
> +
> + /* Clear the interrupt */
> + writel(netisr0, c2dev->regs + C2_NISR0);
> + handled++;
> + }
> +
> + /* Process RNIC interrupts */
> + dmaisr = readl(c2dev->regs + C2_DISR);
> + if (dmaisr) {
> + writel(dmaisr, c2dev->regs + C2_DISR);
> + c2_rnic_interrupt(c2dev);
> + handled++;
> + }
> +
> + if (handled) {
> + return IRQ_HANDLED;
> + } else {
> + return IRQ_NONE;
> + }
>
> return IRQ_RETVAL(handled);
> +}
> +
> +static int c2_up(struct net_device *netdev)
> +{
> + struct c2_port *c2_port = netdev_priv(netdev);
> + struct c2_dev *c2dev = c2_port->c2dev;
> + struct c2_element *elem;
> + struct c2_rxp_hdr *rxp_hdr;
> + size_t rx_size, tx_size;
> + int ret, i;
> + unsigned int netimr0;
> +
> + assert(c2dev != NULL);
>
> More bogus asserts
>
removed.
<snip>
> +static struct net_device_stats *c2_get_stats(struct net_device *netdev)
> +{
> + struct c2_port *c2_port = netdev_priv(netdev);
> +
> + return &c2_port->netstats;
> +}
> +
> +static int c2_set_mac_address(struct net_device *netdev, void *p)
> +{
> + return -1;
> +}
>
> If you don't handle changing mac_address, just leaveing
> dev->set_mac_address will do the right thing.
> Also, if you need to return an error, use -ESOMEERROR, not -1.
>
I'll remove c2_set_mac_address() entirely.
<snip>
> This seems like log spam, or developer debug thing.
> You need to learn to watch netlink event's from user space.
>
Yes, the entire block below will be removed. It's not needed.
>
> +
> +#ifdef NETEVENT_NOTIFIER
> +static int netevent_notifier(struct notifier_block *self, unsigned long event,
> + void *data)
> +{
> + int i;
> + u8 *ha;
> + struct neighbour *neigh = data;
> + struct netevent_redirect *redir = data;
> + struct netevent_route_change *rev = data;
> +
> + switch (event) {
> + case NETEVENT_ROUTE_UPDATE:
> + printk(KERN_ERR "NETEVENT_ROUTE_UPDATE:\n");
> + printk(KERN_ERR "fib_flags : %d\n",
> + rev->fib_info->fib_flags);
> + printk(KERN_ERR "fib_protocol : %d\n",
> + rev->fib_info->fib_protocol);
> + printk(KERN_ERR "fib_prefsrc : %08x\n",
> + rev->fib_info->fib_prefsrc);
> + printk(KERN_ERR "fib_priority : %d\n",
> + rev->fib_info->fib_priority);
> + break;
> +
> + case NETEVENT_NEIGH_UPDATE:
> + printk(KERN_ERR "NETEVENT_NEIGH_UPDATE:\n");
> + printk(KERN_ERR "nud_state : %d\n", neigh->nud_state);
> + printk(KERN_ERR "refcnt : %d\n", neigh->refcnt);
> + printk(KERN_ERR "used : %d\n", neigh->used);
> + printk(KERN_ERR "confirmed : %d\n", neigh->confirmed);
> + printk(KERN_ERR " ha: ");
> + for (i = 0; i < neigh->dev->addr_len; i += 4) {
> + ha = &neigh->ha[i];
> + printk("%02x:%02x:%02x:%02x:", ha[0], ha[1], ha[2],
> + ha[3]);
> + }
> + printk("\n");
> +
> + printk(KERN_ERR "%8s: ", neigh->dev->name);
> + for (i = 0; i < neigh->dev->addr_len; i += 4) {
> + ha = &neigh->ha[i];
> + printk("%02x:%02x:%02x:%02x:", ha[0], ha[1], ha[2],
> + ha[3]);
> + }
> + printk("\n");
> + break;
> +
> + case NETEVENT_REDIRECT:
> + printk(KERN_ERR "NETEVENT_REDIRECT:\n");
> + printk(KERN_ERR "old: ");
> + for (i = 0; i < redir->old->neighbour->dev->addr_len; i += 4) {
> + ha = &redir->old->neighbour->ha[i];
> + printk("%02x:%02x:%02x:%02x:", ha[0], ha[1], ha[2],
> + ha[3]);
> + }
> + printk("\n");
> +
> + printk(KERN_ERR "new: ");
> + for (i = 0; i < redir->new->neighbour->dev->addr_len; i += 4) {
> + ha = &redir->new->neighbour->ha[i];
> + printk("%02x:%02x:%02x:%02x:", ha[0], ha[1], ha[2],
> + ha[3]);
> + }
> + printk("\n");
> + break;
> +
> + default:
> + printk(KERN_ERR "NETEVENT_WTFO:\n");
> + }
> +
> + return NOTIFY_DONE;
> +}
> +
> +static struct notifier_block nb = {
> + .notifier_call = netevent_notifier,
> +};
> +#endif
> +/*
Thanks,
Steve.
^ permalink raw reply
* Re: Problem authenticating using WPA with bcm43xx-softmac
From: Johannes Berg @ 2006-06-07 15:57 UTC (permalink / raw)
To: Larry Finger; +Cc: netdev, Jouni Malinen
In-Reply-To: <1149695470.3925.7.camel@johannes>
[-- Attachment #1: Type: text/plain, Size: 523 bytes --]
On Wed, 2006-06-07 at 17:51 +0200, Johannes Berg wrote:
> Well, it should be shown in the 802.11i spec too.
I suppose that it is the association request, and needs to contain the
RSN described in 7.3.2.25 as per 7.2.3.4 in 802.11i. This is, afaik, the
'generic IE' that is added with the wext. Now, it looks like the RSN
isn't included but the WPA2 info or something? Also, the genIE in your
log doesn't look correct to me, starting with ffffff?? Jouni, do you
have any idea what might be going on?
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 793 bytes --]
^ permalink raw reply
* Re: Problem authenticating using WPA with bcm43xx-softmac
From: Sam Leffler @ 2006-06-07 16:01 UTC (permalink / raw)
To: Johannes Berg; +Cc: Larry Finger, netdev
In-Reply-To: <1149695470.3925.7.camel@johannes>
Johannes Berg wrote:
> On Wed, 2006-06-07 at 10:47 -0500, Larry Finger wrote:
>
>> I have a little more information on what is happening.
>
> Great.
>
>> In IEEE Std 802.11i-2004, which defines the
>> WPA protocol, Figure 11a shows the sequence of exchanges needed to associate. Both bcm43xx-softmac
>> and ndiswrapper go through the "Open System Authentication" process.
>
> Right, you always have to do that.
>
>> Where they seem to diverge is
>> in the STA's "Association Request (Security Parameters)" step. With ndiswrapper, the AP responds
>> with a WPA EAPOL-Key message; whereas with softmac, the AP sends back the "invalid pairwise cipher
>> message" and rejects the association.
>
> Interesting. That's strange.
>
>> Can anyone point to a reference that states what the content of the Association Request should be to
>> get the AP to respond with the EAPOL-Key message? Unfortunately, I have no possibility of
>> implementing a sniffer to see what a "correct" message contains.
>
> Well, it should be shown in the 802.11i spec too.
Beware of the order of IE's in the management frames; some AP's are
touchy about this.
Sam
^ permalink raw reply
* Re: Problem authenticating using WPA with bcm43xx-softmac
From: Johannes Berg @ 2006-06-07 16:06 UTC (permalink / raw)
To: Sam Leffler; +Cc: Larry Finger, netdev
In-Reply-To: <4486F866.9040901@errno.com>
[-- Attachment #1: Type: text/plain, Size: 252 bytes --]
On Wed, 2006-06-07 at 09:01 -0700, Sam Leffler wrote:
> Beware of the order of IE's in the management frames; some AP's are
> touchy about this.
Uh oh. I have no idea where the ieee80211 layer sticks that one,
probably at the end.
johannes
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 793 bytes --]
^ permalink raw reply
* Re: Problem authenticating using WPA with bcm43xx-softmac
From: Larry Finger @ 2006-06-07 16:09 UTC (permalink / raw)
To: Sam Leffler; +Cc: Johannes Berg, netdev
In-Reply-To: <4486F866.9040901@errno.com>
Sam Leffler wrote:
> Beware of the order of IE's in the management frames; some AP's are
> touchy about this.
That may be the cause here as the behavior when I changed AP's from the Linux-based model to one
with VXWorks.
Larry
^ permalink raw reply
* Re: [patch] workaround zd1201 interference problem
From: Daniel Drake @ 2006-06-07 16:22 UTC (permalink / raw)
To: Pavel Machek; +Cc: Jiri Benc, linville, kernel list, netdev
In-Reply-To: <20060607141536.GD1936@elf.ucw.cz>
Pavel Machek wrote:
> Well, I'll try _enable() alone, but it seems to me that _enable()
> command is needed to initialize radio properly. I do not think we can
> get much further without firmware sources...
If you can formulate a proper and technical description of the issue
(and exactly what is needed to workaround it), I can contact ZyDAS for
you. They have been very helpful with ZD1211.
Daniel
^ permalink raw reply
* Re: Problem authenticating using WPA with bcm43xx-softmac
From: Larry Finger @ 2006-06-07 16:30 UTC (permalink / raw)
To: Johannes Berg; +Cc: Sam Leffler, netdev
In-Reply-To: <1149696400.3925.13.camel@johannes>
Johannes Berg wrote:
> On Wed, 2006-06-07 at 09:01 -0700, Sam Leffler wrote:
>
>> Beware of the order of IE's in the management frames; some AP's are
>> touchy about this.
>
> Uh oh. I have no idea where the ieee80211 layer sticks that one,
> probably at the end.
I can verify that. I'm currently building a new module with a printk to verify that it is being
added. If it is, I'll try moving it to see if it helps.
Larry
^ permalink raw reply
* AD:StartSCMÆóÒµ¹©Ó¦Á´,»¥ÁªÍøÊ±´ú¹ÜÀíÓ¦ÓÃϵͳ
From: nB4a @ 2006-06-07 16:33 UTC (permalink / raw)
To: 9YETfmIhHhT8B
ÔÚÏß²âÊÔµØÖ· http://starterp.oicp.net/scm/ ÕʺÅ:admin ÃÜÂë:admin
×Éѯµç»°:0 7 5 5 - 6 1 2 8 7 3 1 1 ²ÜÏÈÉú E-mail: caoshan@starterp.net
Start¹©Ó¦Á´ÊÇÀûÓû¥ÁªÍø¼¼ÊõºÍÏÖ´ú¿Æ¼¼¹ÜÀíÊֶν¨Á¢ÆðÀ´µÄÒ»Ì×ÍêÕûµÄÉÌÆ·»¯µÄÆóÒµ¹ÜÀíÈí¼þ£¬
ÊÇרÃÅÓÃÀ´¹ÜÀí¹©Ó¦ÉÌ¡¢ÁãÊÛÉÌ¡¢Åú·¢ÉÌÒÔ¼°×îÖÕ¿Í»§µÄ×ÛºÏÓ¦ÓÃϵͳ¡£
¡¡¡¡Start¹©Ó¦Á´½è¼øÁ˹úÄÚÍâÓÅÐ㹩ӦÁ´Èí¼þµÄÌØµã£¬²ÉÓÃÁËȫеÄÏÖ´ú¹ÜÀí˼ÏëºÍÏȽøµÄ¼¼ÊõÊֶΣ¬
Ëü¿ÉÒÔÓÐЧµØ½«ÆóÒµºÍºÏ×÷»ï°é½ôÃܵØÁªÏµÆðÀ´£¬¿ÉÒÔ³ÖÐø¿É¿¿µØÂú×ã¸÷Àà¿Í»§µÄÐèÇ󣬿ÉÒÔ×î´óÏÞ¶È
µØ½µµÍÆóÒµµÄ·çÏÕ£¬×îÖÕʵÏÖÒÔ×îµÍµÄ³É±¾ºÍ·ÑÓÃÌṩ×î´óµÄ¼ÛÖµºÍ×îºÃµÄ·þÎñ¡£ÈçͼËùʾ¡£
Start¹©Ó¦Á´ÌṩÁËÍêÕûµÄ¹©Ó¦Á´¹ÜÀí£¬Ê¹µÃ²É¹ºÔ²ÄÁÏ£¬µ½ÖÐÐÄ¿â´æ¹ÜÀí£¬µ½Õû¸öÏúÊÛͨ·ÉϵÄÎï
Á÷¹ÜÀí±äµÃÇáÇáËÉËÉ¡£ÏµÍ³ÖÐÉæ¼°µ½µÄËùÓÐÒµÎñ¶¼Äܹ»×Ô¶¯Éú³ÉÏàÓ¦µÄ»á¼ÆÆ¾Ö¤£¬´ó´ó·½±ãÁËÆóÒµµÄ»á¼Æ
ºËËãºÍ²ÆÎñ¹ÜÀí¹¤×÷¡£Ö÷Òª°üÀ¨£ºÏúÊÛ¡¢¿â´æ¡¢²É¹º¡¢ÆÚÄ©¡¢±¨±í¡¢×ÊÁÏ¡¢ÏµÍ³ÅäÖá£ÈçͼһËùʾ¡£
¡¡¡¡£¨Ò»£©ÏúÊÛ
¡¡¡¡ÏúÊÛ¸²¸ÇÆóÒµÏúÊ۵ĸ÷¸ö»·½Ú¡£Í¨¹ýÏúÊÛ¶©µ¥Â¼ÈëÓë±ä¸ü£¬¸ú×Ù¹ÜÀíÏúÊÛÇé¿ö£»¸ù¾Ý»õÆ·±¨¼ÛºÍÏúÊÛ
ÊýÁ¿×Ô¶¯¿ª³öÏúÊÛ·¢Æ±£¬¸ù¾Ý·¢»õµ¥²úÉú½áËãÆ¾Ö¤ºÍÊÕ»õµ¥£»Ìṩʵ¼ÊÏúÊÛÉÌÆ·½ð¶îÓëÕÊÃæ½ð¶îºË¶Ô¹¦ÄÜ
£»ÌṩÁ˿ͻ§ÐÅÓöî¶È¿ØÖƹ¦ÄÜ£¬¿ÉÒÔ´ïµ½½µµÍÏúÊÛ·çÏÕ£¬¼õÉÙÓ¦ÊÕ´ôÕ˵ÄÄ¿µÄ£¬»¹¿ÉÒÔʵÏÖÒµÎñÔ±ÏúÊÛ
Òµ¼¨¡¢ÏúÊÛÖ¸±êÍê³ÉÇé¿öµÄ¿¼ºË¹¦ÄÜ¡£
ÏúÊÛ¶©µ¥
ÏúÊÛ·¢»õµ¥
ÏúÊÛ·¢Æ±
ÏúÊÛÊÕ¿î
ÏúÊÛÍË»õ
ÏúÊÛÍË»õ·¢Æ±
ÏúÊÛÍË»õ¸¶¿î
ÏúÊÛÒµÎñÉóºË
ÏúÊÛÒµÎñ²éÕÒ
£¨¶þ£©²É¹º
²É¹º¸²¸ÇÆóÒµ²É¹ºµÄ¸÷¸ö»·½Ú¡£Æóҵͨ¹ýÐéÄâµÄÔÚÏß»õƷĿ¼£¬Ñ¸ËÙ¶øÊµÊ±µÄ·ÃÎÊ»õÆ·ÐÅÏ¢£»Í¨¹ý¼Û¸ñºÍÆ·
ÖʵıȽϣ¬Ñ¡¶¨²úÆ·¹©Ó¦ÉÌ£»²É¹ºÈËԱͨ¹ýϵͳ¶Ô¿â´æ×´¿öµÄ·ÖÎöÆÀ¹À¹©Ó¦É̵ÄʵÁ¦£»ÊµÊ±¶øÑ¸ËÙµØÁ˽⹩
Ó¦É̵ÄÐÅÏ¢£¬±ÜÃ⴫ͳ½»Ò×ÖеÄÖÖÖÖÕϰ¡£
²É¹º¶©µ¥
²É¹ºÊÕ»õ
²É¹º·¢Æ±
²É¹º¸¶¿î
²É¹ºÍË»õ
²É¹ºÍË»õ·¢Æ±
²É¹ºÍË»õÊÕ¿î
²É¹ºÒµÎñÉóºË
²É¹ºÒµÎñ²éÕÒ
£¨Èý£©´æ»õ
¸ù¾Ý²É¹ºµ¥½øÐÐÈë¿âµÇ¼Ç£»¿ÉÒÔʵÏÖ»õÆ·Å̵㡢ËðºÄµÇ¼Ç¡¢¿â´æµ÷²¦µÈ¹¦ÄÜ£»¶Ô½ø³ö²Ö»õÆ·Êý¾Ý½øÐк˶ԡ£
½ø¿âµ¥
³ö¿âµ¥
ÆäËûÊÕ»õµ¥
ÆäËû·¢»õµ¥
²Ö¿âµ÷²¦
´æ»õÒµÎñÉóºË
´æ»õÒµÎñ²éÕÒ
£¨ËÄ£©ÆÚÄ©
ÆÚÄ©ÌṩÁË»õÆ·Å̵㡢»õÆ·µ÷¼ÛÒÔ¼°ÒµÎñÉóºËµÈÆÚĩҵÎñ´¦Àí¹¦ÄÜ£¬ÒµÎñÆÚÄ©½áËãΪ²ÆÎñÆÚÄ©½áËã×öÁ˱ØÒª
µÄÆÌµæ×÷Óá£
»õÆ·Å̵ã
»õÆ·µ÷¼Û
ÆÚĩҵÎñÉóºË
£¨Î壩±¨±í
¸ù¾Ý²»Í¬µÄÒµÎñÐèÇó£¬ÌṩÁ˲»Í¬µÄ±¨±í¡£Ã¿Ò»À౨±í¶¼¿ÉÒÔ¸ù¾ÝÆóÒµµÄÐèÒª½øÐлã×Üͳ¼ÆÓйصÄÏîÄ¿¡£±¨
±í¿ÉÒÔ°ïÖúÆóÒµÁìµ¼ÊÊʱ¼à¶½ÒµÎñ¼Æ»®£¬Á˽ⶩµ¥µÄÖ´ÐÐÇé¿ö£¬½øÐÐÏà¹ØÊý¾Ý·ÖÎö£¬½øÒ»²½½øÐоӪ¾ö²ß¡£
£¨Áù£©×ÊÁÏ
Óû§¿ÉÒÔ¿ìËÙ¡¢Ö±¹ÛµØ²éѯËùÐèÒªµÄÊý¾Ý×ÊÁÏ¡£
¿Í»§ºÍ¹©Ó¦ÉÌ×ÊÁÏ
»õÆ·ºÍ²Ö¿â×ÊÁÏ
ÒµÎñ×ÊÁÏ
¹«Ë¾ÐÅÏ¢
µ¥¾ÝÄ£°å
£¨Æß£©ÏµÍ³¹ÜÀí
ϵͳ¹ÜÀíÊÇÕû¸öϵͳµÄÃÅ»§£¬ÔÚϵͳµÄ°²È«ÐÔÉÏÆðµ½Á˲»¿É¹ÀÁ¿µÄ×÷Ó᣸÷ÖÖÐÅÏ¢ÒªÇó¾¡Á¿È«ÃæÏêϸ£¬Ê¹¹ÜÀí
±äµÃ¸üÇáËɸüÓÐЧ¡£
Óû§¹ÜÀí
Óû§×é¹ÜÀí
Óû§×éȨÏÞ¶¨Òå
Óû§È¨ÏÞ¶¨Òå
ΪÓû§×é·ÖÅäÓû§
Start¹©Ó¦Á´Ö÷ÒªÊÇΪÖÐСÐÍÆóҵʵÏÖÈ«Ãæ¹ÜÀí¶øÑз¢µÄ£¬·ûºÏÎÒ¹úÏÖ´úÆóÒµµÄ·ÖÏúģʽ£¬Ö§³Ö¶àÖÖ·ÖÏú
ÒµÎñÌØÓеÄÏúÊÛ½±Àø·½Ê½¡£Start¹©Ó¦Á´°ïÖúÆóÒµ·½±ãµØÕûºÏÇþµÀ×ÊÔ´£¬Í³³ïÐÅÏ¢¡¢»õÆ·Óë×ʽð¹ÜÀí£¬¼õÉÙÆóÒµ
µÄÔËÓª³É±¾£¬Ìá¸ßÁ˹¤×÷ЧÂÊ¡£Ö÷ÒªÌØµãÓУº
ÏȽøµÄWebģʽ£ºÏµÍ³ÍêÈ«»ùÓÚWebģʽ£¬²ÉÓÃÏȽøµÄä¯ÀÀÆ÷/·þÎñÆ÷£¨B/S£©µÄ½á¹¹£¬ÍêÈ«Í»ÆÆÁË´«Í³ÍøÂçʱ
¿ÕÏÞÖÆµÄ¸ÅÄî¡£ÄúÖ»ÒªÁ¬½ÓÉÏInternet£¬¾Í¿ÉÒÔÔÚÈκÎʱ¼ä¡¢Èκεص㡢ÒÔÈκνÓÈ뷽ʽµÇ¼ϵͳ£¬ÇáËÉ×ÔÈçµØ
¹¤×÷¡£ÏµÍ³Êý¾Ý¼¯³É¶È¸ß£ºStart¹©Ó¦Á´Í»ÆÆÁË´«Í³µÄÊý¾Ý´«µÝ·½Ê½£¬²ÉÓÃÁË"ÎÞ·ìÁ´½Ó"µÄ¸ÅÄ¸÷Ä£¿éÖ®¼äµÄÊý
¾Ý×ªÒÆ¿É×Ô¶¯Íê³É£¬±ÜÃâÁËÖØ¸´ÊäÈ룬±£Ö¤ÁËÊý¾ÝµÄÒ»ÖÂÐÔ¡¢Á¬¹áÐÔ£¬´Ó¶ø´ó´ó¼õÇáÁ˹¤×÷Á¿£¬Ìá¸ßÁ˹¤×÷ЧÂÊ¡£
¸ß¶ÈµÄ°²È«ÐÔ¡¢¿É¿¿ÐÔ£ºStart¹©Ó¦Á´Îª±£Ö¤ÆóÒµÄÚ²¿µÄÐͬ¹¤×÷£¬¶ÔËùÓÐÓû§½øÐÐÁËÑϸñµÄ·Ö×é¹ÜÀí£¬²¢¶Ôÿ¸ö
Óû§×é½øÐÐÑÏÃܵÄȨÏÞ·ÖÅ䣬³¹µ×½â¾öÁ˳¤ÆÚÀ§ÈÅÆóÒµÐÅÏ¢»¯µÄ°²È«ÐÔÎÊÌâ¡£
ÍêÈ«µÄÍøÂ绯²Ù×÷£ºStart¹©Ó¦Á´»ùÓÚÏȽøµÄä¯ÀÀÆ÷/·þÎñÆ÷£¨B/S£©Ìåϵ½á¹¹¿ª·¢¶ø³É£¬ÊÇÕæÕýµÄÍøÂ绯ÐÅÏ¢
¹ÜÀíÈí¼þ¡£Êý¾Ý´«ÊäËٶȸü¼Ó¿ì½Ý¡¢×¼È·£¬ÆóÒµ¹ÜÀíЧÂʽ«µÃµ½´ó·ùÌá¸ß¡£
µ¼º½Ê½µÄ²Ù×÷½çÃæ£ºStart¹©Ó¦Á´²ÉÓÃÁ˵¼º½Ê½²Ù×÷½çÃæ£¬¸Ã½çÃæ¼¯ºÏÁËËùÓеÄÒµÎñ²Ù×÷¹¦ÄÜ£¬Ö±¹ÛÐÎÏóµØÒý
µ¼Óû§½øÐÐÒµÎñ²Ù×÷¡£µ¼º½Ê½µÄ½çÃæÊ¹¸÷ÏîÒµÎñ²Ù×÷±äµÃÇáËÉ×ÔÈç¡£
È«ÄܵÄÐÅÏ¢²éѯ£ºStart¹©Ó¦Á´ÌṩÁËÇ¿´óµÄ×ÊÁÏÖÐÐÄ£¬°üÀ¨²É¹º¡¢ÏúÊÛ¡¢¿â´æ¡¢ÆÚÄ©¡¢±¨±íµÈһϵÁж¯Ì¬Êý
¾Ý×ÊÁÏ£¬¸²¸ÇÃæ¹ã£¬Í³¼Æ·½·¨¿ÆÑ§£¬Êý¾Ý׼ȷ¡£Óû§¿ÉÒÔ°´ÕÕÏà¹ØÌõ¼þ¶Ô¶©µ¥¡¢ÊÕ»õ¡¢ÍË»õ¡¢¸¶¿î¡¢¿â´æ¡¢ÏúÊÛµÈ
½øÐÐ×éºÏ²éѯ¡£
·½±ãµÄÓ¦Óö¨Öƹ¦ÄÜ£ºStart¹©Ó¦Á´²ÉÓõ±½ñÁ÷Ðеı¨±íÉè¼ÆÆ÷½øÐе¥¾Ý¡¢Õ˱íµÄÉè¼Æ£¬²¢ÎªÓû§ÌṩÁË×ÔÓɶ¨
ÖÆ¸÷ÀàÔʼµ¥¾Ý¡¢Õ˱í¸ñʽµÄ¹¦ÄÜ£»Óû§²»½ö¿ÉÒÔ¶Ôµ¥¾Ý¡¢Õ˱íÍâ¹Û½øÐÐÉè¼Æ£¨°üÀ¨¶Ô¸ñʽ¡¢×ÖÌå¡¢±ß¿ò¡¢±³¾°µÈµÄ
Éè¼Æ£©£¬¶øÇÒ¿ÉÒÔÉ趨±¨±íÄÚ²¿Êý¾ÝµÄ¼ÆËã·½·¨£¨°üÀ¨¶ÔÊý¾ÝÀ´Ô´µÄÉ趨¡¢Êý¾ÝËã·¨µÄÉ趨µÈ£©£¬Í¬Ê±¼æ¾ßWORDºÍ
EXCELµÄÇ¿´ó¹¦ÄÜ¡£
^ permalink raw reply
* Re: [PATCH 1/2] e1000: fix netpoll with NAPI
From: Matt Mackall @ 2006-06-07 16:48 UTC (permalink / raw)
To: Neil Horman
Cc: Jeff Moyer, Auke Kok, Garzik, Jeff, Mitch Williams, netdev,
Brandeburg, Jesse, Kok, Auke
In-Reply-To: <20060607150522.GA24608@hmsreliant.homelinux.net>
On Wed, Jun 07, 2006 at 11:05:22AM -0400, Neil Horman wrote:
> >
> > > Matt, any ideas on this?
> >
> > Not at the moment.
>
> how about this for a solution? It doesn't make netpoll any more robust, but I
> think in the interests of efficiency it would be fair to require that, when
> netpolled, a driver must receive frames on the same net device for which it was
> polled. With this patch we detect that condition and handle it accordingly in
> e1000_intr. This eliminates the need for us to call the clean_rx method from
> the poll_controller when napi is configured, instead allowing the poll method to
> be called from napi_poll, as the netpoll model currently does. This fixes the
> netdump regression, and eliminates the layering violation and the potential race
> that we've been discussing. I've just tested it with netdump here and it works
> quite well.
>
> Thoughts appreciated.
This looks pretty reasonable, mostly from the perspective that it
doesn't put any further ugliness in netpoll. We might want to add a
comment somewhere in netpoll of the new rule we're now observing.
I'll let the e1000 guys comment on the particulars of the driver change.
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: Matt Mackall <mpm@selenic.com>
--
Mathematics is the supreme nostalgia of our time.
^ permalink raw reply
* [PATCH 2/4] ehea: pHYP interface
From: Jan-Bernd Themann @ 2006-06-07 17:04 UTC (permalink / raw)
To: netdev; +Cc: meder, raisch, themann, tklein
Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
drivers/net/ehea/ehea_phyp.c | 1026 +++++++++++++++++++++++++++++++++++++++++++
drivers/net/ehea/ehea_phyp.h | 625 ++++++++++++++++++++++++++
2 files changed, 1651 insertions(+)
--- linux-2.6.16-rc5-orig/drivers/net/ehea/ehea_phyp.c 1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_phyp.c 2006-06-07 07:01:14.658175056 -0700
@@ -0,0 +1,1026 @@
+/*
+ * linux/drivers/net/ehea/ehea_phyp.c
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Heiko-Joerg Schick <schickhj@de.ibm.com>
+ * Thomas Klein <tklein@de.ibm.com>
+ *
+ *
+ * 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "ehea_phyp.h"
+
+
+static inline u16 get_order_of_qentries(u16 queue_entries)
+{
+ u8 ld = 1; /* logarithmus dualis */
+ EDEB_EN(7, "queue_entries=0x%X", queue_entries);
+ while (((1U << ld) - 1) < queue_entries) {
+ ld++;
+ };
+ EDEB_EX(7, "mapped queue_entries=%d", ld - 1);
+ return ld - 1;
+}
+
+
+/* Defines for H_CALL H_ALLOC_RESOURCE */
+#define H_ALL_RES_TYPE_QP 1
+#define H_ALL_RES_TYPE_CQ 2
+#define H_ALL_RES_TYPE_EQ 3
+#define H_ALL_RES_TYPE_MR 5
+#define H_ALL_RES_TYPE_MW 6
+
+u64 hipz_h_query_ehea_qp(const u64 hcp_adapter_handle,
+ const u8 qp_category,
+ const u64 qp_handle, const u64 sel_mask, void *cb_addr)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy = 0;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lX cat=%X qp_handle=%lX sel_mask=%lX "
+ "cb_addr=%p\n",
+ hcp_adapter_handle,
+ (u16) qp_category, qp_handle, sel_mask, cb_addr);
+ EDEB_DMP(7, (u8 *) cb_addr, sizeof(struct hcp_modify_qp_cb_0),
+ "Before HCALL");
+
+ if ((((u64)cb_addr) & (PAGE_SIZE - 1)) != 0)
+ panic("query_ehea_qp: cb_addr not on page boundary!!!");
+
+ hret = ehea_hcall_7arg_7ret(H_QUERY_EHEA_QP,
+ hcp_adapter_handle, /* R4 */
+ qp_category, /* R5 */
+ qp_handle, /* R6 */
+ sel_mask, /* R7 */
+ virt_to_abs(cb_addr), /* R8 */
+ 0, 0, /* R9-R10 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy); /* R10 */
+
+ EDEB_DMP(7, (u8 *) cb_addr, sizeof(struct hcp_modify_qp_cb_0),
+ "After HCALL");
+ EDEB_EX(7, "");
+ return hret;
+}
+
+/* input param R5 */
+#define H_ALL_RES_QP_EQPO EHEA_BMASK_IBM(9, 11)
+#define H_ALL_RES_QP_QPP EHEA_BMASK_IBM(12, 12)
+#define H_ALL_RES_QP_RQR EHEA_BMASK_IBM(13, 15)
+#define H_ALL_RES_QP_EQEG EHEA_BMASK_IBM(16, 16)
+#define H_ALL_RES_QP_LL_QP EHEA_BMASK_IBM(17, 17)
+#define H_ALL_RES_QP_DMA128 EHEA_BMASK_IBM(19, 19)
+#define H_ALL_RES_QP_HSM EHEA_BMASK_IBM(20, 21)
+#define H_ALL_RES_QP_SIGT EHEA_BMASK_IBM(22, 23)
+#define H_ALL_RES_QP_TENURE EHEA_BMASK_IBM(48, 55)
+#define H_ALL_RES_QP_RES_TYP EHEA_BMASK_IBM(56, 63)
+
+/* input param R9 */
+#define H_ALL_RES_QP_TOKEN EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_PD EHEA_BMASK_IBM(32,63)
+
+/* input param R10 */
+#define H_ALL_RES_QP_MAX_SWQE EHEA_BMASK_IBM(4, 7)
+#define H_ALL_RES_QP_MAX_R1WQE EHEA_BMASK_IBM(12, 15)
+#define H_ALL_RES_QP_MAX_R2WQE EHEA_BMASK_IBM(20, 23)
+#define H_ALL_RES_QP_MAX_R3WQE EHEA_BMASK_IBM(28, 31)
+/* Max Send Scatter Gather Elements */
+#define H_ALL_RES_QP_MAX_SSGE EHEA_BMASK_IBM(37, 39)
+#define H_ALL_RES_QP_MAX_R1SGE EHEA_BMASK_IBM(45, 47)
+/* Max Receive SG Elements RQ1 */
+#define H_ALL_RES_QP_MAX_R2SGE EHEA_BMASK_IBM(53, 55)
+#define H_ALL_RES_QP_MAX_R3SGE EHEA_BMASK_IBM(61, 63)
+
+/* input param R11 */
+#define H_ALL_RES_QP_SWQE_IDL EHEA_BMASK_IBM(0, 7)
+/* max swqe immediate data length */
+#define H_ALL_RES_QP_PORT_NUM EHEA_BMASK_IBM(48, 63)
+
+/* input param R12 */
+#define H_ALL_RES_QP_TH_RQ2 EHEA_BMASK_IBM(0, 15)
+/* Threshold RQ2 */
+#define H_ALL_RES_QP_TH_RQ3 EHEA_BMASK_IBM(16, 31)
+/* Threshold RQ3 */
+
+/* output param R6 */
+#define H_ALL_RES_QP_ACT_SWQE EHEA_BMASK_IBM(0, 15)
+#define H_ALL_RES_QP_ACT_R1WQE EHEA_BMASK_IBM(16, 31)
+#define H_ALL_RES_QP_ACT_R2WQE EHEA_BMASK_IBM(32, 47)
+#define H_ALL_RES_QP_ACT_R3WQE EHEA_BMASK_IBM(48, 63)
+
+/* output param, R7 */
+#define H_ALL_RES_QP_ACT_SSGE EHEA_BMASK_IBM(0, 7)
+#define H_ALL_RES_QP_ACT_R1SGE EHEA_BMASK_IBM(8, 15)
+#define H_ALL_RES_QP_ACT_R2SGE EHEA_BMASK_IBM(16, 23)
+#define H_ALL_RES_QP_ACT_R3SGE EHEA_BMASK_IBM(24, 31)
+#define H_ALL_RES_QP_ACT_SWQE_IDL EHEA_BMASK_IBM(32, 39)
+
+/* output param R8,R9 */
+#define H_ALL_RES_QP_SIZE_SQ EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_SIZE_RQ1 EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_SIZE_RQ2 EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_SIZE_RQ3 EHEA_BMASK_IBM(32, 63)
+
+/* output param R11,R12 */
+#define H_ALL_RES_QP_LIOBN_SQ EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_LIOBN_RQ1 EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_LIOBN_RQ2 EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_LIOBN_RQ3 EHEA_BMASK_IBM(32, 63)
+
+u64 hipz_h_alloc_resource_qp(const u64 adapter_handle,
+ struct ehea_qp *ehea_qp,
+ struct ehea_qp_init_attr *init_attr,
+ const u32 pd,
+ u64 *qp_handle, struct h_galpas *h_galpas)
+{
+ u64 hret = H_ADAPTER_PARM;
+
+ u64 allocate_controls =
+ EHEA_BMASK_SET(H_ALL_RES_QP_EQPO, init_attr->low_lat_rq1 ? 1 : 0)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_QPP, 0)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_RQR, 6) /* RQ1 & RQ2 & rq3 */
+ |EHEA_BMASK_SET(H_ALL_RES_QP_EQEG, 0) /* EQE gen. disabled */
+ |EHEA_BMASK_SET(H_ALL_RES_QP_LL_QP, init_attr->low_lat_rq1)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_DMA128, 0)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_HSM, 0)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_SIGT, init_attr->signalingtype)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_RES_TYP, H_ALL_RES_TYPE_QP);
+
+ u64 r9_reg = EHEA_BMASK_SET(H_ALL_RES_QP_PD, pd)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_TOKEN, init_attr->qp_token);
+
+ u64 max_r10_reg =
+ EHEA_BMASK_SET(H_ALL_RES_QP_MAX_SWQE,
+ get_order_of_qentries(init_attr->max_nr_send_wqes))
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R1WQE,
+ get_order_of_qentries(init_attr->max_nr_rwqes_rq1))
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R2WQE,
+ get_order_of_qentries(init_attr->max_nr_rwqes_rq2))
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R3WQE,
+ get_order_of_qentries(init_attr->max_nr_rwqes_rq3))
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_SSGE, init_attr->wqe_size_enc_sq)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R1SGE,
+ init_attr->wqe_size_enc_rq1)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R2SGE,
+ init_attr->wqe_size_enc_rq2)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R3SGE,
+ init_attr->wqe_size_enc_rq3);
+
+ u64 r11_in =
+ EHEA_BMASK_SET(H_ALL_RES_QP_SWQE_IDL, init_attr->swqe_imm_data_len)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_PORT_NUM, init_attr->port_nr);
+ u64 threshold =
+ EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ2, init_attr->rq2_threshold)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ3, init_attr->rq3_threshold);
+
+ u64 r5_out = 0;
+ u64 r6_out = 0;
+ u64 r7_out = 0;
+ u64 r8_out = 0;
+ u64 r9_out = 0;
+ u64 g_la_user_out = 0;
+ u64 r11_out = 0;
+ u64 r12_out = 0;
+
+ EDEB_EN(7, "adapter_handle=%lx low latency RQ1 0x%X"
+ " signalingtype=0x%X number of RQs=0x%X "
+ " send_cq_handle=%lx receive_cq_handle=%lx"
+ " async_eq_handle=%lx"
+ " qp_token=0x%X pd=0x%X max_nr_send_wqes=0x%X"
+ " max_nr_rcv_wqes_rq1=0x%X max_nr_rcv_wqes_rq2=0x%X "
+ " max_nr_rcv_wqes_rq3=0x%X wqe_enc_size=0x%X"
+ " wqe_enc_size_rq1=0x%X wqe_enc_size_rq2=0x%X "
+ " wqe_enc_size_rq3=0x%X port_nr=%d "
+ " rq2_threshold=%d rq3_threshold=%d "
+ " galpa.pid=%x",
+ adapter_handle, init_attr->low_lat_rq1,
+ init_attr->signalingtype, init_attr->rq_count,
+ init_attr->send_cq_handle, init_attr->recv_cq_handle,
+ init_attr->aff_eq_handle, init_attr->qp_token,
+ pd, init_attr->max_nr_send_wqes, init_attr->max_nr_rwqes_rq1,
+ init_attr->max_nr_rwqes_rq2, init_attr->max_nr_rwqes_rq3,
+ init_attr->wqe_size_enc_sq, init_attr->wqe_size_enc_rq1,
+ init_attr->wqe_size_enc_rq2, init_attr->wqe_size_enc_rq3,
+ init_attr->port_nr, init_attr->rq2_threshold,
+ init_attr->rq3_threshold, h_galpas->pid);
+
+ hret = ehea_hcall_9arg_9ret(H_ALLOC_EHEA_RESOURCE,
+ adapter_handle, /* R4 */
+ allocate_controls, /* R5 */
+ init_attr->send_cq_handle, /* R6 */
+ init_attr->recv_cq_handle, /* R7 */
+ init_attr->aff_eq_handle, /* R8 */
+ r9_reg, /* R9 */
+ max_r10_reg, /* R10 */
+ r11_in, /* R11 */
+ threshold, /* R12 */
+ qp_handle, /* R4 */
+ &r5_out, /* R5 */
+ &r6_out, /* R6 */
+ &r7_out, /* R7 */
+ &r8_out, /* R8 */
+ &r9_out, /* R9 */
+ &g_la_user_out, /* R10 */
+ &r11_out, /* R11 */
+ &r12_out); /* R12 */
+
+ init_attr->qp_nr = (u32)r5_out;
+
+ init_attr->act_nr_send_wqes =
+ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_SWQE, r6_out);
+ init_attr->act_nr_rwqes_rq1 =
+ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R1WQE, r6_out);
+ init_attr->act_nr_rwqes_rq2 =
+ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R2WQE, r6_out);
+ init_attr->act_nr_rwqes_rq3 =
+ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R3WQE, r6_out);
+
+/* Interface is under construction */
+ init_attr->act_wqe_size_enc_sq = init_attr->wqe_size_enc_sq;
+ init_attr->act_wqe_size_enc_rq1 = init_attr->wqe_size_enc_rq1;
+ init_attr->act_wqe_size_enc_rq2 = init_attr->wqe_size_enc_rq2;
+ init_attr->act_wqe_size_enc_rq3 = init_attr->wqe_size_enc_rq3;
+
+ init_attr->nr_sq_pages =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_SQ, r8_out);
+ init_attr->nr_rq1_pages =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ1, r8_out);
+ init_attr->nr_rq2_pages =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ2, r9_out);
+ init_attr->nr_rq3_pages =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ3, r9_out);
+
+ init_attr->liobn_sq =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_SQ, r11_out);
+ init_attr->liobn_rq1 =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ1, r11_out);
+ init_attr->liobn_rq2 =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ2, r12_out);
+ init_attr->liobn_rq3 =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ3, r12_out);
+
+ if (hret == H_SUCCESS)
+ hcp_galpas_ctor(h_galpas, g_la_user_out, g_la_user_out);
+
+ EDEB_EX(7, " qp_nr=%X, act_nr_send_wqes=%X,"
+ " act_nr_rcv_wqes_rq1=%X, act_nr_rcv_wqes_rq2=%X,"
+ " act_nr_rcv_wqes_rq3=%X, act_nr_send_sges=%X,"
+ " act_nr_rcv_sges_rq1=%X, act_nr_rcv_sges_rq2=%X,"
+ " act_nr_rcv_sges_rq3=%X, nr_sq_pages=%X,"
+ " nr_rq1_pages=%X, nr_rq2_pages=%X, nr_rq3_pages=%X,"
+ " galpa.user=%lx galpa.kernel=%lx",
+ init_attr->qp_nr, init_attr->act_nr_send_wqes,
+ init_attr->act_nr_rwqes_rq1, init_attr->act_nr_rwqes_rq2,
+ init_attr->act_nr_rwqes_rq3, init_attr->act_wqe_size_enc_sq,
+ init_attr->act_wqe_size_enc_rq1,
+ init_attr->act_wqe_size_enc_rq2,
+ init_attr->act_wqe_size_enc_rq3, init_attr->nr_sq_pages,
+ init_attr->nr_rq1_pages, init_attr->nr_rq2_pages,
+ init_attr->nr_rq3_pages, h_galpas->user.fw_handle,
+ h_galpas->kernel.fw_handle);
+
+ return hret;
+}
+
+u64 hipz_h_alloc_resource_cq(const u64 hcp_adapter_handle,
+ struct ehea_cq *ehea_cq,
+ struct ehea_cq_attr *cq_attr,
+ u64 *cq_handle, struct h_galpas *galpas)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy = 0;
+ u64 act_nr_of_cqes_out;
+ u64 act_pages_out;
+ u64 g_la_privileged_out;
+ u64 g_la_user_out;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lx eq_handle=%lx"
+ " cq_token=%x max_nr_of_cqes=%x",
+ hcp_adapter_handle, cq_attr->eq_handle, cq_attr->cq_token,
+ cq_attr->max_nr_of_cqes);
+
+
+ hret = ehea_hcall_7arg_7ret(H_ALLOC_EHEA_RESOURCE,
+ hcp_adapter_handle, /* R4 */
+ H_ALL_RES_TYPE_CQ, /* R5 */
+ cq_attr->eq_handle, /* R6 */
+ cq_attr->cq_token, /* R7 */
+ cq_attr->max_nr_of_cqes, /* R8 */
+ dummy, /* R9 */
+ dummy, /* R10 */
+ cq_handle, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &act_nr_of_cqes_out, /* R7 */
+ &act_pages_out, /* R8 */
+ &g_la_privileged_out, /* R9 */
+ &g_la_user_out); /* R10 */
+
+ cq_attr->act_nr_of_cqes = act_nr_of_cqes_out;
+ cq_attr->nr_pages = act_pages_out;
+
+ if (hret == H_SUCCESS)
+ hcp_galpas_ctor(galpas, g_la_privileged_out, g_la_user_out);
+
+ EDEB_EX(7, "cq_handle=%lx act_nr_of_entries=%x act_pages=%x ",
+ *cq_handle, cq_attr->act_nr_of_cqes, cq_attr->nr_pages);
+
+ return hret;
+}
+
+/* Defines for H_CALL H_ALLOC_RESOURCE */
+#define H_ALL_RES_TYPE_QP 1
+#define H_ALL_RES_TYPE_CQ 2
+#define H_ALL_RES_TYPE_EQ 3
+#define H_ALL_RES_TYPE_MR 5
+#define H_ALL_RES_TYPE_MW 6
+
+/* input param R5 */
+#define H_ALL_RES_EQ_NEQ EHEA_BMASK_IBM(0, 0)
+#define H_ALL_RES_EQ_NON_NEQ_ISN EHEA_BMASK_IBM(6, 7)
+#define H_ALL_RES_EQ_INH_EQE_GEN EHEA_BMASK_IBM(16, 16)
+#define H_ALL_RES_EQ_RES_TYPE EHEA_BMASK_IBM(56, 63)
+/* input param R6 */
+#define H_ALL_RES_EQ_MAX_EQE EHEA_BMASK_IBM(32, 63)
+
+/* output param R6 */
+#define H_ALL_RES_EQ_LIOBN EHEA_BMASK_IBM(32, 63)
+
+/* output param R7 */
+#define H_ALL_RES_EQ_ACT_EQE EHEA_BMASK_IBM(32, 63)
+
+/* output param R8 */
+#define H_ALL_RES_EQ_ACT_PS EHEA_BMASK_IBM(32, 63)
+
+/* output param R9 */
+#define H_ALL_RES_EQ_ACT_EQ_IST_C EHEA_BMASK_IBM(30, 31)
+#define H_ALL_RES_EQ_ACT_EQ_IST_1 EHEA_BMASK_IBM(40, 63)
+
+/* output param R10 */
+#define H_ALL_RES_EQ_ACT_EQ_IST_2 EHEA_BMASK_IBM(40, 63)
+
+/* output param R11 */
+#define H_ALL_RES_EQ_ACT_EQ_IST_3 EHEA_BMASK_IBM(40, 63)
+
+/* output param R12 */
+#define H_ALL_RES_EQ_ACT_EQ_IST_4 EHEA_BMASK_IBM(40, 63)
+
+u64 hipz_h_alloc_resource_eq(const u64 hcp_adapter_handle,
+ struct ehea_eq *ehea_eq,
+ struct ehea_eq_attr *eq_attr, u64 *eq_handle)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy;
+ u64 eq_liobn = 0;
+ u64 allocate_controls = 0;
+ u64 ist1_out = 0;
+ u64 ist2_out = 0;
+ u64 ist3_out = 0;
+ u64 ist4_out = 0;
+ u64 act_nr_of_eqes_out = 0;
+ u64 act_pages_out = 0;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lx new_control=%x "
+ "number_of_entries=%x",
+ hcp_adapter_handle, eq_attr->type, eq_attr->max_nr_of_eqes);
+
+ /* resource type */
+ allocate_controls =
+ EHEA_BMASK_SET(H_ALL_RES_EQ_RES_TYPE, H_ALL_RES_TYPE_EQ)
+ | EHEA_BMASK_SET(H_ALL_RES_EQ_NEQ, eq_attr->type ? 1 : 0)
+ | EHEA_BMASK_SET(H_ALL_RES_EQ_INH_EQE_GEN, !eq_attr->eqe_gen)
+ | EHEA_BMASK_SET(H_ALL_RES_EQ_NON_NEQ_ISN, 1);
+
+ hret = ehea_hcall_9arg_9ret(H_ALLOC_EHEA_RESOURCE,
+ hcp_adapter_handle, /* R4 */
+ allocate_controls, /* R5 */
+ eq_attr->max_nr_of_eqes, /* R6 */
+ 0, 0, 0, 0, 0, 0, /* R7-R10 */
+ eq_handle, /* R4 */
+ &dummy, /* R5 */
+ &eq_liobn, /* R6 */
+ &act_nr_of_eqes_out, /* R7 */
+ &act_pages_out, /* R8 */
+ &ist1_out, /* R9 */
+ &ist2_out, /* R10 */
+ &ist3_out, /* R11 */
+ &ist4_out); /* R12 */
+
+ eq_attr->act_nr_of_eqes = act_nr_of_eqes_out;
+ eq_attr->nr_pages = act_pages_out;
+ eq_attr->ist1 = ist1_out;
+ eq_attr->ist2 = ist2_out;
+ eq_attr->ist3 = ist3_out;
+ eq_attr->ist4 = ist4_out;
+
+ EDEB_EX(7, "act_nr_of_entries=%x act_pages=%x eq_ist1=%x",
+ eq_attr->act_nr_of_eqes, eq_attr->nr_pages, eq_attr->ist1);
+
+ return hret;
+}
+
+u64 hipz_h_modify_ehea_qp(const u64 hcp_adapter_handle,
+ const u8 cat,
+ const u64 qp_handle,
+ const u64 sel_mask,
+ void *cb_addr,
+ u64 *inv_attr_id,
+ u64 *proc_mask,
+ u16 *out_swr,
+ u16 *out_rwr)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy = 0;
+ u64 act_out_swr = 0;
+ u64 act_out_rwr = 0;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lX cat=%X qp_handle=%lX sel_mask=%lX "
+ "cb_addr=%p\n",
+ hcp_adapter_handle, (u16) cat, qp_handle, sel_mask, cb_addr);
+ if ((((u64)cb_addr) & (PAGE_SIZE - 1)) != 0)
+ panic("query_ehea_qp: cb_addr not on page boundary!!!");
+
+ EDEB_DMP(7, (u8 *) cb_addr, sizeof(struct hcp_modify_qp_cb_0),
+ "Before HCALL");
+
+ hret = ehea_hcall_9arg_9ret(H_MODIFY_EHEA_QP,
+ hcp_adapter_handle, /* R4 */
+ (u64) cat, /* R5 */
+ qp_handle, /* R6 */
+ sel_mask, /* R7 */
+ virt_to_abs(cb_addr), /* R8 */
+ 0, 0, 0, 0, /* R9-R12 */
+ inv_attr_id, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &act_out_swr, /* R7 */
+ &act_out_rwr, /* R8 */
+ proc_mask, /* R9 */
+ &dummy, /* R10 */
+ &dummy, /* R11 */
+ &dummy); /* R12 */
+ *out_swr = act_out_swr;
+ *out_rwr = act_out_rwr;
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "H_MODIFY_EHEA_QP failed. hret=%lx", hret);
+ }
+
+ EDEB_EX(7, "inv_attr_id=%lX proc_mask=%lX out_swr=%X out_rwr=%X",
+ *inv_attr_id, *proc_mask, *out_swr, *out_rwr);
+
+ return hret;
+}
+
+u64 hipz_h_register_rpage(const u64 hcp_adapter_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 resource_handle,
+ const u64 log_pageaddr, u64 count)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy;
+ u64 reg_control;
+ EDEB_EN(7, "hcp_adapter_handle=%lx pagesize=%x queue_type=%x "
+ "res_handle=%lx log_pageaddr=%lx "
+ "count=%lx",
+ hcp_adapter_handle,
+ pagesize, queue_type, resource_handle, log_pageaddr, count);
+
+ reg_control = EHEA_BMASK_SET(H_REG_RPAGE_PAGE_SIZE, pagesize)
+ | EHEA_BMASK_SET(H_REG_RPAGE_QT, queue_type);
+
+ hret = ehea_hcall_7arg_7ret(H_REGISTER_EHEA_RPAGES,
+ hcp_adapter_handle, /* R4 */
+ reg_control, /* R5 */
+ resource_handle, /* R6 */
+ log_pageaddr, /* R7 */
+ count, /* R8 */
+ 0, /* R9 */
+ 0, /* R10 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy); /* R10 */
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 hipz_h_register_rpage_eq(const u64 hcp_adapter_handle,
+ const u64 eq_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 log_pageaddr, const u64 count)
+{
+ u64 hret = H_ADAPTER_PARM;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lx eq_handle=%lx"
+ " pagesize=%x queue_type=%x log_pageaddr=%lx"
+ " count=%lx",
+ hcp_adapter_handle,
+ eq_handle, pagesize, queue_type, log_pageaddr, count);
+
+ if (count != 1) {
+ EDEB_ERR(4, "page counter=%lx", count);
+ return H_PARAMETER;
+ }
+
+ hret = hipz_h_register_rpage(hcp_adapter_handle,
+ pagesize,
+ queue_type,
+ eq_handle, log_pageaddr, count);
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 hipz_h_register_rpage_cq(const u64 hcp_adapter_handle,
+ const u64 cq_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 log_pageaddr,
+ const u64 count, const struct h_galpa gal)
+{
+ u64 hret = H_ADAPTER_PARM;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lx cq_handle=%lx"
+ " pagesize=%x queue_type=%x log_pageaddr=%lx"
+ " count=%lx",
+ hcp_adapter_handle,
+ cq_handle, pagesize, queue_type, log_pageaddr, count);
+
+ if (count != 1) {
+ EDEB_ERR(4, "page counter=%lx", count);
+ return H_PARAMETER;
+ }
+
+ hret = hipz_h_register_rpage(hcp_adapter_handle,
+ pagesize,
+ queue_type,
+ cq_handle, log_pageaddr, count);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 hipz_h_register_rpage_qp(const u64 hcp_adapter_handle,
+ const u64 qp_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 log_pageaddr,
+ const u64 count, struct h_galpa galpa)
+{
+ u64 hret = H_ADAPTER_PARM;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lx qp_handle=%lx"
+ " pagesize=%x queue_type=%x log_pageaddr=%lx"
+ " count=%lx",
+ hcp_adapter_handle,
+ qp_handle, pagesize, queue_type, log_pageaddr, count);
+
+ if (count != 1) {
+ EDEB_ERR(4, "page counter=%lx", count);
+ return H_PARAMETER;
+ }
+
+ hret = hipz_h_register_rpage(hcp_adapter_handle,
+ pagesize,
+ queue_type,
+ qp_handle, log_pageaddr, count);
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 hipz_h_destroy_qp(const u64 hcp_adapter_handle,
+ struct ehea_qp *qp,
+ u64 qp_handle, struct h_galpas *galpas)
+{
+ u64 hret = H_ADAPTER_PARM;
+ int ret = 0;
+ u64 dummy;
+ u64 ladr_next_sq_wqe_out;
+ u64 ladr_next_rq1_wqe_out;
+ u64 ladr_next_rq2_wqe_out;
+ u64 ladr_next_rq3_wqe_out;
+
+ EDEB_EN(7, "qp = %p ipz_qp_handle=%lx adapter_handle=%lx",
+ qp, qp_handle, hcp_adapter_handle);
+
+ ret = hcp_galpas_dtor(galpas);
+ if (ret) {
+ EDEB_ERR(4, "Could not destroy qp->galpas");
+ return H_RESOURCE;
+ }
+
+ hret = ehea_hcall_7arg_7ret(H_DISABLE_AND_GET_EHEA,
+ hcp_adapter_handle, /* R4 */
+ H_DISABLE_GET_EHEA_WQE_P, /* R5 */
+ qp_handle, /* R6 */
+ 0, 0, 0, 0, /* R7-R10 */
+ &ladr_next_sq_wqe_out, /* R4 */
+ &ladr_next_rq1_wqe_out, /* R5 */
+ &ladr_next_rq2_wqe_out, /* R6 */
+ &ladr_next_rq3_wqe_out, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy); /* R10 */
+ if (hret == H_HARDWARE) {
+ EDEB_ERR(4, "HCA NOT operational - hret=%lx", hret);
+ return hret;
+ }
+
+ hret = ehea_hcall_7arg_7ret(H_FREE_RESOURCE,
+ hcp_adapter_handle, /* R4 */
+ qp_handle, /* R5 */
+ 0, /* R6 */
+ 0, 0, 0, 0, /* R7-R10 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy); /* R10 */
+ if (hret == H_RESOURCE)
+ EDEB_ERR(4, "resource still in use - hret=%lx", hret);
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 hipz_h_destroy_cq(const u64 hcp_adapter_handle,
+ struct ehea_cq *cq,
+ u64 cq_handle, struct h_galpas *galpas)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy;
+
+ EDEB_EN(7, "destroy CQ Entry:>>>> cq = %p ,ipz_cq_handle=%lx"
+ "; adapter_handle=%lx", cq, cq_handle,
+ hcp_adapter_handle);
+ hret = hcp_galpas_dtor(galpas);
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "could not destroy cp->galpas");
+ return H_RESOURCE;
+ }
+
+ hret = ehea_hcall_7arg_7ret(H_FREE_RESOURCE,
+ hcp_adapter_handle, /* R4 */
+ cq_handle, /* R5 */
+ 0, /* R6 */
+ 0, 0, 0, 0, /* R7-R10 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy); /* R10 */
+
+ if (hret == H_RESOURCE)
+ EDEB_ERR(4, "resource in use - hret=%lx ", hret);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 hipz_h_destroy_eq(const u64 hcp_adapter_handle,
+ struct ehea_eq * eq,
+ u64 eq_handle, struct h_galpas * galpas)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy;
+
+ EDEB_EN(7, "eq=%p ipz_eq_handle=%lx adapter_handle=%lx",
+ eq, eq_handle, hcp_adapter_handle);
+
+ hret = hcp_galpas_dtor(galpas);
+
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "could not destroy ep->galpas");
+ return H_RESOURCE;
+ }
+
+ hret = ehea_hcall_7arg_7ret(H_FREE_RESOURCE,
+ hcp_adapter_handle, /* R4 */
+ eq_handle, /* R5 */
+ 0, /* R6 */
+ 0, 0, 0, 0, /* R7-R10 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy); /* R10 */
+
+ if (hret == H_RESOURCE)
+ EDEB_ERR(4, "resource in use - hret=%lx ", hret);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 hipz_h_free_resource_mr(const u64 hcp_adapter_handle,
+ const u64 mr_handle)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy;
+
+ EDEB_EN(7, "adapter_handle=%lx mr_handle=%lx",
+ hcp_adapter_handle, mr_handle);
+
+ hret = ehea_hcall_7arg_7ret(H_FREE_RESOURCE,
+ hcp_adapter_handle, /* r4 */
+ mr_handle, /* r5 */
+ 0, 0, 0, 0, 0,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy,
+ &dummy);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 hipz_h_alloc_resource_mr(const u64 hcp_adapter_handle,
+ const u64 vaddr,
+ const u64 length,
+ const u32 access_ctrl,
+ const u32 pd, u64 * mr_handle, u32 * lkey)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy;
+ u64 lkey_out;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lx vaddr=%lx length=%lx "
+ "access_ctrl=%x pd=%x",
+ hcp_adapter_handle, vaddr, length, access_ctrl, pd);
+
+
+ hret = ehea_hcall_7arg_7ret(H_ALLOC_EHEA_RESOURCE,
+ hcp_adapter_handle, /* R4 */
+ 5, /* R5 */
+ vaddr, /* R6 */
+ length, /* R7 */
+ (((u64) access_ctrl) << 32ULL), /* R8 */
+ pd, /* R9 */
+ 0, /* R10 */
+ mr_handle, /* R4 */
+ &dummy, /* R5 */
+ &lkey_out, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy); /* R10 */
+ *lkey = (u32) lkey_out;
+
+ EDEB_EX(7, "hret=%lX mr_handle=%lX, lkey=%x", hret, *mr_handle, *lkey);
+ return hret;
+}
+
+u64 hipz_h_register_rpage_mr(const u64 hcp_adapter_handle,
+ const u64 mr_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 log_pageaddr, const u64 count)
+{
+ u64 hret = H_ADAPTER_PARM;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lx mr_handle->handle=%lx"
+ " pagesize=%x queue_type=%x log_pageaddr=%lx"
+ " count=%lx",
+ hcp_adapter_handle,
+ mr_handle, pagesize, queue_type, log_pageaddr, count);
+
+ if ((count > 1) && (log_pageaddr & 0xfff)) {
+ EDEB_ERR(4, "log_pageaddr not on a 4k boundary");
+ hret = H_PARAMETER;
+ } else
+ hret = hipz_h_register_rpage(hcp_adapter_handle,
+ pagesize,
+ queue_type,
+ mr_handle, log_pageaddr, count);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 hipz_h_query_ehea(const u64 hcp_adapter_handle, void *cb_addr)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy = 0;
+ struct hcp_query_ehea *query_ehea_cb = (struct hcp_query_ehea *)cb_addr;
+ u64 cb_logaddr;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lX query_ehea_cb=%p",
+ hcp_adapter_handle, query_ehea_cb);
+
+ cb_logaddr = virt_to_abs(cb_addr);
+
+ hret = ehea_hcall_7arg_7ret(H_QUERY_EHEA,
+ hcp_adapter_handle, /* >R4 */
+ cb_logaddr, /* >R5 */
+ 0, 0, 0, 0, 0, /* >R6-R10 */
+ &dummy, /* <R4 */
+ &dummy, /* <R5 */
+ &dummy, /* <R6 */
+ &dummy, /* <R7 */
+ &dummy, /* <R8 */
+ &dummy, /* <R9 */
+ &dummy); /* <R10 */
+
+ EDEB_DMP(7, (u8 *) cb_addr, sizeof(struct hcp_query_ehea),
+ "hcp_query_ehea");
+
+ if (hret != H_SUCCESS)
+ EDEB_ERR(4, "H_QUERY_EHEA failed. hret=%lx", hret);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 hipz_h_query_ehea_port(const u64 hcp_adapter_handle,
+ const u16 port_num,
+ const u8 cb_cat, const u64 select_mask,
+ void *cb_addr)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 port_info = 0;
+ u64 arr_index = 0;
+ u64 dummy = 0;
+ u64 cb_logaddr = virt_to_abs(cb_addr);
+
+ EDEB_EN(7, "hcp_adapter_handle=%lX port_num=%X cb_cat=%X "
+ "select_mask=%lX cb_addr=%lX",
+ hcp_adapter_handle, port_num, cb_cat, select_mask, cb_logaddr);
+
+ port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat)
+ | EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num);
+
+ hret = ehea_hcall_7arg_7ret(H_QUERY_EHEA_PORT,
+ hcp_adapter_handle, /* >R4 */
+ port_info, /* >R5 */
+ select_mask, /* >R6 */
+ arr_index, /* >R7 */
+ cb_logaddr, /* >R8 */
+ 0, 0, /* >R9-R10 */
+ &dummy, /* <R4 */
+ &dummy, /* <R5 */
+ &dummy, /* <R6 */
+ &dummy, /* <R7 */
+ &dummy, /* <R8 */
+ &dummy, /* <R9 */
+ &dummy); /* <R10 */
+ if (hret != H_SUCCESS)
+ EDEB_ERR(4, "H_QUERY_EHEA_PORT failed. hret=%lx", hret);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 hipz_h_modify_ehea_port(const u64 hcp_adapter_handle,
+ const u16 port_num,
+ const u8 cb_cat,
+ const u64 select_mask, void *cb_addr)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 port_info = 0;
+ u64 arr_index = 0;
+ u64 dummy = 0;
+ u64 cb_logaddr = virt_to_abs(cb_addr);
+
+ EDEB_EN(7, "hcp_adapter_handle=%lX port_num=%X cb_cat=%X "
+ "select_mask=%lX cb_addr=%lX",
+ hcp_adapter_handle, port_num, cb_cat, select_mask, cb_logaddr);
+
+ port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat)
+ | EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num);
+
+ EDEB_DMP(7, (u8 *) cb_addr,
+ sizeof(struct hcp_query_ehea_port_cb_0), "Before HCALL");
+
+ hret = ehea_hcall_7arg_7ret(H_MODIFY_EHEA_PORT,
+ hcp_adapter_handle, /* >R4 */
+ port_info, /* >R5 */
+ select_mask, /* >R6 */
+ arr_index, /* >R7 */
+ cb_logaddr, /* >R8 */
+ 0, 0, /* >R9-R10 */
+ &dummy, /* <R4 */
+ &dummy, /* <R5 */
+ &dummy, /* <R6 */
+ &dummy, /* <R7 */
+ &dummy, /* <R8 */
+ &dummy, /* <R9 */
+ &dummy); /* <R10 */
+
+
+ if (hret != H_SUCCESS)
+ EDEB_ERR(4, "H_MODIFY_EHEA_PORT failed. hret=%lx", hret);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 hipz_h_reg_dereg_bcmc(const u64 hcp_adapter_handle,
+ const u16 port_num,
+ const u8 reg_type,
+ const u64 mc_mac_addr,
+ const u16 vlan_id, const u32 hcall_id)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 r5_port_num = 0;
+ u64 r6_reg_type = 0;
+ u64 r7_mc_mac_addr = 0;
+ u64 r8_vlan_id = 0;
+ u64 dummy = 0;
+
+ u64 mac_addr = mc_mac_addr >> 16;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lX port_num=%X reg_type=%X "
+ "mc_mac_addr=%lX hcall_id=%X",
+ hcp_adapter_handle, port_num, reg_type, mc_mac_addr, hcall_id);
+
+ r5_port_num = EHEA_BMASK_SET(H_REGBCMC_PN, port_num);
+ r6_reg_type = EHEA_BMASK_SET(H_REGBCMC_REGTYPE, reg_type);
+ r7_mc_mac_addr = EHEA_BMASK_SET(H_REGBCMC_MACADDR, mac_addr);
+ r8_vlan_id = EHEA_BMASK_SET(H_REGBCMC_VLANID, vlan_id);
+
+
+ hret = ehea_hcall_7arg_7ret(hcall_id,
+ hcp_adapter_handle, /* >R4 */
+ r5_port_num, /* >R5 */
+ r6_reg_type, /* >R6 */
+ r7_mc_mac_addr, /* >R7 */
+ r8_vlan_id, /* >R8 */
+ 0, 0, /* >R9-R10 */
+ &dummy, /* <R4 */
+ &dummy, /* <R5 */
+ &dummy, /* <R6 */
+ &dummy, /* <R7 */
+ &dummy, /* <R8 */
+ &dummy, /* <R9 */
+ &dummy); /* <R10 */
+
+ if (hret != H_SUCCESS)
+ EDEB_ERR(4, "HCALL 0x%x failed. hret=%lx", hcall_id, hret);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
+
+u64 hipz_h_reset_events(const u64 hcp_adapter_handle,
+ const u64 neq_handle, const u64 event_mask)
+{
+ u64 hret = H_ADAPTER_PARM;
+ u64 dummy = 0;
+
+ EDEB_EN(7, "hcp_adapter_handle=%lX neq_handle=%lX event_mask=%lX ",
+ hcp_adapter_handle, neq_handle, event_mask);
+
+ hret = ehea_hcall_7arg_7ret(H_RESET_EVENTS,
+ hcp_adapter_handle, /* >R4 */
+ neq_handle, /* >R5 */
+ event_mask, /* >R6 */
+ 0, 0, 0, 0, /* >R7-R10 */
+ &dummy, /* <R4 */
+ &dummy, /* <R5 */
+ &dummy, /* <R6 */
+ &dummy, /* <R7 */
+ &dummy, /* <R8 */
+ &dummy, /* <R9 */
+ &dummy); /* <R10 */
+ if (hret != H_SUCCESS)
+ EDEB_ERR(4, "H_RESET_EVENTS failed. hret=%lx", hret);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return hret;
+}
--- linux-2.6.16-rc5-orig/drivers/net/ehea/ehea_phyp.h 1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_phyp.h 2006-06-07 07:01:15.392198488 -0700
@@ -0,0 +1,625 @@
+/*
+ * linux/drivers/net/ehea/ehea_phyp.h
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Heiko-Joerg Schick <schickhj@de.ibm.com>
+ * Thomas Klein <tklein@de.ibm.com>
+ *
+ *
+ * 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __EHEA_PHYP_H__
+#define __EHEA_PHYP_H__
+
+#include <linux/delay.h>
+#include <asm/hvcall.h>
+#include "ehea.h"
+#include "ehea_hw.h"
+#include "ehea_hcall.h"
+
+
+static inline u32 get_longbusy_msecs(int long_busy_ret_code)
+{
+ switch (long_busy_ret_code) {
+ case H_LONG_BUSY_ORDER_1_MSEC:
+ return 1;
+ case H_LONG_BUSY_ORDER_10_MSEC:
+ return 10;
+ case H_LONG_BUSY_ORDER_100_MSEC:
+ return 100;
+ case H_LONG_BUSY_ORDER_1_SEC:
+ return 1000;
+ case H_LONG_BUSY_ORDER_10_SEC:
+ return 10000;
+ case H_LONG_BUSY_ORDER_100_SEC:
+ return 100000;
+ default:
+ return 1;
+ }
+}
+
+
+/* Notification Event Queue (NEQ) Entry bit masks */
+#define NEQE_EVENT_CODE EHEA_BMASK_IBM(2, 7)
+#define NEQE_PORTNUM EHEA_BMASK_IBM(32, 47)
+#define NEQE_PORT_UP EHEA_BMASK_IBM(16, 16)
+#define NEQE_EXTSWITCH_PORT_UP EHEA_BMASK_IBM(17, 17)
+#define NEQE_EXTSWITCH_PRIMARY EHEA_BMASK_IBM(18, 18)
+#define NEQE_PLID EHEA_BMASK_IBM(16, 47)
+
+/* Notification Event Codes */
+#define EHEA_EC_PORTSTATE_CHG 0x30
+#define EHEA_EC_ADAPTER_MALFUNC 0x32
+#define EHEA_EC_PORT_MALFUNC 0x33
+
+/* Notification Event Log Register (NELR) bit masks */
+#define NELR_PORT_MALFUNC EHEA_BMASK_IBM(61, 61)
+#define NELR_ADAPTER_MALFUNC EHEA_BMASK_IBM(62, 62)
+#define NELR_PORTSTATE_CHG EHEA_BMASK_IBM(63, 63)
+
+static inline long ehea_hcall_9arg_9ret(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6,
+ unsigned long arg7,
+ unsigned long arg8,
+ unsigned long arg9,
+ unsigned long *out1,
+ unsigned long *out2,
+ unsigned long *out3,
+ unsigned long *out4,
+ unsigned long *out5,
+ unsigned long *out6,
+ unsigned long *out7,
+ unsigned long *out8,
+ unsigned long *out9)
+{
+ long hret = H_SUCCESS;
+ int i, sleep_msecs;
+
+ EDEB_EN(7, "opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx "
+ "arg5=%lx arg6=%lx arg7=%lx arg8=%lx arg9=%lx",
+ opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+ arg8, arg9);
+
+
+ for (i = 0; i < 5; i++) {
+ hret = plpar_hcall_9arg_9ret(opcode,
+ arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7, arg8,
+ arg9,
+ out1, out2, out3, out4,
+ out5, out6, out7, out8,
+ out9);
+
+ if (H_IS_LONG_BUSY(hret)) {
+ sleep_msecs = get_longbusy_msecs(hret);
+ msleep_interruptible(sleep_msecs);
+ continue;
+ }
+
+ if (hret < H_SUCCESS)
+ EDEB_ERR(4, "opcode=%lx hret=%lx"
+ " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
+ " arg5=%lx arg6=%lx arg7=%lx arg8=%lx"
+ " arg9=%lx"
+ " out1=%lx out2=%lx out3=%lx out4=%lx"
+ " out5=%lx out6=%lx out7=%lx out8=%lx"
+ " out9=%lx",
+ opcode, hret,
+ arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7, arg8,
+ arg9,
+ *out1, *out2, *out3, *out4,
+ *out5, *out6, *out7, *out8,
+ *out9);
+
+ EDEB_EX(7, "opcode=%lx hret=%lx out1=%lx out2=%lx out3=%lx "
+ "out4=%lx out5=%lx out6=%lx out7=%lx out8=%lx out9=%lx",
+ opcode, hret,*out1, *out2, *out3, *out4, *out5, *out6,
+ *out7, *out8, *out9);
+ return hret;
+
+ }
+
+ EDEB_EX(7, "opcode=%lx ret=H_BUSY", opcode);
+ return H_BUSY;
+}
+
+inline static long ehea_hcall_7arg_7ret(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6,
+ unsigned long arg7,
+ unsigned long *out1,
+ unsigned long *out2,
+ unsigned long *out3,
+ unsigned long *out4,
+ unsigned long *out5,
+ unsigned long *out6,
+ unsigned long *out7)
+{
+ long hret = H_SUCCESS;
+ int i, sleep_msecs;
+
+ EDEB_EN(7, "opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx arg5=%lx"
+ " arg6=%lx arg7=%lx", opcode, arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7);
+
+ for (i = 0; i < 5; i++) {
+ hret = plpar_hcall_7arg_7ret(opcode,
+ arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7,
+ out1, out2, out3, out4,
+ out5, out6, out7);
+
+ if (H_IS_LONG_BUSY(hret)) {
+ sleep_msecs = get_longbusy_msecs(hret);
+ msleep_interruptible(sleep_msecs);
+ continue;
+ }
+
+ if (hret < H_SUCCESS)
+ EDEB_ERR(4, "opcode=%lx ret=%lx"
+ " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
+ " arg5=%lx arg6=%lx arg7=%lx"
+ " out1=%lx out2=%lx out3=%lx out4=%lx"
+ " out5=%lx out6=%lx out7=%lx",
+ opcode, hret,
+ arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7,
+ *out1, *out2, *out3, *out4,
+ *out5, *out6, *out7);
+
+ EDEB_EX(7, "opcode=%lx hret=%lx out1=%lx out2=%lx out3=%lx "
+ "out4=%lx out5=%lx out6=%lx out7=%lx",
+ opcode, hret, *out1, *out2, *out3, *out4, *out5,
+ *out6, *out7);
+ return hret;
+ }
+
+ EDEB_EX(7, "opcode=%lx hret=H_BUSY", opcode);
+
+ return H_BUSY;
+}
+
+static inline int hcp_galpas_ctor(struct h_galpas *galpas,
+ u64 paddr_kernel, u64 paddr_user)
+{
+
+ EDEB_EN(7, "ioremap physaddr=%lx mapaddr=%lx\n",
+ paddr_kernel, galpas->kernel.fw_handle);
+ galpas->kernel.fw_handle = (u64) ioremap(paddr_kernel, PAGE_SIZE);
+ galpas->user.fw_handle = paddr_user;
+
+ EDEB_EX(7, "paddr_kernel=%lx paddr_user=%lx galpas->kernel=%lx"
+ " galpas->user=%lx", paddr_kernel, paddr_user,
+ galpas->kernel.fw_handle, galpas->user.fw_handle);
+ return 0;
+}
+
+static inline int hcp_galpas_dtor(struct h_galpas *galpas)
+{
+
+ if (galpas->kernel.fw_handle)
+ iounmap((void *)galpas->kernel.fw_handle);
+ galpas->user.fw_handle = galpas->kernel.fw_handle = 0;
+ return 0;
+}
+
+struct hcp_modify_qp_cb_0 {
+ u64 qp_ctl_reg; /* 00 */
+ u32 max_swqe; /* 02 */
+ u32 max_rwqe; /* 03 */
+ u32 port_nb; /* 04 */
+ u32 reserved0; /* 05 */
+ u64 qp_aer; /* 06 */
+ u64 qp_tenure; /* 08 */
+};
+
+/* Hcall Query/Modify Queue Pair Control Block 0 Selection Mask Bits */
+#define H_QPCB0_ALL EHEA_BMASK_IBM(0, 5)
+#define H_QPCB0_QP_CTL_REG EHEA_BMASK_IBM(0, 0)
+#define H_QPCB0_MAX_SWQE EHEA_BMASK_IBM(1, 1)
+#define H_QPCB0_MAX_RWQE EHEA_BMASK_IBM(2, 2)
+#define H_QPCB0_PORT_NB EHEA_BMASK_IBM(3, 3)
+#define H_QPCB0_QP_AER EHEA_BMASK_IBM(4, 4)
+#define H_QPCB0_QP_TENURE EHEA_BMASK_IBM(5, 5)
+
+/* Queue Pair Control Register Status Bits */
+#define H_QP_CR_ENABLED 0x8000000000000000 /* Queue Pair enabled */
+ /* QP States: */
+#define H_QP_CR_STATE_RESET 0x0000010000000000 /* Reset */
+#define H_QP_CR_STATE_INITIALIZED 0x0000020000000000 /* Initialized */
+#define H_QP_CR_STATE_RDY2RCV 0x0000030000000000 /* Ready to receive */
+#define H_QP_CR_STATE_RDY2SND 0x0000050000000000 /* Ready to send */
+#define H_QP_CR_STATE_ERROR 0x0000800000000000 /* Error */
+
+struct hcp_modify_qp_cb_1 {
+ u32 qpn; /* 00 */
+ u32 qp_asyn_ev_eq_nb; /* 01 */
+ u64 sq_cq_handle; /* 02 */
+ u64 rq_cq_handle; /* 04 */
+ /* sgel = scatter gather element */
+ u32 sgel_nb_sq; /* 06 */
+ u32 sgel_nb_rq1; /* 07 */
+ u32 sgel_nb_rq2; /* 08 */
+ u32 sgel_nb_rq3; /* 09 */
+};
+
+/* Hcall Query/Modify Queue Pair Control Block 1 Selection Mask Bits */
+#define H_QPCB1_ALL EHEA_BMASK_IBM(0, 7)
+#define H_QPCB1_QPN EHEA_BMASK_IBM(0, 0)
+#define H_QPCB1_ASYN_EV_EQ_NB EHEA_BMASK_IBM(1, 1)
+#define H_QPCB1_SQ_CQ_HANDLE EHEA_BMASK_IBM(2, 2)
+#define H_QPCB1_RQ_CQ_HANDLE EHEA_BMASK_IBM(3, 3)
+#define H_QPCB1_SGEL_NB_SQ EHEA_BMASK_IBM(4, 4)
+#define H_QPCB1_SGEL_NB_RQ1 EHEA_BMASK_IBM(5, 5)
+#define H_QPCB1_SGEL_NB_RQ2 EHEA_BMASK_IBM(6, 6)
+#define H_QPCB1_SGEL_NB_RQ3 EHEA_BMASK_IBM(7, 7)
+
+struct hcp_query_ehea {
+ u32 cur_num_qps; /* 00 */
+ u32 cur_num_cqs; /* 01 */
+ u32 cur_num_eqs; /* 02 */
+ u32 cur_num_mrs; /* 03 */
+ u32 auth_level; /* 04 */
+ u32 max_num_qps; /* 05 */
+ u32 max_num_cqs; /* 06 */
+ u32 max_num_eqs; /* 07 */
+ u32 max_num_mrs; /* 08 */
+ u32 reserved0; /* 09 */
+ u32 int_clock_freq; /* 10 */
+ u32 max_num_pds; /* 11 */
+ u32 max_num_addr_handles; /* 12 */
+ u32 max_num_cqes; /* 13 */
+ u32 max_num_wqes; /* 14 */
+ u32 max_num_sgel_rq1wqe; /* 15 */
+ u32 max_num_sgel_rq2wqe; /* 16 */
+ u32 max_num_sgel_rq3wqe; /* 17 */
+ u32 mr_page_size; /*define */
+ u32 reserved1; /* 19 */
+ u64 max_mr_size; /* 20 */
+ u64 reserved2; /* 22 */
+ u32 num_ports; /* 24 */
+ u32 reserved3; /* 25 */
+ u32 reserved4; /* 26 */
+ u32 reserved5; /* 27 */
+ u64 max_mc_mac; /* 28 */
+ u64 ehea_cap; /* 30 */
+ u32 max_isn_per_eq; /* 32 */
+ u32 max_num_neq; /* 33 */
+ u64 max_num_vlan_ids; /* 34 */
+ u32 max_num_port_group; /* 36 */
+ u32 max_num_phys_port; /* 37 */
+
+};
+
+/* Hcall Query/Modify Port Control Block defines */
+#define H_PORT_CB0 0
+#define H_PORT_CB1 1
+#define H_PORT_CB2 2
+#define H_PORT_CB3 3
+#define H_PORT_CB4 4
+#define H_PORT_CB5 5
+#define H_PORT_CB6 6
+#define H_PORT_CB7 7
+
+struct hcp_query_ehea_port_cb_0 {
+ u64 port_mac_addr;
+ u64 port_rc;
+ u64 reserved0;
+ u32 port_op_state;
+ u32 port_speed;
+ u32 ext_swport_op_state;
+ u32 neg_tpf_prpf;
+ u32 num_default_qps;
+ u32 reserved1;
+ u64 default_qpn_array[16];
+};
+
+/* Hcall Query/Modify Port Control Block 0 Selection Mask Bits */
+#define H_PORT_CB0_ALL EHEA_BMASK_IBM(0, 7) /* Set all bits */
+#define H_PORT_CB0_MAC EHEA_BMASK_IBM(0, 0) /* MAC address */
+#define H_PORT_CB0_PRC EHEA_BMASK_IBM(1, 1) /* Port Recv Control */
+#define H_PORT_CB0_DEFQPNARRAY EHEA_BMASK_IBM(7, 7) /* Default QPN Array */
+
+/* Hcall Query Port: Returned port speed values */
+#define H_PORT_SPEED_10M_H 1 /* 10 Mbps, Half Duplex */
+#define H_PORT_SPEED_10M_F 2 /* 10 Mbps, Full Duplex */
+#define H_PORT_SPEED_100M_H 3 /* 100 Mbps, Half Duplex */
+#define H_PORT_SPEED_100M_F 4 /* 100 Mbps, Full Duplex */
+#define H_PORT_SPEED_1G_F 6 /* 1 Gbps, Full Duplex */
+#define H_PORT_SPEED_10G_F 8 /* 10 Gbps, Full Duplex */
+
+/* Port Receive Control Status Bits */
+#define PXLY_RC_VALID EHEA_BMASK_IBM(49, 49)
+#define PXLY_RC_VLAN_XTRACT EHEA_BMASK_IBM(50, 50)
+#define PXLY_RC_TCP_6_TUPLE EHEA_BMASK_IBM(51, 51)
+#define PXLY_RC_UDP_6_TUPLE EHEA_BMASK_IBM(52, 52)
+#define PXLY_RC_TCP_3_TUPLE EHEA_BMASK_IBM(53, 53)
+#define PXLY_RC_TCP_2_TUPLE EHEA_BMASK_IBM(54, 54)
+#define PXLY_RC_LLC_SNAP EHEA_BMASK_IBM(55, 55)
+#define PXLY_RC_JUMBO_FRAME EHEA_BMASK_IBM(56, 56)
+#define PXLY_RC_FRAG_IP_PKT EHEA_BMASK_IBM(57, 57)
+#define PXLY_RC_TCP_UDP_CHKSUM EHEA_BMASK_IBM(58, 58)
+#define PXLY_RC_IP_CHKSUM EHEA_BMASK_IBM(59, 59)
+#define PXLY_RC_MAC_FILTER EHEA_BMASK_IBM(60, 60)
+#define PXLY_RC_UNTAG_FILTER EHEA_BMASK_IBM(61, 61)
+#define PXLY_RC_VLAN_TAG_FILTER EHEA_BMASK_IBM(62, 63)
+
+#define PXLY_RC_VLAN_FILTER 2
+#define PXLY_RC_VLAN_PERM 0
+
+
+#define H_PORT_CB1_ALL 0x8000000000000000
+
+struct hcp_query_ehea_port_cb_1 {
+ u64 vlan_filter[64];
+};
+
+#define H_PORT_CB2_ALL 0xFFE0000000000000
+
+struct hcp_query_ehea_port_cb_2 {
+ u64 rxo;
+ u64 rxucp;
+ u64 rxufd;
+ u64 rxuerr;
+ u64 rxftl;
+ u64 rxmcp;
+ u64 rxbcp;
+ u64 txo;
+ u64 txucp;
+ u64 txmcp;
+ u64 txbcp;
+};
+
+struct hcp_query_ehea_port_cb_3 {
+ u64 vlan_bc_filter[64];
+ u64 vlan_mc_filter[64];
+ u64 vlan_un_filter[64];
+ u64 port_mac_hash_array[64];
+};
+
+#define H_PORT_CB4_ALL 0xF000000000000000
+#define H_PORT_CB4_JUMBO 0x1000000000000000
+
+struct hcp_query_ehea_port_cb_4 {
+ u32 port_speed;
+ u32 pause_frame;
+ u32 ens_port_op_state;
+ u32 jumbo_frame;
+ u32 ens_port_wrap;
+};
+
+struct hcp_query_ehea_port_cb_5 {
+ u64 prc; /* 00 */
+ u64 uaa; /* 01 */
+ u64 macvc; /* 02 */
+ u64 xpcsc; /* 03 */
+ u64 xpcsp; /* 04 */
+ u64 pcsid; /* 05 */
+ u64 xpcsst; /* 06 */
+ u64 pthlb; /* 07 */
+ u64 pthrb; /* 08 */
+ u64 pqu; /* 09 */
+ u64 pqd; /* 10 */
+ u64 prt; /* 11 */
+ u64 wsth; /* 12 */
+ u64 rcb; /* 13 */
+ u64 rcm; /* 14 */
+ u64 rcu; /* 15 */
+ u64 macc; /* 16 */
+ u64 pc; /* 17 */
+ u64 pst; /* 18 */
+ u64 ducqpn; /* 19 */
+ u64 mcqpn; /* 20 */
+ u64 mma; /* 21 */
+ u64 pmc0h; /* 22 */
+ u64 pmc0l; /* 23 */
+ u64 lbc; /* 24 */
+};
+
+#define H_PORT_CB6_ALL 0xFFFFFE7FFFFF8000
+
+struct hcp_query_ehea_port_cb_6 {
+ u64 rxo; /* 00 */
+ u64 rx64; /* 01 */
+ u64 rx65; /* 02 */
+ u64 rx128; /* 03 */
+ u64 rx256; /* 04 */
+ u64 rx512; /* 05 */
+ u64 rx1024; /* 06 */
+ u64 rxbfcs; /* 07 */
+ u64 rxime; /* 08 */
+ u64 rxrle; /* 09 */
+ u64 rxorle; /* 10 */
+ u64 rxftl; /* 11 */
+ u64 rxjab; /* 12 */
+ u64 rxse; /* 13 */
+ u64 rxce; /* 14 */
+ u64 rxrf; /* 15 */
+ u64 rxfrag; /* 16 */
+ u64 rxuoc; /* 17 */
+ u64 rxcpf; /* 18 */
+ u64 rxsb; /* 19 */
+ u64 rxfd; /* 20 */
+ u64 rxoerr; /* 21 */
+ u64 rxaln; /* 22 */
+ u64 ducqpn; /* 23 */
+ u64 reserved0; /* 24 */
+ u64 rxmcp; /* 25 */
+ u64 rxbcp; /* 26 */
+ u64 txmcp; /* 27 */
+ u64 txbcp; /* 28 */
+ u64 txo; /* 29 */
+ u64 tx64; /* 30 */
+ u64 tx65; /* 31 */
+ u64 tx128; /* 32 */
+ u64 tx256; /* 33 */
+ u64 tx512; /* 34 */
+ u64 tx1024; /* 35 */
+ u64 txbfcs; /* 36 */
+ u64 txcpf; /* 37 */
+ u64 txlf; /* 38 */
+ u64 txrf; /* 39 */
+ u64 txime; /* 40 */
+ u64 txsc; /* 41 */
+ u64 txmc; /* 42 */
+ u64 txsqe; /* 43 */
+ u64 txdef; /* 44 */
+ u64 txlcol; /* 45 */
+ u64 txexcol; /* 46 */
+ u64 txcse; /* 47 */
+ u64 txbor; /* 48 */
+};
+
+struct hcp_query_ehea_port_cb_7 {
+ u64 def_uc_qpn;
+};
+
+u64 hipz_h_query_ehea_qp(const u64 hcp_adapter_handle,
+ const u8 qp_category,
+ const u64 qp_handle, const u64 sel_mask,
+ void *cb_addr);
+
+u64 hipz_h_modify_ehea_qp(const u64 hcp_adapter_handle,
+ const u8 cat,
+ const u64 qp_handle,
+ const u64 sel_mask,
+ void *cb_addr,
+ u64 * inv_attr_id,
+ u64 * proc_mask, u16 * out_swr, u16 * out_rwr);
+
+u64 hipz_h_alloc_resource_eq(const u64 hcp_adapter_handle,
+ struct ehea_eq *ehea_eq,
+ struct ehea_eq_attr *eq_attr, u64 * eq_handle);
+
+u64 hipz_h_alloc_resource_cq(const u64 hcp_adapter_handle,
+ struct ehea_cq *ehea_cq,
+ struct ehea_cq_attr *cq_attr,
+ u64 * cq_handle, struct h_galpas *galpas);
+
+u64 hipz_h_alloc_resource_qp(const u64 adapter_handle,
+ struct ehea_qp *ehea_qp,
+ struct ehea_qp_init_attr *init_attr,
+ const u32 pd,
+ u64 * qp_handle, struct h_galpas *h_galpas);
+
+#define H_REG_RPAGE_PAGE_SIZE EHEA_BMASK_IBM(48,55)
+#define H_REG_RPAGE_QT EHEA_BMASK_IBM(62,63)
+
+u64 hipz_h_register_rpage(const u64 hcp_adapter_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 resource_handle,
+ const u64 log_pageaddr, u64 count);
+
+u64 hipz_h_register_rpage_eq(const u64 hcp_adapter_handle,
+ const u64 eq_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 log_pageaddr, const u64 count);
+
+u64 hipz_h_register_rpage_cq(const u64 hcp_adapter_handle,
+ const u64 cq_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 log_pageaddr,
+ const u64 count, const struct h_galpa gal);
+
+u64 hipz_h_register_rpage_qp(const u64 hcp_adapter_handle,
+ const u64 qp_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 log_pageaddr,
+ const u64 count, struct h_galpa galpa);
+
+#define H_DISABLE_GET_EHEA_WQE_P 1
+#define H_DISABLE_GET_SQ_WQE_P 2
+#define H_DISABLE_GET_RQC 3
+
+u64 hipz_h_destroy_qp(const u64 hcp_adapter_handle,
+ struct ehea_qp *qp,
+ u64 qp_handle, struct h_galpas *galpas);
+
+u64 hipz_h_destroy_cq(const u64 hcp_adapter_handle,
+ struct ehea_cq *cq,
+ u64 cq_handle, struct h_galpas *galpas);
+
+u64 hipz_h_destroy_eq(const u64 hcp_adapter_handle,
+ struct ehea_eq *eq,
+ u64 eq_handle, struct h_galpas *galpas);
+
+u64 hipz_h_free_resource_mr(const u64 hcp_adapter_handle,
+ const u64 mr_handle);
+
+
+u64 hipz_h_alloc_resource_mr(const u64 hcp_adapter_handle,
+ const u64 vaddr,
+ const u64 length,
+ const u32 access_ctrl,
+ const u32 pd, u64 * mr_handle, u32 * lkey);
+
+u64 hipz_h_register_rpage_mr(const u64 hcp_adapter_handle,
+ const u64 mr_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 log_pageaddr, const u64 count);
+
+u64 hipz_h_query_ehea(const u64 hcp_adapter_handle, void *cb_addr);
+
+/* output param R5 */
+#define H_MEHEAPORT_CAT EHEA_BMASK_IBM(40,47)
+#define H_MEHEAPORT_PN EHEA_BMASK_IBM(48,63)
+
+u64 hipz_h_query_ehea_port(const u64 hcp_adapter_handle,
+ const u16 port_num,
+ const u8 cb_cat,
+ const u64 select_mask, void *cb_addr);
+
+u64 hipz_h_modify_ehea_port(const u64 hcp_adapter_handle,
+ const u16 port_num,
+ const u8 cb_cat,
+ const u64 select_mask, void *cb_addr);
+
+#define H_REGBCMC_PN EHEA_BMASK_IBM(48, 63)
+#define H_REGBCMC_REGTYPE EHEA_BMASK_IBM(61, 63)
+#define H_REGBCMC_MACADDR EHEA_BMASK_IBM(16, 63)
+#define H_REGBCMC_VLANID EHEA_BMASK_IBM(52, 63)
+
+u64 hipz_h_reg_dereg_bcmc(const u64 hcp_adapter_handle,
+ const u16 port_num,
+ const u8 reg_type,
+ const u64 mc_mac_addr,
+ const u16 vlan_id, const u32 hcall_id);
+
+u64 hipz_h_reset_events(const u64 hcp_adapter_handle,
+ const u64 neq_handle, const u64 event_mask);
+
+#endif /* __EHEA_PHYP_H__ */
^ permalink raw reply
* [PATCH 3/4] ehea: queue managment
From: Jan-Bernd Themann @ 2006-06-07 17:05 UTC (permalink / raw)
To: netdev; +Cc: meder, raisch, themann, tklein
Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
drivers/net/ehea/ehea_qmr.c | 719 ++++++++++++++++++++++++++++++++++++++++++++
drivers/net/ehea/ehea_qmr.h | 390 +++++++++++++++++++++++
2 files changed, 1109 insertions(+)
--- linux-2.6.16-rc5-orig/drivers/net/ehea/ehea_qmr.c 1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_qmr.c 2006-06-07 07:01:14.664174144 -0700
@@ -0,0 +1,719 @@
+/*
+ * linux/drivers/net/ehea/ehea_qmr.c
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Heiko-Joerg Schick <schickhj@de.ibm.com>
+ * Thomas Klein <tklein@de.ibm.com>
+ *
+ *
+ * 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "ehea.h"
+#include "ehea_phyp.h"
+#include "ehea_qmr.h"
+
+static void *ipz_qpageit_get_inc(struct ipz_queue *queue)
+{
+ void *retvalue = ipz_qeit_get(queue);
+ queue->current_q_offset += queue->pagesize;
+ if (queue->current_q_offset > queue->queue_length) {
+ queue->current_q_offset -= queue->pagesize;
+ retvalue = NULL;
+ }
+ else if ((((u64) retvalue) & (EHEA_PAGESIZE-1)) != 0) {
+ EDEB(4, "ERROR!! not at PAGE-Boundary");
+ return NULL;
+ }
+ EDEB(7, "queue=%p retvalue=%p", queue, retvalue);
+ return retvalue;
+}
+
+static int ipz_queue_ctor(struct ipz_queue *queue,
+ const u32 nr_of_pages,
+ const u32 pagesize, const u32 qe_size,
+ const u32 nr_of_sg)
+{
+ int f;
+ EDEB_EN(7, "nr_of_pages=%x pagesize=%x qe_size=%x",
+ nr_of_pages, pagesize, qe_size);
+ queue->queue_length = nr_of_pages * pagesize;
+ queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
+ if (!queue->queue_pages) {
+ EDEB(4, "ERROR!! didn't get the memory");
+ return 0;
+ }
+ memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *));
+
+ for (f = 0; f < nr_of_pages; f++) {
+ (queue->queue_pages)[f] =
+ (struct ipz_page *)get_zeroed_page(GFP_KERNEL);
+ if (!(queue->queue_pages)[f]) {
+ break;
+ }
+ }
+ if (f < nr_of_pages) {
+ int g;
+ EDEB_ERR(4, "couldn't get 0ed pages queue=%p f=%x "
+ "nr_of_pages=%x", queue, f, nr_of_pages);
+ for (g = 0; g < f; g++) {
+ free_page((unsigned long)(queue->queue_pages)[g]);
+ }
+ return 0;
+ }
+ queue->current_q_offset = 0;
+ queue->qe_size = qe_size;
+ queue->act_nr_of_sg = nr_of_sg;
+ queue->pagesize = pagesize;
+ queue->toggle_state = 1;
+ EDEB_EX(7, "queue_length=%x queue_pages=%p qe_size=%x"
+ " act_nr_of_sg=%x", queue->queue_length, queue->queue_pages,
+ queue->qe_size, queue->act_nr_of_sg);
+ return 1;
+}
+
+static int ipz_queue_dtor(struct ipz_queue *queue)
+{
+ int g;
+ EDEB_EN(7, "ipz_queue pointer=%p", queue);
+ if (!queue) {
+ return 0;
+ }
+ if (!queue->queue_pages) {
+ return 0;
+ }
+ EDEB(7, "destructing a queue with the following properties:\n"
+ "queue_length=%x act_nr_of_sg=%x pagesize=%x qe_size=%x",
+ queue->queue_length, queue->act_nr_of_sg, queue->pagesize,
+ queue->qe_size);
+ for (g = 0; g < (queue->queue_length / queue->pagesize); g++) {
+ free_page((unsigned long)(queue->queue_pages)[g]);
+ }
+ vfree(queue->queue_pages);
+
+ EDEB_EX(7, "queue freed!");
+ return 1;
+}
+
+struct ehea_cq *ehea_cq_new(void)
+{
+ struct ehea_cq *cq = vmalloc(sizeof(*cq));
+ if (cq)
+ memset(cq, 0, sizeof(*cq));
+ return cq;
+}
+
+void ehea_cq_delete(struct ehea_cq *cq)
+{
+ vfree(cq);
+}
+
+struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
+ int nr_of_cqe, u64 eq_handle, u32 cq_token)
+{
+ struct ehea_cq *cq = NULL;
+ struct h_galpa gal;
+
+ u64 *cq_handle_ref;
+ u32 act_nr_of_entries;
+ u32 act_pages;
+ u64 hret;
+ int ipz_rc;
+ u32 counter;
+ void *vpage = NULL;
+ u64 rpage = 0;
+
+ EDEB_EN(7, "adapter=%p nr_of_cqe=%x , eq_handle: %016lX",
+ adapter, nr_of_cqe, eq_handle);
+
+ cq = ehea_cq_new();
+ if (!cq) {
+ cq = NULL;
+ EDEB_ERR(4, "ehea_create_cq ret=%p (-ENOMEM)", cq);
+ goto create_cq_exit0;
+ }
+
+ cq->attr.max_nr_of_cqes = nr_of_cqe;
+ cq->attr.cq_token = cq_token;
+ cq->attr.eq_handle = eq_handle;
+
+ cq->adapter = adapter;
+
+ cq_handle_ref = &cq->ipz_cq_handle;
+ act_nr_of_entries = 0;
+ act_pages = 0;
+
+ hret = hipz_h_alloc_resource_cq(adapter->handle,
+ cq,
+ &cq->attr,
+ &cq->ipz_cq_handle, &cq->galpas);
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "hipz_h_alloc_resource_cq failed. hret=%lx", hret);
+ goto create_cq_exit1;
+ }
+
+ ipz_rc = ipz_queue_ctor(&cq->ipz_queue, cq->attr.nr_pages,
+ EHEA_PAGESIZE, sizeof(struct ehea_cqe), 0);
+ if (!ipz_rc)
+ goto create_cq_exit2;
+
+ hret = H_SUCCESS;
+
+ for (counter = 0; counter < cq->attr.nr_pages; counter++) {
+ vpage = ipz_qpageit_get_inc(&cq->ipz_queue);
+ if (!vpage) {
+ EDEB_ERR(4, "ipz_qpageit_get_inc() "
+ "returns NULL adapter=%p", adapter);
+ goto create_cq_exit3;
+ }
+
+ rpage = virt_to_abs(vpage);
+
+ hret = hipz_h_register_rpage_cq(adapter->handle,
+ cq->ipz_cq_handle,
+ 0,
+ HIPZ_CQ_REGISTER_ORIG,
+ rpage, 1, cq->galpas.kernel);
+
+ if (hret < H_SUCCESS) {
+ EDEB_ERR(4, "hipz_h_register_rpage_cq() failed "
+ "ehea_cq=%p hret=%lx "
+ "counter=%i act_pages=%i",
+ cq, hret, counter, cq->attr.nr_pages);
+ goto create_cq_exit3;
+ }
+
+ if (counter == (cq->attr.nr_pages - 1)) {
+ vpage = ipz_qpageit_get_inc(&cq->ipz_queue);
+
+ if ((hret != H_SUCCESS) || (vpage)) {
+ EDEB_ERR(4, "Registration of pages not "
+ "complete ehea_cq=%p hret=%lx",
+ cq, hret)
+ goto create_cq_exit3;
+ }
+ } else {
+ if ((hret != H_PAGE_REGISTERED) || (vpage == 0)) {
+ EDEB_ERR(4, "Registration of page failed "
+ "ehea_cq=%p hret=%lx"
+ "counter=%i act_pages=%i",
+ cq, hret, counter, cq->attr.nr_pages);
+ goto create_cq_exit3;
+ }
+ }
+ }
+
+ ipz_qeit_reset(&cq->ipz_queue);
+ gal = cq->galpas.kernel;
+ hipz_reset_cq_ep(cq);
+ hipz_reset_cq_n1(cq);
+
+ EDEB_EX(7, "ret=%p ", cq);
+ return cq;
+
+create_cq_exit3:
+ ipz_queue_dtor(&cq->ipz_queue);
+
+create_cq_exit2:
+ hret = hipz_h_destroy_cq(adapter->handle, cq, cq->ipz_cq_handle,
+ &cq->galpas);
+ EDEB(7, "return code of hipz_cq_destroy=%lx", hret);
+
+create_cq_exit1:
+ ehea_cq_delete(cq);
+
+create_cq_exit0:
+ EDEB_EX(7, "ret=NULL");
+ return NULL;
+}
+
+int ehea_destroy_cq(struct ehea_cq *cq)
+{
+ int ret = 0;
+ u64 adapter_handle;
+ u64 hret;
+
+ adapter_handle = cq->adapter->handle;
+ EDEB_EN(7, "adapter=%p cq=%p", cq->adapter, cq);
+
+ /* deregister all previous registered pages */
+ hret = hipz_h_destroy_cq(adapter_handle, cq, cq->ipz_cq_handle,
+ &cq->galpas);
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "destroy CQ failed!");
+ return -EINVAL;
+ }
+ ipz_queue_dtor(&cq->ipz_queue);
+ ehea_cq_delete(cq);
+
+ EDEB_EX(7, "ret=%x ", ret);
+ return ret;
+}
+
+struct ehea_eq *ehea_eq_new(void)
+{
+ struct ehea_eq *eq = vmalloc(sizeof(*eq));
+ if (eq)
+ memset(eq, 0, sizeof(*eq));
+ return eq;
+}
+
+void ehea_eq_delete(struct ehea_eq *eq)
+{
+ vfree(eq);
+}
+
+struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
+ const enum ehea_eq_type type,
+ const u32 max_nr_of_eqes, const u8 eqe_gen)
+{
+ u64 hret = H_HARDWARE;
+ int ret = 0;
+ u32 i;
+ void *vpage = NULL;
+ struct ehea_eq *eq;
+
+ EDEB_EN(7, "adapter=%p, max_nr_of_eqes=%x", adapter, max_nr_of_eqes);
+
+ eq = ehea_eq_new();
+ if (!eq)
+ return NULL;
+
+ eq->attr.type = type;
+ eq->attr.max_nr_of_eqes = max_nr_of_eqes;
+ eq->attr.eqe_gen = eqe_gen;
+ spin_lock_init(&eq->spinlock);
+
+ hret = hipz_h_alloc_resource_eq(adapter->handle,
+ eq, &eq->attr, &eq->ipz_eq_handle);
+
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "hipz_h_alloc_resource_eq failed. hret=%lx", hret);
+ goto free_eq_mem;
+ }
+
+ ret = ipz_queue_ctor(&eq->ipz_queue, eq->attr.nr_pages,
+ EHEA_PAGESIZE, sizeof(struct ehea_eqe), 0);
+ if (!ret) {
+ EDEB_ERR(4, "can't allocate EQ pages");
+ goto alloc_pages_failed;
+ }
+
+ for (i = 0; i < eq->attr.nr_pages; i++) {
+ u64 rpage;
+
+ if (!(vpage = ipz_qpageit_get_inc(&eq->ipz_queue))) {
+ hret = H_RESOURCE;
+ goto register_page_failed;
+ }
+
+ rpage = virt_to_abs(vpage);
+
+ hret = hipz_h_register_rpage_eq(adapter->handle,
+ eq->ipz_eq_handle,
+ 0,
+ HIPZ_EQ_REGISTER_ORIG,
+ rpage, 1);
+
+ if (i == (eq->attr.nr_pages - 1)) {
+ /* last page */
+ vpage = ipz_qpageit_get_inc(&eq->ipz_queue);
+ if ((hret != H_SUCCESS) || (vpage)) {
+ goto register_page_failed;
+ }
+ } else {
+ if ((hret != H_PAGE_REGISTERED) || (!vpage)) {
+ goto register_page_failed;
+ }
+ }
+ }
+
+ ipz_qeit_reset(&eq->ipz_queue);
+
+ EDEB_EX(7, "hret=%lx", hret);
+ return eq;
+
+register_page_failed:
+ ipz_queue_dtor(&eq->ipz_queue);
+
+alloc_pages_failed:
+ hipz_h_destroy_eq(adapter->handle, eq, eq->ipz_eq_handle, &eq->galpas);
+free_eq_mem:
+ ehea_eq_delete(eq);
+
+ EDEB_EX(7, "return with error hret=%lx", hret);
+ return NULL;
+}
+
+void *ehea_poll_eq(struct ehea_adapter *adapter, struct ehea_eq *eq)
+{
+ void *eqe = NULL;
+ unsigned long flags = 0;
+
+ EDEB_EN(7, "adapter=%p eq=%p", adapter, eq);
+
+ spin_lock_irqsave(&eq->spinlock, flags);
+ eqe = ipz_eqit_eq_get_inc_valid(&eq->ipz_queue);
+ spin_unlock_irqrestore(&eq->spinlock, flags);
+
+ EDEB_EX(7, "eqe=%p", eqe);
+
+ return eqe;
+}
+
+int ehea_destroy_eq(struct ehea_adapter *adapter, struct ehea_eq *eq)
+{
+ unsigned long flags = 0;
+ u64 hret = H_HARDWARE;
+
+ EDEB_EN(7, "adapter=%p eq=%p", adapter, eq);
+
+ spin_lock_irqsave(&eq->spinlock, flags);
+
+ hret = hipz_h_destroy_eq(adapter->handle, eq, eq->ipz_eq_handle,
+ &eq->galpas);
+ spin_unlock_irqrestore(&eq->spinlock, flags);
+
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "Failed freeing EQ resources. hret=%lx", hret);
+ return -EINVAL;
+ }
+ ipz_queue_dtor(&eq->ipz_queue);
+ ehea_eq_delete(eq);
+ EDEB_EX(7, "");
+
+ return 0;
+}
+
+struct ehea_qp *ehea_qp_new(void) {
+ struct ehea_qp *qp = vmalloc(sizeof(*qp));
+ if (qp != 0) {
+ memset(qp, 0, sizeof(*qp));
+ }
+ return qp;
+}
+
+void ehea_qp_delete(struct ehea_qp *qp)
+{
+ vfree(qp);
+}
+
+/**
+ * allocates memory for a queue and registers pages in phyp
+ */
+int ehea_qp_alloc_register(struct ehea_qp *qp,
+ struct ipz_queue *ipz_queue,
+ int nr_pages,
+ int wqe_size,
+ int act_nr_sges,
+ struct ehea_adapter *adapter, int h_call_q_selector)
+{
+ u64 hret = H_HARDWARE;
+ u64 rpage = 0;
+ int iret = 0;
+ int cnt = 0;
+ void *vpage = NULL;
+
+ iret = ipz_queue_ctor(ipz_queue,
+ nr_pages, EHEA_PAGESIZE, wqe_size, act_nr_sges);
+ if (!iret) {
+ EDEB_ERR(4, "Cannot allocate page for queue. iret=%x", iret);
+ return -ENOMEM;
+ }
+
+ EDEB(7, "queue_size=%x, alloc_len=%x, toggle_state=%d",
+ ipz_queue->qe_size,
+ ipz_queue->queue_length, ipz_queue->toggle_state);
+
+ for (cnt = 0; cnt < nr_pages; cnt++) {
+ vpage = ipz_qpageit_get_inc(ipz_queue);
+ if (!vpage) {
+ EDEB_ERR(4, "SQ ipz_qpageit_get_inc() "
+ "failed p_vpage= %p", vpage);
+ goto qp_alloc_register_exit0;
+ }
+ rpage = virt_to_abs(vpage);
+
+ hret = hipz_h_register_rpage_qp(adapter->handle,
+ qp->ipz_qp_handle,
+ 0,
+ h_call_q_selector,
+ rpage,
+ 1, qp->galpas.kernel);
+
+ if (hret < H_SUCCESS) {
+ EDEB_ERR(4, "hipz_h_register_rpage_qp failed. hret=%lx",
+ hret);
+ goto qp_alloc_register_exit0;
+ }
+ }
+ ipz_qeit_reset(ipz_queue);
+
+ return 0;
+
+qp_alloc_register_exit0:
+ ipz_queue_dtor(ipz_queue);
+ return -EINVAL;
+}
+
+u32 map_swqe_size(u8 swqe_enc_size)
+{
+ return 128 << swqe_enc_size;
+}
+
+u32 map_rwqe_size(u8 rwqe_enc_size)
+{
+ return 128 << rwqe_enc_size;
+}
+
+struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter,
+ u32 pd, struct ehea_qp_init_attr *init_attr)
+{
+ struct ehea_qp *qp;
+ u64 hret = H_HARDWARE;
+
+ u32 wqe_size_in_bytes_sq = 0;
+ u32 wqe_size_in_bytes_rq1 = 0;
+ u32 wqe_size_in_bytes_rq2 = 0;
+ u32 wqe_size_in_bytes_rq3 = 0;
+
+ int ret = -1;
+
+ EDEB_EN(7, "init_attr=%p", init_attr);
+
+ qp = ehea_qp_new();
+
+ if (!qp) {
+ EDEB_ERR(4, "pd=%X not enough memory to alloc qp", pd);
+ return NULL;
+ }
+ qp->adapter = adapter;
+
+ EDEB(7, "send_ehea_cq->ipz_cq_handle=0x%lX"
+ "recv_ehea_cq->ipz_cq_handle=0x%lX", init_attr->send_cq_handle,
+ init_attr->recv_cq_handle);
+
+
+ hret = hipz_h_alloc_resource_qp(adapter->handle, qp,
+ init_attr,
+ pd,
+ &qp->ipz_qp_handle,
+ &qp->galpas);
+
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "hipz_h_alloc_resource_qp failed. hret=%lx", hret);
+ goto create_qp_exit1;
+ }
+
+ wqe_size_in_bytes_sq = map_swqe_size(init_attr->act_wqe_size_enc_sq);
+ EDEB(7, "SWQE SG %d", init_attr->wqe_size_enc_sq);
+
+ wqe_size_in_bytes_rq1 = map_rwqe_size(init_attr->act_wqe_size_enc_rq1);
+ wqe_size_in_bytes_rq2 = map_rwqe_size(init_attr->act_wqe_size_enc_rq2);
+ wqe_size_in_bytes_rq3 = map_rwqe_size(init_attr->act_wqe_size_enc_rq3);
+
+ EDEB(7, "SQ pages: %d, SQ WQE size:%d, max SWQE size enc: %d",
+ init_attr->nr_sq_pages,
+ wqe_size_in_bytes_sq, init_attr->act_wqe_size_enc_sq);
+
+ EDEB(7, "RQ1 pages: %d, RQ1 WQE size:%d, max RWQE size enc: %d",
+ init_attr->nr_rq1_pages,
+ wqe_size_in_bytes_rq1, init_attr->act_wqe_size_enc_rq1);
+
+ EDEB(7, "RQ2 pages: %d, RQ2 WQE size:%d, max RWQE size enc: %d",
+ init_attr->nr_rq2_pages,
+ wqe_size_in_bytes_rq2, init_attr->act_wqe_size_enc_rq2);
+
+ EDEB(7, "RQ3 pages: %d, RQ3 WQE size:%d, max RWQE size enc: %d",
+ init_attr->nr_rq3_pages,
+ wqe_size_in_bytes_rq3, init_attr->act_wqe_size_enc_rq3);
+
+ ret = ehea_qp_alloc_register(qp,
+ &qp->ipz_squeue,
+ init_attr->nr_sq_pages,
+ wqe_size_in_bytes_sq,
+ init_attr->act_wqe_size_enc_sq, adapter,
+ 0);
+ if (ret < H_SUCCESS) {
+ EDEB_ERR(4, "can't register for sq hret=%x", ret);
+ goto create_qp_exit2;
+ }
+
+ ret = ehea_qp_alloc_register(qp,
+ &qp->ipz_rqueue1,
+ init_attr->nr_rq1_pages,
+ wqe_size_in_bytes_rq1,
+ init_attr->act_wqe_size_enc_rq1,
+ adapter, 1);
+
+ if (ret < 0) {
+ EDEB_ERR(4, "can't register for rq1 hret=%x", ret);
+ goto create_qp_exit3;
+ }
+
+ if (init_attr->rq_count > 1) {
+ ret = ehea_qp_alloc_register(qp,
+ &qp->ipz_rqueue2,
+ init_attr->nr_rq2_pages,
+ wqe_size_in_bytes_rq2,
+ init_attr->act_wqe_size_enc_rq2,
+ adapter, 2);
+
+ if (ret < 0) {
+ EDEB_ERR(4, "can't register for rq2 hret=%x", ret);
+ goto create_qp_exit4;
+ }
+ }
+
+ if (init_attr->rq_count > 2) {
+ ret = ehea_qp_alloc_register(qp,
+ &qp->ipz_rqueue3,
+ init_attr->nr_rq3_pages,
+ wqe_size_in_bytes_rq3,
+ init_attr->act_wqe_size_enc_rq3,
+ adapter, 3);
+
+ if (ret != 0) {
+ EDEB_ERR(4, "can't register for rq3 hret=%x", ret);
+ goto create_qp_exit5;
+ }
+ }
+
+ qp->init_attr = *init_attr;
+
+ EDEB_EX(7, "");
+ return qp;
+
+create_qp_exit5:
+ ipz_queue_dtor(&qp->ipz_rqueue2);
+
+create_qp_exit4:
+ ipz_queue_dtor(&qp->ipz_rqueue1);
+
+create_qp_exit3:
+ ipz_queue_dtor(&qp->ipz_squeue);
+
+create_qp_exit2:
+ hret = hipz_h_destroy_qp(adapter->handle, qp, qp->ipz_qp_handle,
+ &qp->galpas);
+
+create_qp_exit1:
+ ehea_qp_delete(qp);
+
+ EDEB_EX(7, "hret=NULL");
+ return NULL;
+
+}
+
+int ehea_destroy_qp(struct ehea_qp *qp)
+{
+ int ret = 0;
+ u64 hret;
+ struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
+ EDEB_EX(7, "");
+
+ hret = hipz_h_destroy_qp(qp->adapter->handle, qp, qp->ipz_qp_handle,
+ &qp->galpas);
+ if (hret != H_SUCCESS) {
+ EDEB_ERR(4, "destroy QP failed!");
+ ret = -EINVAL;
+ }
+
+ ipz_queue_dtor(&qp->ipz_squeue);
+ ipz_queue_dtor(&qp->ipz_rqueue1);
+
+ if(qp_attr->rq_count > 1)
+ ipz_queue_dtor(&qp->ipz_rqueue2);
+ if(qp_attr->rq_count > 2)
+ ipz_queue_dtor(&qp->ipz_rqueue3);
+ ehea_qp_delete(qp);
+
+ EDEB_EX(7, "hret=%lx", hret);
+
+ return ret;
+}
+
+#define EHEA_MEM_START 0xc000000000000000
+#define EHEA_MEM_ACC_CTRL 0x00800000
+
+int register_mr_adapter(struct ehea_adapter *adapter)
+{
+ int i;
+ u64 hret;
+ u64 start = EHEA_MEM_START;
+ u64 end = (u64) high_memory;
+ u64 nr_pages = (end - start) / PAGE_SIZE;
+ u32 acc_ctrl = EHEA_MEM_ACC_CTRL;
+
+ EDEB_EN(7, "adapter=%p", adapter);
+
+ hret = hipz_h_alloc_resource_mr(adapter->handle,
+ start,
+ end - start,
+ acc_ctrl,
+ adapter->pd,
+ &adapter->mr_handle,
+ &adapter->lkey);
+ if (hret != H_SUCCESS) {
+ EDEB_EX(4, "Error: hret=%lX\n", hret);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < nr_pages; i++) {
+ hret = hipz_h_register_rpage_mr(adapter->handle,
+ adapter->mr_handle,
+ 0,
+ 0,
+ virt_to_abs(
+ (void *)(((u64) start)
+ + (i * PAGE_SIZE))),
+ 1);
+
+ if (((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED))) {
+ hipz_h_free_resource_mr(adapter->handle, adapter->mr_handle);
+ EDEB_EX(4, " register rpage_mr: hret=%lX\n", hret);
+ return -EINVAL;
+ }
+ }
+
+ if (hret != H_SUCCESS) {
+ hipz_h_free_resource_mr(adapter->handle, adapter->mr_handle);
+ EDEB_EX(4, " register rpage_mr failed for last page:"
+ "hret=%lX\n", hret);
+ return -EINVAL;
+ }
+
+ EDEB_EX(7, "");
+ return 0;
+}
+
+int deregister_mr_adapter(struct ehea_adapter *adapter)
+{
+ u64 hret;
+ EDEB_EN(7, "adapter=%p", adapter);
+ hret = hipz_h_free_resource_mr(adapter->handle, adapter->mr_handle);
+ if (hret != H_SUCCESS) {
+ EDEB_EX(4, "deregistering memory region failed");
+ return -EINVAL;
+ }
+ EDEB_EX(7, "");
+ return 0;
+}
--- linux-2.6.16-rc5-orig/drivers/net/ehea/ehea_qmr.h 1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/ehea_qmr.h 2006-06-07 07:01:14.667173688 -0700
@@ -0,0 +1,390 @@
+/*
+ * linux/drivers/net/ehea/ehea_qmr.h
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Heiko-Joerg Schick <schickhj@de.ibm.com>
+ * Thomas Klein <tklein@de.ibm.com>
+ *
+ *
+ * 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __EHEA_QMR_H__
+#define __EHEA_QMR_H__
+
+#include "ehea.h"
+#include "ehea_hw.h"
+
+/* Use of WR_ID field for EHEA */
+#define EHEA_WR_ID_COUNT EHEA_BMASK_IBM(0, 19)
+#define EHEA_WR_ID_TYPE EHEA_BMASK_IBM(20, 23)
+#define EHEA_SWQE2_TYPE 0x1
+#define EHEA_SWQE3_TYPE 0x2
+#define EHEA_RWQE2_TYPE 0x3 /* RQ2 */
+#define EHEA_RWQE3_TYPE 0x4 /* RQ3 */
+#define EHEA_WR_ID_INDEX EHEA_BMASK_IBM(24, 47)
+#define EHEA_WR_ID_REFILL EHEA_BMASK_IBM(48, 63)
+
+struct ehea_vsgentry {
+ u64 vaddr;
+ u32 l_key;
+ u32 len;
+};
+
+/* maximum number of sg entries allowed in a WQE */
+#define EHEA_MAX_WQE_SG_ENTRIES 252
+#define SWQE2_RES_IMM 14
+#define SWQE2_MAX_IMM (160-SWQE2_RES_IMM)
+#define SWQE3_MAX_IMM 224
+
+/* tx control flags for swqe */
+#define EHEA_SWQE_CRC 0x8000
+#define EHEA_SWQE_IP_CHECKSUM 0x4000
+#define EHEA_SWQE_TCP_CHECKSUM 0x2000
+#define EHEA_SWQE_TSO 0x1000
+#define EHEA_SWQE_SIGNALLED_COMPLETION 0x0800
+#define EHEA_SWQE_VLAN_INSERT 0x0400
+#define EHEA_SWQE_IMM_DATA_PRESENT 0x0200
+#define EHEA_SWQE_DESCRIPTORS_PRESENT 0x0100
+#define EHEA_SWQE_WRAP_CTL_REC 0x0080
+#define EHEA_SWQE_WRAP_CTL_FORCE 0x0040
+#define EHEA_SWQE_BIND 0x0020
+#define EHEA_SWQE_PURGE 0x0010
+
+#define SWQE_HEADER_SIZE 32
+
+struct ehea_swqe {
+ u64 wr_id;
+ u16 tx_control;
+ u16 vlan_tag;
+ u8 reserved1;
+ u8 ip_start;
+ u8 ip_end;
+ u8 immediate_data_length;
+ u8 tcp_offset;
+ u8 reserved2;
+ u16 tcp_end;
+ u8 wrap_tag;
+ u8 descriptors; /* number of valid descriptors in WQE */
+ u16 reserved3;
+ u16 reserved4;
+ u16 mss;
+ u32 reserved5;
+ union {
+ /* Send WQE Format 1 */
+ struct {
+ struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES];
+ } no_immediate_data;
+
+ /* Send WQE Format 2 */
+ struct {
+ struct ehea_vsgentry sg_entry;
+ /* 0x30 */
+ u8 immediate_data[0xd0 - 0x30];
+ /* 0xd0 */
+ struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES -
+ 1];
+ } immdata_desc __attribute__ ((packed));
+
+ /* Send WQE Format 3 */
+ struct {
+ u8 immediate_data[1];
+ } immdata_nodesc;
+ } u;
+};
+
+struct ehea_rwqe {
+ u64 wr_id; /* work request ID */
+ u8 reserved1[5];
+ u8 data_segments;
+ u16 reserved2;
+ u64 reserved3;
+ u64 reserved4;
+ struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES];
+};
+
+#define EHEA_CQE_VLAN_TAG_XTRACT 0x0400
+
+#define EHEA_CQE_TYPE_RQ 0x60
+#define EHEA_CQE_STAT_ERR_MASK 0x7300
+#define EHEA_CQE_STAT_ERR_TCP 0x4000
+
+struct ehea_cqe {
+ u64 wr_id; /* work request ID from WQE */
+ u8 type;
+ u8 valid;
+ u16 status;
+ u16 reserved1;
+ u16 num_bytes_transfered;
+ u16 vlan_tag;
+ u16 inet_checksum_value;
+ u8 reserved2;
+ u8 header_length;
+ u16 reserved3;
+ u16 page_offset;
+ u16 wqe_count;
+ u32 qp_token;
+ u32 timestamp;
+ u32 reserved4;
+ u64 reserved5[3];
+};
+
+#define EHEA_EQE_VALID EHEA_BMASK_IBM(0, 0)
+#define EHEA_EQE_IS_CQE EHEA_BMASK_IBM(1, 1)
+#define EHEA_EQE_IDENTIFIER EHEA_BMASK_IBM(2, 7)
+#define EHEA_EQE_QP_CQ_NUMBER EHEA_BMASK_IBM(8, 31)
+#define EHEA_EQE_QP_TOKEN EHEA_BMASK_IBM(32, 63)
+#define EHEA_EQE_CQ_TOKEN EHEA_BMASK_IBM(32, 63)
+#define EHEA_EQE_KEY EHEA_BMASK_IBM(32, 63)
+#define EHEA_EQE_PORT_NUMBER EHEA_BMASK_IBM(56, 63)
+#define EHEA_EQE_EQ_NUMBER EHEA_BMASK_IBM(48, 63)
+#define EHEA_EQE_SM_ID EHEA_BMASK_IBM(48, 63)
+#define EHEA_EQE_SM_MECH_NUMBER EHEA_BMASK_IBM(48, 55)
+#define EHEA_EQE_SM_PORT_NUMBER EHEA_BMASK_IBM(56, 63)
+
+struct ehea_eqe {
+ u64 entry;
+};
+
+struct ehea_mrte {
+ u64 starting_va;
+ u64 length; /* length of memory region in bytes */
+ u32 pd;
+ u8 key_instance;
+ u8 pagesize;
+ u8 mr_control;
+ u8 local_remote_access_controll;
+ u8 reserved[0x20 - 0x18];
+ u64 at_pointer[4];
+};
+
+static inline void *ipz_qeit_calc(struct ipz_queue *queue, u64 q_offset)
+{
+ struct ipz_page *current_page = NULL;
+ if (q_offset >= queue->queue_length)
+ q_offset -= queue->queue_length;
+ current_page = (queue->queue_pages)[q_offset >> EHEA_PAGESHIFT];
+ return ¤t_page->entries[q_offset & (EHEA_PAGESIZE - 1)];
+}
+
+static inline void *ipz_qeit_get(struct ipz_queue *queue)
+{
+ return ipz_qeit_calc(queue, queue->current_q_offset);
+}
+
+static inline void ipz_qeit_inc(struct ipz_queue *queue)
+{
+ queue->current_q_offset += queue->qe_size;
+ if (queue->current_q_offset >= queue->queue_length) {
+ queue->current_q_offset = 0;
+ /* toggle the valid flag */
+ queue->toggle_state = (~queue->toggle_state) & 1;
+ }
+}
+
+static inline void *ipz_qeit_get_inc(struct ipz_queue *queue)
+{
+ void *retvalue = ipz_qeit_get(queue);
+ ipz_qeit_inc(queue);
+ EDEB(8, "queue=%p retvalue=%p new current_q_addr=%lx qe_size=%x",
+ queue, retvalue, queue->current_q_offset, queue->qe_size);
+
+ return retvalue;
+}
+
+static inline void *ipz_qeit_get_inc_valid(struct ipz_queue *queue)
+{
+ struct ehea_cqe *retvalue = ipz_qeit_get(queue);
+ void *pref;
+ u8 valid = retvalue->valid;
+ if ((valid >> 7) == (queue->toggle_state & 1)) {
+ /* this is a good one */
+ iosync();
+ ipz_qeit_inc(queue);
+ pref = ipz_qeit_calc(queue, queue->current_q_offset);
+ prefetch(pref);
+ prefetch(pref + 128);
+ } else
+ retvalue = NULL;
+ return retvalue;
+}
+
+static inline void *ipz_qeit_get_valid(struct ipz_queue *queue)
+{
+ struct ehea_cqe *retvalue = ipz_qeit_get(queue);
+ void *pref;
+ pref = ipz_qeit_calc(queue, queue->current_q_offset);
+ prefetch(pref);
+ prefetch(pref + 128);
+ prefetch(pref + 256);
+ u8 valid = retvalue->valid;
+ if ((valid >> 7) == (queue->toggle_state & 1))
+ iosync();
+ else
+ retvalue = NULL;
+ return retvalue;
+}
+
+static inline void *ipz_qeit_reset(struct ipz_queue *queue)
+{
+ queue->current_q_offset = 0;
+ return ipz_qeit_get(queue);
+}
+
+static inline void *ipz_qeit_eq_get_inc(struct ipz_queue *queue)
+{
+ void *retvalue = NULL;
+ u64 last_entry_in_q = queue->queue_length - queue->qe_size;
+
+ retvalue = ipz_qeit_get(queue);
+ queue->current_q_offset += queue->qe_size;
+ if (queue->current_q_offset > last_entry_in_q) {
+ queue->current_q_offset = 0;
+ queue->toggle_state = (~queue->toggle_state) & 1;
+ }
+
+ EDEB(7, "queue=%p retvalue=%p new current_q_offset=%lx qe_size=%x",
+ queue, retvalue, queue->current_q_offset, queue->qe_size);
+
+ return retvalue;
+}
+
+static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
+{
+ void *retvalue = ipz_qeit_get(queue);
+ u32 qe = *(u8 *) retvalue;
+ EDEB(7, "ipz_eqit_eq_get_inc_valid qe=%x", qe);
+ if ((qe >> 7) == (queue->toggle_state & 1))
+ ipz_qeit_eq_get_inc(queue);
+ else
+ retvalue = NULL;
+ return retvalue;
+}
+
+static inline struct ehea_rwqe *ehea_get_next_rwqe(struct ehea_qp *qp,
+ int rq_nr)
+{
+
+ struct ehea_rwqe *wqe_p = NULL;
+ struct ipz_queue *queue = NULL;
+ struct ehea_qp *my_qp = qp;
+ EDEB_EN(8, "QP=%p, RQ_nr=%d", qp, rq_nr);
+
+ if (rq_nr == 1)
+ queue = &my_qp->ipz_rqueue1;
+ else if (rq_nr == 2)
+ queue = &my_qp->ipz_rqueue2;
+ else
+ queue = &my_qp->ipz_rqueue3;
+ wqe_p = (struct ehea_rwqe *)ipz_qeit_get_inc(queue);
+
+ EDEB_EX(8, "&RWQE=%p, queue=%p", wqe_p, queue);
+ return wqe_p;
+}
+
+static inline struct ehea_swqe *ehea_get_swqe(struct ehea_qp *my_qp)
+{
+
+ struct ehea_swqe *wqe_p = NULL;
+ EDEB_EN(7, "QP=%p, queue=%p", my_qp, &my_qp->ipz_squeue);
+ wqe_p = (struct ehea_swqe *)ipz_qeit_get_inc(&my_qp->ipz_squeue);
+ EDEB_EX(7, "");
+ return wqe_p;
+}
+
+static inline void ehea_post_swqe(struct ehea_qp *my_qp, struct ehea_swqe *swqe)
+{
+
+ EDEB_EN(7, "QP=%p, SWQE=%p", my_qp, swqe);
+ EDEB(6, "SWQE workreqid = 0x%lX, imm_data_len=%d, descriptors=%d",
+ (u64) swqe->wr_id, swqe->immediate_data_length, swqe->descriptors);
+ iosync();
+ hipz_update_sqa(my_qp, 1);
+ EDEB_EX(7, "");
+}
+
+static inline struct ehea_cqe *ehea_poll_rq1(struct ehea_qp *qp, int *wqe_index)
+{
+ struct ipz_queue *queue = &qp->ipz_rqueue1;
+ struct ehea_cqe *cqe = NULL;
+
+ EDEB_EN(7, "QP=%p, RQ1 toggle state = %d, current_q_offset=%lx", qp,
+ queue->toggle_state, queue->current_q_offset);
+ *wqe_index = (queue->current_q_offset) >> (7 + EHEA_SG_RQ1);
+ cqe = (struct ehea_cqe *)ipz_qeit_get_valid(queue);
+ EDEB_EX(7, "cqe=%p, new toggle state %d, wqe_index = %d",
+ cqe, queue->toggle_state, *wqe_index);
+ return cqe;
+}
+
+static inline void ehea_inc_rq1(struct ehea_qp *qp)
+{
+ struct ipz_queue *queue = &qp->ipz_rqueue1;
+ ipz_qeit_inc(queue);
+}
+
+static inline struct ehea_cqe *ehea_poll_cq(struct ehea_cq *my_cq)
+{
+
+ struct ehea_cqe *wqe_p = NULL;
+ EDEB_EN(7, "CQ=%p", my_cq);
+
+ EDEB(7, "queue_element_size=%x, alloc_len=%x, queue=%p",
+ my_cq->ipz_queue.qe_size,
+ my_cq->ipz_queue.queue_length, &my_cq->ipz_queue);
+ wqe_p = (struct ehea_cqe *)ipz_qeit_get_inc_valid(&my_cq->ipz_queue);
+
+ EDEB_EX(7, "wqe_p=%p", wqe_p);
+ return wqe_p;
+};
+
+#define HIPZ_CQ_REGISTER_ORIG 0
+#define HIPZ_EQ_REGISTER_ORIG 0
+
+enum ehea_eq_type {
+ EHEA_EQ = 0, /* event queue */
+ EHEA_NEQ /* notification event queue */
+};
+
+struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
+ enum ehea_eq_type type,
+ const u32 length, const u8 eqe_gen);
+
+int ehea_destroy_eq(struct ehea_adapter *adapter, struct ehea_eq *eq);
+
+void *ehea_poll_eq(struct ehea_adapter *adapter, struct ehea_eq *eq);
+
+struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter, int cqe,
+ u64 eq_handle, u32 cq_token);
+
+int ehea_destroy_cq(struct ehea_cq *cq);
+
+
+struct ehea_qp *ehea_create_qp(struct ehea_adapter * adapter,
+ u32 pd,
+ struct ehea_qp_init_attr *init_attr);
+
+int ehea_destroy_qp(struct ehea_qp *qp);
+
+int register_mr_adapter(struct ehea_adapter *adapter);
+int deregister_mr_adapter(struct ehea_adapter *adapter);
+
+#endif /* __EHEA_QMR_H__ */
^ permalink raw reply
* [PATCH 4/4] ehea: Kconfig and Makefile
From: Jan-Bernd Themann @ 2006-06-07 17:06 UTC (permalink / raw)
To: netdev; +Cc: meder, raisch, themann, tklein
Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
drivers/net/ehea/Kconfig | 6 ++++++
drivers/net/ehea/Makefile | 45 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 51 insertions(+)
--- linux-2.6.16-rc5-orig/drivers/net/ehea/Makefile 1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/Makefile 2006-06-07 07:01:14.634178704 -0700
@@ -0,0 +1,45 @@
+# Server eHEA ethernet device driver for Linux on POWER
+#
+#
+# linux/drivers/net/ehea/Makefile
+#
+# eHEA ethernet device driver for IBM eServer System p
+#
+# (C) Copyright IBM Corp. 2006
+#
+# Authors:
+# Christoph Raisch <raisch@de.ibm.com>
+# Jan-Bernd Themann <themann@de.ibm.com>
+# Heiko-Joerg Schick <schickhj@de.ibm.com>
+# Thomas Klein <tklein@de.ibm.com>
+#
+#
+# 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+
+
+# To compile module type:
+# make -C /root/linux-2.6.5-7.244 SUBDIRS=`pwd` V=1 modules CONFIG_EHEA=m
+# make -C /usr/src/linux-2.6.17-rc5 SUBDIRS=`pwd` V=1 modules CONFIG_EHEA=m
+
+ehea_mod-objs = ehea_main.o ehea_phyp.o ehea_qmr.o ehea_ethtool.o ehea_phyp.o
+
+obj-$(CONFIG_EHEA) += ehea_mod.o
+
+#CFLAGS += -Werror
+
+
+
--- linux-2.6.16-rc5-orig/drivers/net/ehea/Kconfig 1969-12-31 16:00:00.000000000 -0800
+++ kernel/drivers/net/ehea/Kconfig 2006-06-07 07:01:14.637178248 -0700
@@ -0,0 +1,6 @@
+config EHEA
+ tristate "eHEA Ethernet support"
+ depends on IBMEBUS
+ ---help---
+ This driver supports the IBM pSeries
+ Ethernet adapter
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox