Kernel driver patch 2 of 9. Signed-off-by: Glenn Grundstrom <[EMAIL PROTECTED]>
====================================================== diff -ruNp old/drivers/infiniband/hw/nes/nes.c new/drivers/infiniband/hw/nes/nes.c --- old/drivers/infiniband/hw/nes/nes.c 1969-12-31 18:00:00.000000000 -0600 +++ new/drivers/infiniband/hw/nes/nes.c 2006-10-25 10:15:49.000000000 -0500 @@ -0,0 +1,653 @@ +/* + * Copyright (c) 2006 NetEffect, Inc. All rights reserved. + * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#include <linux/if_vlan.h> +#include <linux/crc32.h> +#include <linux/in.h> +#include <linux/init.h> +#include <linux/if_arp.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/byteorder.h> + +#include <rdma/ib_smi.h> +#include <rdma/ib_verbs.h> +#include <rdma/ib_pack.h> +#include <rdma/iw_cm.h> + +#include "nes.h" + +MODULE_AUTHOR("NetEffect"); +MODULE_DESCRIPTION("NetEffect RNIC Low-level iWARP Driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(DRV_VERSION); + +int max_mtu = ETH_DATA_LEN; + + +/* Interoperability */ +int mpa_version = 1; +module_param(mpa_version, int, 0); +MODULE_PARM_DESC(mpa_version, "MPA version to be used int MPA Req/Resp (0 or 1)"); + +/* Interoperability */ +int disable_mpa_crc = 0; +module_param(disable_mpa_crc, int, 0); +MODULE_PARM_DESC(disable_mpa_crc, "Disable checking of MPA CRC"); + + +unsigned int send_first = 0; +module_param(send_first, int, 0); +MODULE_PARM_DESC(send_first, "Send RDMA Message First on Active Connection"); + + +LIST_HEAD(nes_adapter_list); +LIST_HEAD(nes_dev_list); + +static int nes_device_event(struct notifier_block *notifier, unsigned long event, void *ptr); +static int nes_inetaddr_event(struct notifier_block *notifier, unsigned long event, void *ptr); +static void nes_print_macaddr(struct net_device *netdev); +static irqreturn_t nes_interrupt(int, void *, struct pt_regs *); +static int __devinit nes_probe(struct pci_dev *, const struct pci_device_id *); +static int nes_suspend(struct pci_dev *, pm_message_t); +static int nes_resume(struct pci_dev *); +static void __devexit nes_remove(struct pci_dev *); +static int __init nes_init_module(void); +static void __exit nes_exit_module(void); + +extern struct nes_dev *nes_ifs[]; + +// _the_ function interface handle to nes_tcpip module +struct nes_stack_ops *stack_ops_p; + +static struct pci_device_id nes_pci_table[] = { + {PCI_VENDOR_ID_NETEFFECT, PCI_DEVICE_ID_NETEFFECT_NE010, PCI_ANY_ID, PCI_ANY_ID}, + {0} +}; + +MODULE_DEVICE_TABLE(pci, nes_pci_table); + + +static struct notifier_block nes_dev_notifier = { + notifier_call: nes_device_event +}; + +static struct notifier_block nes_inetaddr_notifier = { + notifier_call: nes_inetaddr_event +}; + + +/** + * nes_device_event + * + * @param notifier + * @param event + * @param ptr + * + * @return int + */ +static int nes_device_event(struct notifier_block *notifier, + unsigned long event, void *ptr) +{ + struct net_device *netdev = (struct net_device *)ptr; + struct nes_dev *nesdev; + + dprintk("nes_device_event: notifier %p event=%ld netdev=%p, interface name = %s.\n", + notifier, event, netdev, netdev->name); + + list_for_each_entry(nesdev, &nes_dev_list, list) { + dprintk("Nesdev list entry = 0x%p.\n", nesdev); + if (nesdev->netdev == netdev) { + switch (event) { + case NETDEV_DOWN: + { + nes_ifs[0] = NULL; + dprintk("event:DOWN \n"); + nes_stop_cm(nesdev); + } + break; + case NETDEV_REGISTER: + { + dprintk("event:Register \n"); + nes_ifs[0] = nesdev; + if (nesdev->nes_stack_start == 0) + { + // initialize tcpip stack + if (!nes_register_stack_client(0, &stack_ops_p, nes_update_arp)) + { + // initialize the stack + stack_ops_p->stack_init((void *)nesdev->netdev); + // disable dhcp + stack_ops_p->dhcp_control(0x00); + + nesdev->nes_stack_start = 1; + } + } + } + break; + default: + break; + } + } + } + + return (NOTIFY_DONE); +} + + +/** + * nes_inetaddr_event + * + * @param notifier + * @param event + * @param ptr + * + * @return int + */ +static int nes_inetaddr_event(struct notifier_block *notifier, + unsigned long event, void *ptr) +{ + struct in_ifaddr *ifa = ptr; + struct net_device *netdev = ifa->ifa_dev->dev; + struct nes_dev *nesdev; + unsigned int addr; + unsigned int mask; + int ret; + + dprintk("nes_inetaddr_event: notifier %p event=%ld netdev=%p, interface name = %s.\n", + notifier, event, netdev, netdev->name); + dprintk("nes_inetaddr_event: ifa_address=%08X, ifa_mask=%08X\n", ifa->ifa_address, ifa->ifa_mask); + + addr = ntohl(ifa->ifa_address); + mask = ntohl(ifa->ifa_mask); + dprintk("nes_inetaddr_event: ip address %08X, netmask %08X.\n", addr, mask); + list_for_each_entry(nesdev, &nes_dev_list, list) { + dprintk("Nesdev list entry = 0x%p.\n", nesdev); + if (nesdev->netdev == netdev) { + // we have ifa->ifa_address/mask here if we need it + switch (event) { + case NETDEV_DOWN: + { + dprintk("event:DOWN \n"); + nes_write_indexed(nesdev->index_reg, + NES_IDX_DST_IP_ADDR+(0x10*PCI_FUNC(nesdev->pcidev->devfn)), 0); + // del the IP addr + stack_ops_p->del_ipaddr(addr, mask); + nesdev->local_ipaddr = 0; + stack_ops_p->dump_rt_table(); + } + break; + case NETDEV_UP: + { + dprintk("event:UP \n"); + // Add the address to the IP table + stack_ops_p->add_ipaddr(addr, mask); + nesdev->local_ipaddr = ifa->ifa_address; + + nes_write_indexed(nesdev->index_reg, + NES_IDX_DST_IP_ADDR+(0x10*PCI_FUNC(nesdev->pcidev->devfn)), ntohl(ifa->ifa_address)); + + stack_ops_p->dump_rt_table(); + if (0 == nesdev->of_device_registered) + { + ret = nes_register_device(nesdev); + if (ret) { + printk(KERN_ERR PFX "Unable to register RDMA device, ret = %d\n", ret); + } else { + nesdev->of_device_registered = 1; + } + } + } + break; + default: + break; + } + } + } + return (NOTIFY_DONE); +} + + +/** + * nes_print_macaddr + * + * @param netdev + */ +static void nes_print_macaddr(struct net_device *netdev) +{ + dprintk("%s: MAC %02X:%02X:%02X:%02X:%02X:%02X, " + "IRQ %u\n", netdev->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], + netdev->irq); +} + + +/** + * nes_add_ref + * + * @param ibqp + */ +void nes_add_ref(struct ib_qp *ibqp) +{ + struct nes_qp *nesqp; + dprintk("%s: Bumping refcount for QP%u.\n", __FUNCTION__, ibqp->qp_num ); + + nesqp = to_nesqp(ibqp); + atomic_inc(&nesqp->refcount); +} + + +/** + * nes_rem_ref + * + * @param ibqp + */ +void nes_rem_ref(struct ib_qp *ibqp) +{ + struct nes_qp *nesqp; + dprintk("%s: Decing refcount for QP%u.\n", __FUNCTION__, ibqp->qp_num ); + + nesqp = to_nesqp(ibqp); + if (atomic_dec_and_test(&nesqp->refcount)) { + dprintk("%s: Refcount for QP%u is 0. Freeing QP structure\n", __FUNCTION__, ibqp->qp_num ); + kfree(nesqp->allocated_buffer); + } +} + + +/** + * nes_get_qp + * + * @param device + * @param qpn + * + * @return struct ib_qp* + */ +struct ib_qp *nes_get_qp(struct ib_device *device, int qpn) +{ + struct nes_dev *nesdev = to_nesdev(device); + struct nes_adapter *nesadapter = nesdev->nesadapter; + + if ((qpn<NES_FIRST_QPN) || (qpn>=(NES_FIRST_QPN+nesadapter->max_qp))) + return NULL; + + return (&nesadapter->qp_table[qpn-NES_FIRST_QPN]->ibqp); +} + + +/** + * nes_interrupt - handle interrupts + */ +static irqreturn_t nes_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct nes_dev *nesdev = (struct nes_dev *) dev_id; + int handled = 0; + + handled = nes_read32(nesdev->regs+NES_INT_PENDING ); + // dprintk("Interrupt Pending value = 0x%08X\n", handled ); + + if (handled) { + tasklet_schedule(&nesdev->dpc_tasklet); + return IRQ_HANDLED; + } else { + return IRQ_NONE; + } +} + + +/** + * nes_probe - + * + * @param pcidev + * @param ent + * + * @return int __devinit + */ +static int __devinit nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) +{ + int ret = 0; + unsigned long reg0_start, reg0_flags, reg0_len; + unsigned long reg1_start, reg1_flags, reg1_len; + struct net_device *netdev = NULL; + struct nes_dev *nesdev = NULL; + void __iomem *mmio_regs = NULL; + + assert(pcidev != NULL); + assert(ent != NULL); + + printk(KERN_INFO PFX "%s: NetEffect RNIC driver v%s loading\n", pci_name(pcidev), DRV_VERSION); + + /* Enable PCI device */ + ret = pci_enable_device(pcidev); + if (ret){ + printk(KERN_ERR PFX "%s: Unable to enable PCI device\n", pci_name(pcidev)); + goto bail0; + } + + reg0_start = pci_resource_start(pcidev, BAR_0); + reg0_len = pci_resource_len(pcidev, BAR_0); + reg0_flags = pci_resource_flags(pcidev, BAR_0); + + reg1_start = pci_resource_start(pcidev, BAR_1); + reg1_len = pci_resource_len(pcidev, BAR_1); + reg1_flags = pci_resource_flags(pcidev, BAR_1); + + dprintk("BAR0 (@0x%08lX) size = 0x%lX bytes\n", reg0_start, reg0_len); + dprintk("BAR1 (@0x%08lX) size = 0x%lX bytes\n", reg1_start, reg1_len); + + /* Make sure PCI base addr are MMIO */ + if (!(reg0_flags & IORESOURCE_MEM) || !(reg1_flags & IORESOURCE_MEM)) { + printk(KERN_ERR PFX "PCI regions not an MMIO resource\n"); + ret = -ENODEV; + goto bail1; + } + + /* Reserve PCI I/O and memory resources */ + ret = pci_request_regions(pcidev, DRV_NAME); + if (ret) { + printk(KERN_ERR PFX "%s: Unable to request regions\n", pci_name(pcidev)); + goto bail1; + } + + if ((sizeof(dma_addr_t) > 4)) { + ret = pci_set_dma_mask(pcidev, DMA_64BIT_MASK); + if (ret < 0) { + printk(KERN_ERR PFX "64b DMA configuration failed\n"); + goto bail2; + } + } else { + ret = pci_set_dma_mask(pcidev, DMA_32BIT_MASK); + if (ret < 0){ + printk(KERN_ERR PFX "32b DMA configuration failed\n"); + goto bail2; + } + } + + /* Enables bus-mastering on the device */ + pci_set_master(pcidev); + + /* pci tweaks */ + pci_write_config_word(pcidev, 0x000c, 0xfc10); + pci_write_config_dword(pcidev, 0x0048, 0x00480007); + + /* Allocate hardware structure */ + nesdev = (struct nes_dev *)ib_alloc_device(sizeof *nesdev); + if (!nesdev) { + printk(KERN_ERR PFX "%s: Unable to alloc hardware struct\n", pci_name(pcidev)); + ret = -ENOMEM; + iounmap(mmio_regs); + goto bail2; + } + + memset(nesdev, 0, sizeof(*nesdev)); + spin_lock_init(&nesdev->lock); + nesdev->pcidev = pcidev; + nesdev->cur_tx = 0; + + /* Remap the PCI registers in adapter BAR0 to kernel VA space */ + mmio_regs = ioremap_nocache(reg0_start, sizeof(mmio_regs)); + if (mmio_regs == 0UL){ + printk(KERN_ERR PFX "Unable to remap BAR0\n"); + ret = -EIO; + goto bail35; + } + nesdev->regs = mmio_regs; + nesdev->index_reg = 0x50 + (PCI_FUNC(pcidev->devfn)*8) + mmio_regs; + + // Ensure interrupts are disabled + nes_write32(nesdev->regs+NES_INT_MASK, 0x7fffffff ); + + tasklet_init(&nesdev->dpc_tasklet, nes_dpc, (unsigned long) nesdev); + + /* Request an interrupt line for the driver */ + ret = request_irq(pcidev->irq, nes_interrupt, SA_SHIRQ, DRV_NAME, nesdev); + if (ret) { + printk(KERN_ERR PFX "%s: requested IRQ %u is busy\n", pci_name(pcidev), pcidev->irq); + iounmap(mmio_regs); + goto bail3; + } + + // Init the adapter + nesdev->nesadapter = nes_adapter_init(nesdev, (reg1_len / 4096)); + if (!nesdev->nesadapter) { + printk(KERN_ERR PFX "Unable to initialize adapter.\n" ); + ret = -ENOMEM; + goto bail37; + } + + nesdev->nesadapter->csr_start = reg0_start; + nesdev->nesadapter->doorbell_start = reg1_start; + + if (nes_read_eeprom_values(nesdev)) { + printk(KERN_ERR PFX "Unable to read EEPROM data.\n"); + ret = -ENODEV; + goto bail4; + } + + /* Set driver specific data */ + pci_set_drvdata(pcidev, nesdev); + + /* Initialize network device */ + if ((netdev = nes_netdev_init(nesdev, mmio_regs)) == NULL) { + goto bail4; + } + + /* Register network device */ + ret = register_netdev(netdev); + if (ret) { + printk(KERN_ERR PFX "Unable to register netdev, ret = %d\n", ret); + goto bail5; + } + + /* Disable network packets */ + netif_stop_queue(netdev); + + dprintk("CQP Status = 0x%08X bytes\n", nes_read_indexed(nesdev->index_reg, 0xa0)); + dprintk("PCI Function # = %u.\n", PCI_FUNC(pcidev->devfn) ); + + /* Print out the MAC address */ + nes_print_macaddr(netdev); + + dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__); + + register_netdevice_notifier(&nes_dev_notifier); + register_inetaddr_notifier(&nes_inetaddr_notifier); + + printk(KERN_ERR PFX "%s: NetEffect RNIC driver successfully loaded.\n", pci_name(pcidev)); + + return 0; + +bail5: + printk(KERN_ERR PFX "bail5\n"); + nes_netdev_exit(nesdev); + free_netdev(netdev); + +bail4: + printk(KERN_ERR PFX "bail4\n"); + /* Deallocate the Adapter Structure */ + nes_adapter_free(nesdev->nesadapter); + +bail37: + printk(KERN_ERR PFX "bail37\n"); + /* Unmap adapter PA space */ + iounmap(mmio_regs); + +bail35: + printk(KERN_ERR PFX "bail3.5\n"); + free_irq(pcidev->irq, nesdev); + +bail3: + printk(KERN_ERR PFX "bail3\n"); + ib_dealloc_device(&nesdev->ibdev); + +bail2: + pci_release_regions(pcidev); + +bail1: + pci_disable_device(pcidev); + +bail0: + return (ret); +} + + +/** + * nes_suspend - power management + */ +static int nes_suspend(struct pci_dev *pcidev, pm_message_t state) +{ + dprintk("pcidev=%p\n", pcidev); + + return (0); +} + + +/** + * nes_resume - power management + */ +static int nes_resume(struct pci_dev *pcidev) +{ + dprintk("pcidev=%p\n", pcidev); + + return (0); +} + + +/** + * nes_remove - unload from kernel + * + * @param pcidev + * + * @return void __devexit + */ +static void __devexit nes_remove(struct pci_dev *pcidev) +{ + struct nes_dev *nesdev = pci_get_drvdata(pcidev); + struct net_device *netdev = nesdev->netdev; + + dprintk("nes_remove called.\n"); + assert(netdev != NULL); + + unregister_inetaddr_notifier(&nes_inetaddr_notifier); + unregister_netdevice_notifier(&nes_dev_notifier); + + /* Clean up the RNIC resources */ + dprintk("nes_remove: calling unregister_netdev.\n"); + /* Remove network device from the kernel */ + unregister_netdev(netdev); + + dprintk("nes_remove: calling nes_netdev_exit.\n"); + /* Free network device */ + nes_netdev_exit(nesdev); + free_netdev(netdev); + + dprintk("nes_remove: calling free_irq.\n"); + /* Free the interrupt line */ + free_irq(pcidev->irq, nesdev); + + /* missing: Turn LEDs off here */ + + dprintk("nes_remove: calling nes_adapter_free(%p).\n", nesdev->nesadapter); + /* Deallocate the Adapter Structure */ + nes_adapter_free(nesdev->nesadapter); + + dprintk("nes_remove: calling iounmap.\n"); + /* Unmap adapter PA space */ + iounmap(nesdev->regs); + + /* Unregister with OpenFabrics */ + if (nesdev->of_device_registered) { + dprintk("nes_remove: calling nes_unregister_device.\n"); + nes_unregister_device(nesdev); + } + + dprintk("nes_remove: calling ib_dealloc_device.\n"); + /* Free the hardware structure */ + ib_dealloc_device(&nesdev->ibdev); + + dprintk("nes_remove: calling pci_release_regions.\n"); + /* Release reserved PCI I/O and memory resources */ + pci_release_regions(pcidev); + + dprintk("nes_remove: calling pci_disable_device.\n"); + /* Disable PCI device */ + pci_disable_device(pcidev); + + dprintk("nes_remove: calling pci_set_drvdata.\n"); + /* Clear driver specific data */ + pci_set_drvdata(pcidev, NULL); +} + + +static struct pci_driver nes_pci_driver = { + .name = DRV_NAME, + .id_table = nes_pci_table, + .probe = nes_probe, + .remove = __devexit_p(nes_remove), +#ifdef CONFIG_PM + .suspend = nes_suspend, + .resume = nes_resume, +#endif +}; + + +/** + * nes_init_module - module initialization entry point + * + * @return int __init + */ +static int __init nes_init_module(void) +{ + return (pci_module_init(&nes_pci_driver)); +} + + +/** + * nes_exit_module - module unload entry point + * + * @return void __exit + */ +static void __exit nes_exit_module(void) +{ + pci_unregister_driver(&nes_pci_driver); +} + + +module_init(nes_init_module); +module_exit(nes_exit_module); + - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html