diff options
Diffstat (limited to 'drivers/staging/sxg/sxg.c')
-rw-r--r-- | drivers/staging/sxg/sxg.c | 2885 |
1 files changed, 1881 insertions, 1004 deletions
diff --git a/drivers/staging/sxg/sxg.c b/drivers/staging/sxg/sxg.c index 1e0cfcd..0050a02 100644 --- a/drivers/staging/sxg/sxg.c +++ b/drivers/staging/sxg/sxg.c @@ -30,6 +30,8 @@ * are those of the authors and should not be interpreted as representing * official policies, either expressed or implied, of Alacritech, Inc. * + * Parts developed by LinSysSoft Sahara team + * **************************************************************************/ /* @@ -46,6 +48,7 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/firmware.h> #include <linux/ioport.h> #include <linux/slab.h> #include <linux/interrupt.h> @@ -61,101 +64,122 @@ #include <linux/types.h> #include <linux/dma-mapping.h> #include <linux/mii.h> +#include <linux/ip.h> +#include <linux/in.h> +#include <linux/tcp.h> +#include <linux/ipv6.h> -#define SLIC_DUMP_ENABLED 0 #define SLIC_GET_STATS_ENABLED 0 #define LINUX_FREES_ADAPTER_RESOURCES 1 #define SXG_OFFLOAD_IP_CHECKSUM 0 #define SXG_POWER_MANAGEMENT_ENABLED 0 #define VPCI 0 -#define DBG 1 #define ATK_DEBUG 1 +#define SXG_UCODE_DEBUG 0 + #include "sxg_os.h" #include "sxghw.h" #include "sxghif.h" #include "sxg.h" #include "sxgdbg.h" - -#include "sxgphycode.h" -#include "saharadbgdownload.h" +#include "sxgphycode-1.2.h" static int sxg_allocate_buffer_memory(struct adapter_t *adapter, u32 Size, - enum SXG_BUFFER_TYPE BufferType); -static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter, void *RcvBlock, - dma_addr_t PhysicalAddress, - u32 Length); + enum sxg_buffer_type BufferType); +static int sxg_allocate_rcvblock_complete(struct adapter_t *adapter, + void *RcvBlock, + dma_addr_t PhysicalAddress, + u32 Length); static void sxg_allocate_sgl_buffer_complete(struct adapter_t *adapter, - struct SXG_SCATTER_GATHER *SxgSgl, + struct sxg_scatter_gather *SxgSgl, dma_addr_t PhysicalAddress, u32 Length); static void sxg_mcast_init_crc32(void); - -static int sxg_entry_open(p_net_device dev); -static int sxg_entry_halt(p_net_device dev); -static int sxg_ioctl(p_net_device dev, struct ifreq *rq, int cmd); -static int sxg_send_packets(struct sk_buff *skb, p_net_device dev); +static int sxg_entry_open(struct net_device *dev); +static int sxg_second_open(struct net_device * dev); +static int sxg_entry_halt(struct net_device *dev); +static int sxg_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static int sxg_send_packets(struct sk_buff *skb, struct net_device *dev); static int sxg_transmit_packet(struct adapter_t *adapter, struct sk_buff *skb); -static void sxg_dumb_sgl(struct SCATTER_GATHER_LIST *pSgl, struct SXG_SCATTER_GATHER *SxgSgl); +static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl, + struct sxg_scatter_gather *SxgSgl); -static void sxg_handle_interrupt(struct adapter_t *adapter); +static void sxg_handle_interrupt(struct adapter_t *adapter, int *work_done, + int budget); +static void sxg_interrupt(struct adapter_t *adapter); +static int sxg_poll(struct napi_struct *napi, int budget); static int sxg_process_isr(struct adapter_t *adapter, u32 MessageId); -static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId); +static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId, + int *sxg_napi_continue, int *work_done, int budget); static void sxg_complete_slow_send(struct adapter_t *adapter); -static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter, struct SXG_EVENT *Event); +static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter, + struct sxg_event *Event); static void sxg_process_rcv_error(struct adapter_t *adapter, u32 ErrorStatus); static bool sxg_mac_filter(struct adapter_t *adapter, struct ether_header *EtherHdr, ushort length); - -#if SLIC_GET_STATS_ENABLED -static struct net_device_stats *sxg_get_stats(p_net_device dev); -#endif +static struct net_device_stats *sxg_get_stats(struct net_device * dev); +void sxg_free_resources(struct adapter_t *adapter); +void sxg_free_rcvblocks(struct adapter_t *adapter); +void sxg_free_sgl_buffers(struct adapter_t *adapter); +void sxg_unmap_resources(struct adapter_t *adapter); +void sxg_free_mcast_addrs(struct adapter_t *adapter); +void sxg_collect_statistics(struct adapter_t *adapter); +static int sxg_register_interrupt(struct adapter_t *adapter); +static void sxg_remove_isr(struct adapter_t *adapter); +static irqreturn_t sxg_isr(int irq, void *dev_id); + +static void sxg_watchdog(unsigned long data); +static void sxg_update_link_status (struct work_struct *work); #define XXXTODO 0 #if XXXTODO -static int sxg_mac_set_address(p_net_device dev, void *ptr); -static void sxg_mcast_set_list(p_net_device dev); +static int sxg_mac_set_address(struct net_device *dev, void *ptr); #endif +static void sxg_mcast_set_list(struct net_device *dev); -static void sxg_adapter_set_hwaddr(struct adapter_t *adapter); - -static void sxg_unmap_mmio_space(struct adapter_t *adapter); +static int sxg_adapter_set_hwaddr(struct adapter_t *adapter); static int sxg_initialize_adapter(struct adapter_t *adapter); static void sxg_stock_rcv_buffers(struct adapter_t *adapter); static void sxg_complete_descriptor_blocks(struct adapter_t *adapter, unsigned char Index); +int sxg_change_mtu (struct net_device *netdev, int new_mtu); static int sxg_initialize_link(struct adapter_t *adapter); static int sxg_phy_init(struct adapter_t *adapter); static void sxg_link_event(struct adapter_t *adapter); static enum SXG_LINK_STATE sxg_get_link_state(struct adapter_t *adapter); -static void sxg_link_state(struct adapter_t *adapter, enum SXG_LINK_STATE LinkState); +static void sxg_link_state(struct adapter_t *adapter, + enum SXG_LINK_STATE LinkState); static int sxg_write_mdio_reg(struct adapter_t *adapter, u32 DevAddr, u32 RegAddr, u32 Value); static int sxg_read_mdio_reg(struct adapter_t *adapter, u32 DevAddr, u32 RegAddr, u32 *pValue); +static void sxg_set_mcast_addr(struct adapter_t *adapter); static unsigned int sxg_first_init = 1; static char *sxg_banner = - "Alacritech SLIC Technology(tm) Server and Storage 10Gbe Accelerator (Non-Accelerated)\n"; + "Alacritech SLIC Technology(tm) Server and Storage \ + 10Gbe Accelerator (Non-Accelerated)\n"; static int sxg_debug = 1; static int debug = -1; -static p_net_device head_netdevice = NULL; +static struct net_device *head_netdevice = NULL; -static struct sxgbase_driver_t sxg_global = { +static struct sxgbase_driver sxg_global = { .dynamic_intagg = 1, }; static int intagg_delay = 100; static u32 dynamic_intagg = 0; -#define DRV_NAME "sxg" -#define DRV_VERSION "1.0.1" +char sxg_driver_name[] = "sxg_nic"; #define DRV_AUTHOR "Alacritech, Inc. Engineering" -#define DRV_DESCRIPTION "Alacritech SLIC Techonology(tm) Non-Accelerated 10Gbe Driver" -#define DRV_COPYRIGHT "Copyright 2000-2008 Alacritech, Inc. All rights reserved." +#define DRV_DESCRIPTION \ + "Alacritech SLIC Techonology(tm) Non-Accelerated 10Gbe Driver" +#define DRV_COPYRIGHT \ + "Copyright 2000-2008 Alacritech, Inc. All rights reserved." MODULE_AUTHOR(DRV_AUTHOR); MODULE_DESCRIPTION(DRV_DESCRIPTION); @@ -173,12 +197,6 @@ static struct pci_device_id sxg_pci_tbl[] __devinitdata = { MODULE_DEVICE_TABLE(pci, sxg_pci_tbl); -/*********************************************************************** -************************************************************************ -************************************************************************ -************************************************************************ -************************************************************************/ - static inline void sxg_reg32_write(void __iomem *reg, u32 value, bool flush) { writel(value, reg); @@ -225,17 +243,143 @@ static void sxg_dbg_macaddrs(struct adapter_t *adapter) } /* SXG Globals */ -static struct SXG_DRIVER SxgDriver; +static struct sxg_driver SxgDriver; #ifdef ATKDBG -static struct sxg_trace_buffer_t LSxgTraceBuffer; +static struct sxg_trace_buffer LSxgTraceBuffer; #endif /* ATKDBG */ -static struct sxg_trace_buffer_t *SxgTraceBuffer = NULL; +static struct sxg_trace_buffer *SxgTraceBuffer = NULL; + +/* + * MSI Related API's + */ +int sxg_register_intr(struct adapter_t *adapter); +int sxg_enable_msi_x(struct adapter_t *adapter); +int sxg_add_msi_isr(struct adapter_t *adapter); +void sxg_remove_msix_isr(struct adapter_t *adapter); +int sxg_set_interrupt_capability(struct adapter_t *adapter); + +int sxg_set_interrupt_capability(struct adapter_t *adapter) +{ + int ret; + + ret = sxg_enable_msi_x(adapter); + if (ret != STATUS_SUCCESS) { + adapter->msi_enabled = FALSE; + DBG_ERROR("sxg_set_interrupt_capability MSI-X Disable\n"); + } else { + adapter->msi_enabled = TRUE; + DBG_ERROR("sxg_set_interrupt_capability MSI-X Enable\n"); + } + return ret; +} + +int sxg_register_intr(struct adapter_t *adapter) +{ + int ret = 0; + + if (adapter->msi_enabled) { + ret = sxg_add_msi_isr(adapter); + } + else { + DBG_ERROR("MSI-X Enable Failed. Using Pin INT\n"); + ret = sxg_register_interrupt(adapter); + if (ret != STATUS_SUCCESS) { + DBG_ERROR("sxg_register_interrupt Failed\n"); + } + } + return ret; +} + +int sxg_enable_msi_x(struct adapter_t *adapter) +{ + int ret; + + adapter->nr_msix_entries = 1; + adapter->msi_entries = kmalloc(adapter->nr_msix_entries * + sizeof(struct msix_entry),GFP_KERNEL); + if (!adapter->msi_entries) { + DBG_ERROR("%s:MSI Entries memory allocation Failed\n",__func__); + return -ENOMEM; + } + memset(adapter->msi_entries, 0, adapter->nr_msix_entries * + sizeof(struct msix_entry)); + + ret = pci_enable_msix(adapter->pcidev, adapter->msi_entries, + adapter->nr_msix_entries); + if (ret) { + DBG_ERROR("Enabling MSI-X with %d vectors failed\n", + adapter->nr_msix_entries); + /*Should try with less vector returned.*/ + kfree(adapter->msi_entries); + return STATUS_FAILURE; /*MSI-X Enable failed.*/ + } + return (STATUS_SUCCESS); +} + +int sxg_add_msi_isr(struct adapter_t *adapter) +{ + int ret,i; + + if (!adapter->intrregistered) { + for (i=0; i<adapter->nr_msix_entries; i++) { + ret = request_irq (adapter->msi_entries[i].vector, + sxg_isr, + IRQF_SHARED, + adapter->netdev->name, + adapter->netdev); + if (ret) { + DBG_ERROR("sxg: MSI-X request_irq (%s) " + "FAILED [%x]\n", adapter->netdev->name, + ret); + return (ret); + } + } + } + adapter->msi_enabled = TRUE; + adapter->intrregistered = 1; + adapter->IntRegistered = TRUE; + return (STATUS_SUCCESS); +} + +void sxg_remove_msix_isr(struct adapter_t *adapter) +{ + int i,vector; + struct net_device *netdev = adapter->netdev; + + for(i=0; i< adapter->nr_msix_entries;i++) + { + vector = adapter->msi_entries[i].vector; + DBG_ERROR("%s : Freeing IRQ vector#%d\n",__FUNCTION__,vector); + free_irq(vector,netdev); + } +} + + +static void sxg_remove_isr(struct adapter_t *adapter) +{ + struct net_device *netdev = adapter->netdev; + if (adapter->msi_enabled) + sxg_remove_msix_isr(adapter); + else + free_irq(adapter->netdev->irq, netdev); +} + +void sxg_reset_interrupt_capability(struct adapter_t *adapter) +{ + if (adapter->msi_enabled) { + pci_disable_msix(adapter->pcidev); + kfree(adapter->msi_entries); + adapter->msi_entries = NULL; + } + return; +} /* * sxg_download_microcode * - * Download Microcode to Sahara adapter + * Download Microcode to Sahara adapter using the Linux + * Firmware module to get the ucode.sys file. * * Arguments - * adapter - A pointer to our adapter structure @@ -244,98 +388,141 @@ static struct sxg_trace_buffer_t *SxgTraceBuffer = NULL; * Return * int */ -static bool sxg_download_microcode(struct adapter_t *adapter, enum SXG_UCODE_SEL UcodeSel) +static bool sxg_download_microcode(struct adapter_t *adapter, + enum SXG_UCODE_SEL UcodeSel) { - struct SXG_HW_REGS *HwRegs = adapter->HwRegs; + const struct firmware *fw; + const char *file = ""; + struct sxg_hw_regs *HwRegs = adapter->HwRegs; + int ret; + int ucode_start; u32 Section; u32 ThisSectionSize; - u32 *Instruction = NULL; + u32 instruction = 0; u32 BaseAddress, AddressOffset, Address; -/* u32 Failure; */ + /* u32 Failure; */ u32 ValueRead; u32 i; - u32 numSections = 0; + u32 index = 0; + u32 num_sections = 0; u32 sectionSize[16]; u32 sectionStart[16]; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DnldUcod", adapter, 0, 0, 0); - DBG_ERROR("sxg: %s ENTER\n", __func__); - - switch (UcodeSel) { - case SXG_UCODE_SAHARA: /* Sahara operational ucode */ - numSections = SNumSections; - for (i = 0; i < numSections; i++) { - sectionSize[i] = SSectionSize[i]; - sectionStart[i] = SSectionStart[i]; - } - break; - default: - printk(KERN_ERR KBUILD_MODNAME - ": Woah, big error with the microcode!\n"); - break; + + /* + * This routine is only implemented to download the microcode + * for the Revision B Sahara chip. Rev A and Diagnostic + * microcode is not supported at this time. If Rev A or + * diagnostic ucode is required, this routine will obviously + * need to change. Also, eventually need to add support for + * Rev B checked version of ucode. That's easy enough once + * the free version of Rev B works. + */ + ASSERT(UcodeSel == SXG_UCODE_SYSTEM); + ASSERT(adapter->asictype == SAHARA_REV_B); +#if SXG_UCODE_DEBUG + file = "sxg/saharadbgdownloadB.sys"; +#else + file = "sxg/saharadownloadB.sys"; +#endif + ret = request_firmware(&fw, file, &adapter->pcidev->dev); + if (ret) { + DBG_ERROR("%s SXG_NIC: Failed to load firmware %s\n", __func__,file); + return ret; + } + + /* + * The microcode .sys file contains starts with a 4 byte word containing + * the number of sections. That is followed by "num_sections" 4 byte + * words containing each "section" size. That is followed num_sections + * 4 byte words containing each section "start" address. + * + * Following the above header, the .sys file contains num_sections, + * where each section size is specified, newline delineatetd 12 byte + * microcode instructions. + */ + num_sections = *(u32 *)(fw->data + index); + index += 4; + ASSERT(num_sections <= 3); + for (i = 0; i < num_sections; i++) { + sectionSize[i] = *(u32 *)(fw->data + index); + index += 4; + } + for (i = 0; i < num_sections; i++) { + sectionStart[i] = *(u32 *)(fw->data + index); + index += 4; } - DBG_ERROR("sxg: RESET THE CARD\n"); /* First, reset the card */ WRITE_REG(HwRegs->Reset, 0xDEAD, FLUSH); + udelay(50); + HwRegs = adapter->HwRegs; - /* Download each section of the microcode as specified in */ - /* its download file. The *download.c file is generated using */ - /* the saharaobjtoc facility which converts the metastep .obj */ - /* file to a .c file which contains a two dimentional array. */ - for (Section = 0; Section < numSections; Section++) { - DBG_ERROR("sxg: SECTION # %d\n", Section); - switch (UcodeSel) { - case SXG_UCODE_SAHARA: - Instruction = (u32 *) & SaharaUCode[Section][0]; - break; - default: - ASSERT(0); - break; - } + /* + * Download each section of the microcode as specified in + * sectionSize[index] to sectionStart[index] address. As + * described above, the .sys file contains 12 byte word + * microcode instructions. The *download.sys file is generated + * using the objtosys.exe utility that was built for Sahara + * microcode. + */ + /* See usage of this below when we read back for parity */ + ucode_start = index; + instruction = *(u32 *)(fw->data + index); + index += 4; + + for (Section = 0; Section < num_sections; Section++) { BaseAddress = sectionStart[Section]; - ThisSectionSize = sectionSize[Section] / 12; /* Size in instructions */ + /* Size in instructions */ + ThisSectionSize = sectionSize[Section] / 12; for (AddressOffset = 0; AddressOffset < ThisSectionSize; AddressOffset++) { + u32 first_instr = 0; /* See comment below */ + Address = BaseAddress + AddressOffset; ASSERT((Address & ~MICROCODE_ADDRESS_MASK) == 0); - /* Write instruction bits 31 - 0 */ - WRITE_REG(HwRegs->UcodeDataLow, *Instruction, FLUSH); - /* Write instruction bits 63-32 */ - WRITE_REG(HwRegs->UcodeDataMiddle, *(Instruction + 1), - FLUSH); - /* Write instruction bits 95-64 */ - WRITE_REG(HwRegs->UcodeDataHigh, *(Instruction + 2), - FLUSH); + /* Write instruction bits 31 - 0 (low) */ + first_instr = instruction; + WRITE_REG(HwRegs->UcodeDataLow, instruction, FLUSH); + instruction = *(u32 *)(fw->data + index); + index += 4; /* Advance to the "next" instruction */ + + /* Write instruction bits 63-32 (middle) */ + WRITE_REG(HwRegs->UcodeDataMiddle, instruction, FLUSH); + instruction = *(u32 *)(fw->data + index); + index += 4; /* Advance to the "next" instruction */ + + /* Write instruction bits 95-64 (high) */ + WRITE_REG(HwRegs->UcodeDataHigh, instruction, FLUSH); + instruction = *(u32 *)(fw->data + index); + index += 4; /* Advance to the "next" instruction */ + /* Write instruction address with the WRITE bit set */ WRITE_REG(HwRegs->UcodeAddr, (Address | MICROCODE_ADDRESS_WRITE), FLUSH); - /* Sahara bug in the ucode download logic - the write to DataLow */ - /* for the next instruction could get corrupted. To avoid this, */ - /* write to DataLow again for this instruction (which may get */ - /* corrupted, but it doesn't matter), then increment the address */ - /* and write the data for the next instruction to DataLow. That */ - /* write should succeed. */ - WRITE_REG(HwRegs->UcodeDataLow, *Instruction, TRUE); - /* Advance 3 u32S to start of next instruction */ - Instruction += 3; + /* + * Sahara bug in the ucode download logic - the write to DataLow + * for the next instruction could get corrupted. To avoid this, + * write to DataLow again for this instruction (which may get + * corrupted, but it doesn't matter), then increment the address + * and write the data for the next instruction to DataLow. That + * write should succeed. + */ + WRITE_REG(HwRegs->UcodeDataLow, first_instr, FLUSH); } } - /* Now repeat the entire operation reading the instruction back and */ - /* checking for parity errors */ - for (Section = 0; Section < numSections; Section++) { - DBG_ERROR("sxg: check SECTION # %d\n", Section); - switch (UcodeSel) { - case SXG_UCODE_SAHARA: - Instruction = (u32 *) & SaharaUCode[Section][0]; - break; - default: - ASSERT(0); - break; - } + /* + * Now repeat the entire operation reading the instruction back and + * checking for parity errors + */ + index = ucode_start; + + for (Section = 0; Section < num_sections; Section++) { BaseAddress = sectionStart[Section]; - ThisSectionSize = sectionSize[Section] / 12; /* Size in instructions */ + /* Size in instructions */ + ThisSectionSize = sectionSize[Section] / 12; for (AddressOffset = 0; AddressOffset < ThisSectionSize; AddressOffset++) { Address = BaseAddress + AddressOffset; @@ -348,62 +535,70 @@ static bool sxg_download_microcode(struct adapter_t *adapter, enum SXG_UCODE_SEL DBG_ERROR("sxg: %s PARITY ERROR\n", __func__); - return (FALSE); /* Parity error */ + return FALSE; /* Parity error */ } ASSERT((ValueRead & MICROCODE_ADDRESS_MASK) == Address); /* Read the instruction back and compare */ + /* First instruction */ + instruction = *(u32 *)(fw->data + index); + index += 4; READ_REG(HwRegs->UcodeDataLow, ValueRead); - if (ValueRead != *Instruction) { + if (ValueRead != instruction) { DBG_ERROR("sxg: %s MISCOMPARE LOW\n", __func__); - return (FALSE); /* Miscompare */ + return FALSE; /* Miscompare */ } + instruction = *(u32 *)(fw->data + index); + index += 4; READ_REG(HwRegs->UcodeDataMiddle, ValueRead); - if (ValueRead != *(Instruction + 1)) { + if (ValueRead != instruction) { DBG_ERROR("sxg: %s MISCOMPARE MIDDLE\n", __func__); - return (FALSE); /* Miscompare */ + return FALSE; /* Miscompare */ } + instruction = *(u32 *)(fw->data + index); + index += 4; READ_REG(HwRegs->UcodeDataHigh, ValueRead); - if (ValueRead != *(Instruction + 2)) { + if (ValueRead != instruction) { DBG_ERROR("sxg: %s MISCOMPARE HIGH\n", __func__); - return (FALSE); /* Miscompare */ + return FALSE; /* Miscompare */ } - /* Advance 3 u32S to start of next instruction */ - Instruction += 3; } } + /* download finished */ + release_firmware(fw); /* Everything OK, Go. */ WRITE_REG(HwRegs->UcodeAddr, MICROCODE_ADDRESS_GO, FLUSH); - /* Poll the CardUp register to wait for microcode to initialize */ - /* Give up after 10,000 attemps (500ms). */ + /* + * Poll the CardUp register to wait for microcode to initialize + * Give up after 10,000 attemps (500ms). + */ for (i = 0; i < 10000; i++) { udelay(50); READ_REG(adapter->UcodeRegs[0].CardUp, ValueRead); if (ValueRead == 0xCAFE) { - DBG_ERROR("sxg: %s BOO YA 0xCAFE\n", __func__); break; } } if (i == 10000) { - DBG_ERROR("sxg: %s TIMEOUT\n", __func__); + DBG_ERROR("sxg: %s TIMEOUT bringing up card - verify MICROCODE\n", __func__); - return (FALSE); /* Timeout */ + return FALSE; /* Timeout */ } - /* Now write the LoadSync register. This is used to */ - /* synchronize with the card so it can scribble on the memory */ - /* that contained 0xCAFE from the "CardUp" step above */ - if (UcodeSel == SXG_UCODE_SAHARA) { + /* + * Now write the LoadSync register. This is used to + * synchronize with the card so it can scribble on the memory + * that contained 0xCAFE from the "CardUp" step above + */ + if (UcodeSel == SXG_UCODE_SYSTEM) { WRITE_REG(adapter->UcodeRegs[0].LoadSync, 0, FLUSH); } SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XDnldUcd", adapter, 0, 0, 0); - DBG_ERROR("sxg: %s EXIT\n", __func__); - return (TRUE); } @@ -411,18 +606,16 @@ static bool sxg_download_microcode(struct adapter_t *adapter, enum SXG_UCODE_SEL * sxg_allocate_resources - Allocate memory and locks * * Arguments - - * adapter - A pointer to our adapter structure + * adapter - A pointer to our adapter structure * - * Return - * int + * Return - int */ static int sxg_allocate_resources(struct adapter_t *adapter) { - int status; - u32 i; + int status = STATUS_SUCCESS; u32 RssIds, IsrCount; -/* struct SXG_XMT_RING *XmtRing; */ -/* struct SXG_RCV_RING *RcvRing; */ + /* struct sxg_xmt_ring *XmtRing; */ + /* struct sxg_rcv_ring *RcvRing; */ DBG_ERROR("%s ENTER\n", __func__); @@ -432,7 +625,7 @@ static int sxg_allocate_resources(struct adapter_t *adapter) /* Windows tells us how many CPUs it plans to use for */ /* RSS */ RssIds = SXG_RSS_CPU_COUNT(adapter); - IsrCount = adapter->MsiEnabled ? RssIds : 1; + IsrCount = adapter->msi_enabled ? RssIds : 1; DBG_ERROR("%s Setup the spinlocks\n", __func__); @@ -442,6 +635,7 @@ static int sxg_allocate_resources(struct adapter_t *adapter) spin_lock_init(&adapter->XmtZeroLock); spin_lock_init(&adapter->Bit64RegLock); spin_lock_init(&adapter->AdapterLock); + atomic_set(&adapter->pending_allocations, 0); DBG_ERROR("%s Setup the lists\n", __func__); @@ -451,62 +645,82 @@ static int sxg_allocate_resources(struct adapter_t *adapter) InitializeListHead(&adapter->FreeSglBuffers); InitializeListHead(&adapter->AllSglBuffers); - /* Mark these basic allocations done. This flags essentially */ - /* tells the SxgFreeResources routine that it can grab spinlocks */ - /* and reference listheads. */ + /* + * Mark these basic allocations done. This flags essentially + * tells the SxgFreeResources routine that it can grab spinlocks + * and reference listheads. + */ adapter->BasicAllocations = TRUE; - /* Main allocation loop. Start with the maximum supported by */ - /* the microcode and back off if memory allocation */ - /* fails. If we hit a minimum, fail. */ + /* + * Main allocation loop. Start with the maximum supported by + * the microcode and back off if memory allocation + * fails. If we hit a minimum, fail. + */ for (;;) { DBG_ERROR("%s Allocate XmtRings size[%x]\n", __func__, - (unsigned int)(sizeof(struct SXG_XMT_RING) * 1)); + (unsigned int)(sizeof(struct sxg_xmt_ring) * 1)); - /* Start with big items first - receive and transmit rings. At the moment */ - /* I'm going to keep the ring size fixed and adjust the number of */ - /* TCBs if we fail. Later we might consider reducing the ring size as well.. */ + /* + * Start with big items first - receive and transmit rings. + * At the moment I'm going to keep the ring size fixed and + * adjust the TCBs if we fail. Later we might + * consider reducing the ring size as well.. + */ adapter->XmtRings = pci_alloc_consistent(adapter->pcidev, - sizeof(struct SXG_XMT_RING) * - 1, - &adapter->PXmtRings); + sizeof(struct sxg_xmt_ring) * + 1, + &adapter->PXmtRings); DBG_ERROR("%s XmtRings[%p]\n", __func__, adapter->XmtRings); if (!adapter->XmtRings) { goto per_tcb_allocation_failed; } - memset(adapter->XmtRings, 0, sizeof(struct SXG_XMT_RING) * 1); + memset(adapter->XmtRings, 0, sizeof(struct sxg_xmt_ring) * 1); DBG_ERROR("%s Allocate RcvRings size[%x]\n", __func__, - (unsigned int)(sizeof(struct SXG_RCV_RING) * 1)); + (unsigned int)(sizeof(struct sxg_rcv_ring) * 1)); adapter->RcvRings = pci_alloc_consistent(adapter->pcidev, - sizeof(struct SXG_RCV_RING) * 1, + sizeof(struct sxg_rcv_ring) * 1, &adapter->PRcvRings); DBG_ERROR("%s RcvRings[%p]\n", __func__, adapter->RcvRings); if (!adapter->RcvRings) { goto per_tcb_allocation_failed; } - memset(adapter->RcvRings, 0, sizeof(struct SXG_RCV_RING) * 1); + memset(adapter->RcvRings, 0, sizeof(struct sxg_rcv_ring) * 1); + adapter->ucode_stats = kzalloc(sizeof(struct sxg_ucode_stats), GFP_ATOMIC); + adapter->pucode_stats = pci_map_single(adapter->pcidev, + adapter->ucode_stats, + sizeof(struct sxg_ucode_stats), + PCI_DMA_FROMDEVICE); +// memset(adapter->ucode_stats, 0, sizeof(struct sxg_ucode_stats)); break; per_tcb_allocation_failed: /* an allocation failed. Free any successful allocations. */ if (adapter->XmtRings) { pci_free_consistent(adapter->pcidev, - sizeof(struct SXG_XMT_RING) * 4096, + sizeof(struct sxg_xmt_ring) * 1, adapter->XmtRings, adapter->PXmtRings); adapter->XmtRings = NULL; } if (adapter->RcvRings) { pci_free_consistent(adapter->pcidev, - sizeof(struct SXG_RCV_RING) * 4096, + sizeof(struct sxg_rcv_ring) * 1, adapter->RcvRings, adapter->PRcvRings); adapter->RcvRings = NULL; } /* Loop around and try again.... */ + if (adapter->ucode_stats) { + pci_unmap_single(adapter->pcidev, + sizeof(struct sxg_ucode_stats), + adapter->pucode_stats, PCI_DMA_FROMDEVICE); + adapter->ucode_stats = NULL; + } + } DBG_ERROR("%s Initialize RCV ZERO and XMT ZERO rings\n", __func__); @@ -515,53 +729,37 @@ static int sxg_allocate_resources(struct adapter_t *adapter) SXG_INITIALIZE_RING(adapter->XmtRingZeroInfo, SXG_XMT_RING_SIZE); /* Sanity check receive data structure format */ - ASSERT((adapter->ReceiveBufferSize == SXG_RCV_DATA_BUFFER_SIZE) || - (adapter->ReceiveBufferSize == SXG_RCV_JUMBO_BUFFER_SIZE)); - ASSERT(sizeof(struct SXG_RCV_DESCRIPTOR_BLOCK) == + /* ASSERT((adapter->ReceiveBufferSize == SXG_RCV_DATA_BUFFER_SIZE) || + (adapter->ReceiveBufferSize == SXG_RCV_JUMBO_BUFFER_SIZE)); */ + ASSERT(sizeof(struct sxg_rcv_descriptor_block) == SXG_RCV_DESCRIPTOR_BLOCK_SIZE); - /* Allocate receive data buffers. We allocate a block of buffers and */ - /* a corresponding descriptor block at once. See sxghw.h:SXG_RCV_BLOCK */ - for (i = 0; i < SXG_INITIAL_RCV_DATA_BUFFERS; - i += SXG_RCV_DESCRIPTORS_PER_BLOCK) { - sxg_allocate_buffer_memory(adapter, - SXG_RCV_BLOCK_SIZE(adapter-> - ReceiveBufferSize), - SXG_BUFFER_TYPE_RCV); - } - /* NBL resource allocation can fail in the 'AllocateComplete' routine, which */ - /* doesn't return status. Make sure we got the number of buffers we requested */ - if (adapter->FreeRcvBufferCount < SXG_INITIAL_RCV_DATA_BUFFERS) { - SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAResF6", - adapter, adapter->FreeRcvBufferCount, SXG_MAX_ENTRIES, - 0); - return (STATUS_RESOURCES); - } - DBG_ERROR("%s Allocate EventRings size[%x]\n", __func__, - (unsigned int)(sizeof(struct SXG_EVENT_RING) * RssIds)); + (unsigned int)(sizeof(struct sxg_event_ring) * RssIds)); /* Allocate event queues. */ adapter->EventRings = pci_alloc_consistent(adapter->pcidev, - sizeof(struct SXG_EVENT_RING) * - RssIds, - &adapter->PEventRings); + sizeof(struct sxg_event_ring) * + RssIds, + &adapter->PEventRings); if (!adapter->EventRings) { - /* Caller will call SxgFreeAdapter to clean up above allocations */ + /* Caller will call SxgFreeAdapter to clean up above + * allocations */ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAResF8", adapter, SXG_MAX_ENTRIES, 0, 0); status = STATUS_RESOURCES; goto per_tcb_allocation_failed; } - memset(adapter->EventRings, 0, sizeof(struct SXG_EVENT_RING) * RssIds); + memset(adapter->EventRings, 0, sizeof(struct sxg_event_ring) * RssIds); DBG_ERROR("%s Allocate ISR size[%x]\n", __func__, IsrCount); /* Allocate ISR */ adapter->Isr = pci_alloc_consistent(adapter->pcidev, IsrCount, &adapter->PIsr); if (!adapter->Isr) { - /* Caller will call SxgFreeAdapter to clean up above allocations */ + /* Caller will call SxgFreeAdapter to clean up above + * allocations */ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAResF9", adapter, SXG_MAX_ENTRIES, 0, 0); status = STATUS_RESOURCES; @@ -588,8 +786,7 @@ static int sxg_allocate_resources(struct adapter_t *adapter) SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAlcResS", adapter, SXG_MAX_ENTRIES, 0, 0); - DBG_ERROR("%s EXIT\n", __func__); - return (STATUS_SUCCESS); + return status; } /* @@ -599,7 +796,6 @@ static int sxg_allocate_resources(struct adapter_t *adapter) * * Arguments - * pcidev - A pointer to our adapter structure - * */ static void sxg_config_pci(struct pci_dev *pcidev) { @@ -609,12 +805,19 @@ static void sxg_config_pci(struct pci_dev *pcidev) pci_read_config_word(pcidev, PCI_COMMAND, &pci_command); DBG_ERROR("sxg: %s PCI command[%4.4x]\n", __func__, pci_command); /* Set the command register */ - new_command = pci_command | (PCI_COMMAND_MEMORY | /* Memory Space Enable */ - PCI_COMMAND_MASTER | /* Bus master enable */ - PCI_COMMAND_INVALIDATE | /* Memory write and invalidate */ - PCI_COMMAND_PARITY | /* Parity error response */ - PCI_COMMAND_SERR | /* System ERR */ - PCI_COMMAND_FAST_BACK); /* Fast back-to-back */ + new_command = pci_command | ( + /* Memory Space Enable */ + PCI_COMMAND_MEMORY | + /* Bus master enable */ + PCI_COMMAND_MASTER | + /* Memory write and invalidate */ + PCI_COMMAND_INVALIDATE | + /* Parity error response */ + PCI_COMMAND_PARITY | + /* System ERR */ + PCI_COMMAND_SERR | + /* Fast back-to-back */ + PCI_COMMAND_FAST_BACK); if (pci_command != new_command) { DBG_ERROR("%s -- Updating PCI COMMAND register %4.4x->%4.4x.\n", __func__, pci_command, new_command); @@ -622,6 +825,77 @@ static void sxg_config_pci(struct pci_dev *pcidev) } } +/* + * sxg_read_config + * @adapter : Pointer to the adapter structure for the card + * This function will read the configuration data from EEPROM/FLASH + */ +static inline int sxg_read_config(struct adapter_t *adapter) +{ + /* struct sxg_config data; */ + struct sxg_config *config; + struct sw_cfg_data *data; + dma_addr_t p_addr; + unsigned long status; + unsigned long i; + config = pci_alloc_consistent(adapter->pcidev, + sizeof(struct sxg_config), &p_addr); + + if(!config) { + /* + * We cant get even this much memory. Raise a hell + * Get out of here + */ + printk(KERN_ERR"%s : Could not allocate memory for reading \ + EEPROM\n", __FUNCTION__); + return -ENOMEM; + } + + data = &config->SwCfg; + + /* Initialize (reflective memory) status register */ + WRITE_REG(adapter->UcodeRegs[0].ConfigStat, SXG_CFG_TIMEOUT, TRUE); + + /* Send request to fetch configuration data */ + WRITE_REG64(adapter, adapter->UcodeRegs[0].Config, p_addr, 0); + for(i=0; i<1000; i++) { + READ_REG(adapter->UcodeRegs[0].ConfigStat, status); + if (status != SXG_CFG_TIMEOUT) + break; + mdelay(1); /* Do we really need this */ + } + + switch(status) { + /* Config read from EEPROM succeeded */ + case SXG_CFG_LOAD_EEPROM: + /* Config read from Flash succeeded */ + case SXG_CFG_LOAD_FLASH: + /* + * Copy the MAC address to adapter structure + * TODO: We are not doing the remaining part : FRU, etc + */ + memcpy(adapter->macaddr, data->MacAddr[0].MacAddr, + sizeof(struct sxg_config_mac)); + break; + case SXG_CFG_TIMEOUT: + case SXG_CFG_LOAD_INVALID: + case SXG_CFG_LOAD_ERROR: + default: /* Fix default handler later */ + printk(KERN_WARNING"%s : We could not read the config \ + word. Status = %ld\n", __FUNCTION__, status); + break; + } + pci_free_consistent(adapter->pcidev, sizeof(struct sw_cfg_data), data, + p_addr); + if (adapter->netdev) { + memcpy(adapter->netdev->dev_addr, adapter->currmacaddr, 6); + memcpy(adapter->netdev->perm_addr, adapter->currmacaddr, 6); + } + sxg_dbg_macaddrs(adapter); + + return status; +} + static int sxg_entry_probe(struct pci_dev *pcidev, const struct pci_device_id *pci_tbl_entry) { @@ -633,6 +907,7 @@ static int sxg_entry_probe(struct pci_dev *pcidev, u32 status = 0; ulong mmio_start = 0; ulong mmio_len = 0; + unsigned char revision_id; DBG_ERROR("sxg: %s 2.6 VERSION ENTER jiffies[%lx] cpu %d\n", __func__, jiffies, smp_processor_id()); @@ -654,9 +929,11 @@ static int sxg_entry_probe(struct pci_dev *pcidev, if (sxg_debug > 0 && did_version++ == 0) { printk(KERN_INFO "%s\n", sxg_banner); - printk(KERN_INFO "%s\n", DRV_VERSION); + printk(KERN_INFO "%s\n", SXG_DRV_VERSION); } + pci_read_config_byte(pcidev, PCI_REVISION_ID, &revision_id); + if (!(err = pci_set_dma_mask(pcidev, DMA_64BIT_MASK))) { DBG_ERROR("pci_set_dma_mask(DMA_64BIT_MASK) successful\n"); } else { @@ -671,7 +948,7 @@ static int sxg_entry_probe(struct pci_dev *pcidev, DBG_ERROR("Call pci_request_regions\n"); - err = pci_request_regions(pcidev, DRV_NAME); + err = pci_request_regions(pcidev, sxg_driver_name); if (err) { DBG_ERROR("pci_request_regions FAILED err[%x]\n", err); return err; @@ -692,6 +969,15 @@ static int sxg_entry_probe(struct pci_dev *pcidev, pci_set_drvdata(pcidev, netdev); adapter = netdev_priv(netdev); + if (revision_id == 1) { + adapter->asictype = SAHARA_REV_A; + } else if (revision_id == 2) { + adapter->asictype = SAHARA_REV_B; + } else { + ASSERT(0); + DBG_ERROR("%s Unexpected revision ID %x\n", __FUNCTION__, revision_id); + goto err_out_exit_sxg_probe; + } adapter->netdev = netdev; adapter->pcidev = pcidev; @@ -707,12 +993,12 @@ static int sxg_entry_probe(struct pci_dev *pcidev, if (!memmapped_ioaddr) { DBG_ERROR("%s cannot remap MMIO region %lx @ %lx\n", __func__, mmio_len, mmio_start); - goto err_out_free_mmio_region; + goto err_out_free_mmio_region_0; } - DBG_ERROR - ("sxg: %s found Alacritech SXG PCI, MMIO at %p, start[%lx] len[%lx], IRQ %d.\n", - __func__, memmapped_ioaddr, mmio_start, mmio_len, pcidev->irq); + DBG_ERROR("sxg: %s found Alacritech SXG PCI, MMIO at %p, start[%lx] \ + len[%lx], IRQ %d.\n", __func__, memmapped_ioaddr, mmio_start, + mmio_len, pcidev->irq); adapter->HwRegs = (void *)memmapped_ioaddr; adapter->base_addr = memmapped_ioaddr; @@ -729,7 +1015,7 @@ static int sxg_entry_probe(struct pci_dev *pcidev, if (!memmapped_ioaddr) { DBG_ERROR("%s cannot remap MMIO region %lx @ %lx\n", __func__, mmio_len, mmio_start); - goto err_out_free_mmio_region; + goto err_out_free_mmio_region_2; } DBG_ERROR("sxg: %s found Alacritech SXG PCI, MMIO at %p, " @@ -739,8 +1025,10 @@ static int sxg_entry_probe(struct pci_dev *pcidev, adapter->UcodeRegs = (void *)memmapped_ioaddr; adapter->State = SXG_STATE_INITIALIZING; - /* Maintain a list of all adapters anchored by */ - /* the global SxgDriver structure. */ + /* + * Maintain a list of all adapters anchored by + * the global SxgDriver structure. + */ adapter->Next = SxgDriver.Adapters; SxgDriver.Adapters = adapter; adapter->AdapterID = ++SxgDriver.AdapterID; @@ -758,10 +1046,12 @@ static int sxg_entry_probe(struct pci_dev *pcidev, adapter->ReceiveBufferSize = SXG_RCV_DATA_BUFFER_SIZE; } -/* status = SXG_READ_EEPROM(adapter); */ -/* if (!status) { */ -/* goto sxg_init_bad; */ -/* } */ + /* + * status = SXG_READ_EEPROM(adapter); + * if (!status) { + * goto sxg_init_bad; + * } + */ DBG_ERROR("sxg: %s ENTER sxg_config_pci\n", __func__); sxg_config_pci(pcidev); @@ -774,16 +1064,13 @@ static int sxg_entry_probe(struct pci_dev *pcidev, adapter->vendid = pci_tbl_entry->vendor; adapter->devid = pci_tbl_entry->device; adapter->subsysid = pci_tbl_entry->subdevice; - adapter->busnumber = pcidev->bus->number; adapter->slotnumber = ((pcidev->devfn >> 3) & 0x1F); adapter->functionnumber = (pcidev->devfn & 0x7); adapter->memorylength = pci_resource_len(pcidev, 0); adapter->irq = pcidev->irq; adapter->next_netdevice = head_netdevice; head_netdevice = netdev; -/* adapter->chipid = chip_idx; */ adapter->port = 0; /*adapter->functionnumber; */ - adapter->cardindex = adapter->port; /* Allocate memory and other resources */ DBG_ERROR("sxg: %s ENTER sxg_allocate_resources\n", __func__); @@ -795,10 +1082,11 @@ static int sxg_entry_probe(struct pci_dev *pcidev, } DBG_ERROR("sxg: %s ENTER sxg_download_microcode\n", __func__); - if (sxg_download_microcode(adapter, SXG_UCODE_SAHARA)) { + if (sxg_download_microcode(adapter, SXG_UCODE_SYSTEM)) { DBG_ERROR("sxg: %s ENTER sxg_adapter_set_hwaddr\n", __func__); - sxg_adapter_set_hwaddr(adapter); + sxg_read_config(adapter); + status = sxg_adapter_set_hwaddr(adapter); } else { adapter->state = ADAPT_FAIL; adapter->linkstate = LINK_DOWN; @@ -811,40 +1099,63 @@ static int sxg_entry_probe(struct pci_dev *pcidev, netdev->stop = sxg_entry_halt; netdev->hard_start_xmit = sxg_send_packets; netdev->do_ioctl = sxg_ioctl; + netdev->change_mtu = sxg_change_mtu; #if XXXTODO netdev->set_mac_address = sxg_mac_set_address; -#if SLIC_GET_STATS_ENABLED - netdev->get_stats = sxg_get_stats; #endif + netdev->get_stats = sxg_get_stats; netdev->set_multicast_list = sxg_mcast_set_list; -#endif + SET_ETHTOOL_OPS(netdev, &sxg_nic_ethtool_ops); + netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + err = sxg_set_interrupt_capability(adapter); + if (err != STATUS_SUCCESS) + DBG_ERROR("Cannot enable MSI-X capability\n"); strcpy(netdev->name, "eth%d"); -/* strcpy(netdev->name, pci_name(pcidev)); */ + /* strcpy(netdev->name, pci_name(pcidev)); */ if ((err = register_netdev(netdev))) { DBG_ERROR("Cannot register net device, aborting. %s\n", netdev->name); goto err_out_unmap; } + netif_napi_add(netdev, &adapter->napi, + sxg_poll, SXG_NETDEV_WEIGHT); + netdev->watchdog_timeo = 2 * HZ; + init_timer(&adapter->watchdog_timer); + adapter->watchdog_timer.function = &sxg_watchdog; + adapter->watchdog_timer.data = (unsigned long) adapter; + INIT_WORK(&adapter->update_link_status, sxg_update_link_status); + DBG_ERROR - ("sxg: %s addr 0x%lx, irq %d, MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n", + ("sxg: %s addr 0x%lx, irq %d, MAC addr \ + %02X:%02X:%02X:%02X:%02X:%02X\n", netdev->name, netdev->base_addr, pcidev->irq, netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); -/*sxg_init_bad: */ + /* sxg_init_bad: */ ASSERT(status == FALSE); -/* sxg_free_adapter(adapter); */ + /* sxg_free_adapter(adapter); */ DBG_ERROR("sxg: %s EXIT status[%x] jiffies[%lx] cpu %d\n", __func__, status, jiffies, smp_processor_id()); return status; err_out_unmap: - iounmap((void *)memmapped_ioaddr); + sxg_free_resources(adapter); + + err_out_free_mmio_region_2: + + mmio_start = pci_resource_start(pcidev, 2); + mmio_len = pci_resource_len(pcidev, 2); + release_mem_region(mmio_start, mmio_len); + + err_out_free_mmio_region_0: + + mmio_start = pci_resource_start(pcidev, 0); + mmio_len = pci_resource_len(pcidev, 0); - err_out_free_mmio_region: release_mem_region(mmio_start, mmio_len); err_out_exit_sxg_probe: @@ -852,13 +1163,16 @@ static int sxg_entry_probe(struct pci_dev *pcidev, DBG_ERROR("%s EXIT jiffies[%lx] cpu %d\n", __func__, jiffies, smp_processor_id()); + pci_disable_device(pcidev); + DBG_ERROR("sxg: %s deallocate device\n", __FUNCTION__); + kfree(netdev); + printk("Exit %s, Sxg driver loading failed..\n", __FUNCTION__); + return -ENODEV; } -/*********************************************************************** - * LINE BASE Interrupt routines.. - ***********************************************************************/ /* + * LINE BASE Interrupt routines.. * * sxg_disable_interrupt * @@ -877,10 +1191,7 @@ static void sxg_disable_interrupt(struct adapter_t *adapter) adapter, adapter->InterruptsEnabled, 0, 0); /* For now, RSS is disabled with line based interrupts */ ASSERT(adapter->RssEnabled == FALSE); - ASSERT(adapter->MsiEnabled == FALSE); - /* */ /* Turn off interrupts by writing to the icr register. */ - /* */ WRITE_REG(adapter->UcodeRegs[0].Icr, SXG_ICR(0, SXG_ICR_DISABLE), TRUE); adapter->InterruptsEnabled = 0; @@ -890,7 +1201,6 @@ static void sxg_disable_interrupt(struct adapter_t *adapter) } /* - * * sxg_enable_interrupt * * EnableInterrupt Handler @@ -908,10 +1218,7 @@ static void sxg_enable_interrupt(struct adapter_t *adapter) adapter, adapter->InterruptsEnabled, 0, 0); /* For now, RSS is disabled with line based interrupts */ ASSERT(adapter->RssEnabled == FALSE); - ASSERT(adapter->MsiEnabled == FALSE); - /* */ /* Turn on interrupts by writing to the icr register. */ - /* */ WRITE_REG(adapter->UcodeRegs[0].Icr, SXG_ICR(0, SXG_ICR_ENABLE), TRUE); adapter->InterruptsEnabled = 1; @@ -921,50 +1228,51 @@ static void sxg_enable_interrupt(struct adapter_t *adapter) } /* - * * sxg_isr - Process an line-based interrupt * * Arguments: - * Context - Our adapter structure + * Context - Our adapter structure * QueueDefault - Output parameter to queue to default CPU - * TargetCpus - Output bitmap to schedule DPC's + * TargetCpus - Output bitmap to schedule DPC's * - * Return Value: - * TRUE if our interrupt + * Return Value: TRUE if our interrupt */ static irqreturn_t sxg_isr(int irq, void *dev_id) { - p_net_device dev = (p_net_device) dev_id; + struct net_device *dev = (struct net_device *) dev_id; struct adapter_t *adapter = (struct adapter_t *) netdev_priv(dev); -/* u32 CpuMask = 0, i; */ + if(adapter->state != ADAPT_UP) + return IRQ_NONE; adapter->Stats.NumInts++; if (adapter->Isr[0] == 0) { - /* The SLIC driver used to experience a number of spurious interrupts */ - /* due to the delay associated with the masking of the interrupt */ - /* (we'd bounce back in here). If we see that again with Sahara, */ - /* add a READ_REG of the Icr register after the WRITE_REG below. */ + /* + * The SLIC driver used to experience a number of spurious + * interrupts due to the delay associated with the masking of + * the interrupt (we'd bounce back in here). If we see that + * again with Sahara,add a READ_REG of the Icr register after + * the WRITE_REG below. + */ adapter->Stats.FalseInts++; return IRQ_NONE; } - /* */ - /* Move the Isr contents and clear the value in */ - /* shared memory, and mask interrupts */ - /* */ - adapter->IsrCopy[0] = adapter->Isr[0]; - adapter->Isr[0] = 0; - WRITE_REG(adapter->UcodeRegs[0].Icr, SXG_ICR(0, SXG_ICR_MASK), TRUE); -/* ASSERT(adapter->IsrDpcsPending == 0); */ + /* + * Move the Isr contents and clear the value in + * shared memory, and mask interrupts + */ + /* ASSERT(adapter->IsrDpcsPending == 0); */ #if XXXTODO /* RSS Stuff */ - /* If RSS is enabled and the ISR specifies */ - /* SXG_ISR_EVENT, then schedule DPC's */ - /* based on event queues. */ + /* + * If RSS is enabled and the ISR specifies SXG_ISR_EVENT, then + * schedule DPC's based on event queues. + */ if (adapter->RssEnabled && (adapter->IsrCopy[0] & SXG_ISR_EVENT)) { for (i = 0; i < adapter->RssSystemInfo->ProcessorInfo.RssCpuCount; i++) { - struct XG_EVENT_RING *EventRing = &adapter->EventRings[i]; - struct SXG_EVENT *Event = + struct sxg_event_ring *EventRing = + &adapter->EventRings[i]; + struct sxg_event *Event = &EventRing->Ring[adapter->NextEvent[i]]; unsigned char Cpu = adapter->RssSystemInfo->RssIdToCpu[i]; @@ -974,8 +1282,10 @@ static irqreturn_t sxg_isr(int irq, void *dev_id) } } } - /* Now, either schedule the CPUs specified by the CpuMask, */ - /* or queue default */ + /* + * Now, either schedule the CPUs specified by the CpuMask, + * or queue default + */ if (CpuMask) { *QueueDefault = FALSE; } else { @@ -984,34 +1294,41 @@ static irqreturn_t sxg_isr(int irq, void *dev_id) } *TargetCpus = CpuMask; #endif - /* */ - /* There are no DPCs in Linux, so call the handler now */ - /* */ - sxg_handle_interrupt(adapter); + sxg_interrupt(adapter); return IRQ_HANDLED; } -static void sxg_handle_interrupt(struct adapter_t *adapter) +static void sxg_interrupt(struct adapter_t *adapter) { -/* unsigned char RssId = 0; */ - u32 NewIsr; + WRITE_REG(adapter->UcodeRegs[0].Icr, SXG_ICR(0, SXG_ICR_MASK), TRUE); - if (adapter->Stats.RcvNoBuffer < 5) { - DBG_ERROR("Enter sxg_handle_interrupt ISR[%x]\n", - adapter->IsrCopy[0]); + if (napi_schedule_prep(&adapter->napi)) { + __napi_schedule(&adapter->napi); } +} + +static void sxg_handle_interrupt(struct adapter_t *adapter, int *work_done, + int budget) +{ + /* unsigned char RssId = 0; */ + u32 NewIsr; + int sxg_napi_continue = 1; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "HndlIntr", adapter, adapter->IsrCopy[0], 0, 0); /* For now, RSS is disabled with line based interrupts */ ASSERT(adapter->RssEnabled == FALSE); - ASSERT(adapter->MsiEnabled == FALSE); - ASSERT(adapter->IsrCopy[0]); -/*/////////////////////////// */ + + adapter->IsrCopy[0] = adapter->Isr[0]; + adapter->Isr[0] = 0; /* Always process the event queue. */ - sxg_process_event_queue(adapter, - (adapter->RssEnabled ? /*RssId */ 0 : 0)); + while (sxg_napi_continue) + { + sxg_process_event_queue(adapter, + (adapter->RssEnabled ? /*RssId */ 0 : 0), + &sxg_napi_continue, work_done, budget); + } #if XXXTODO /* RSS stuff */ if (--adapter->IsrDpcsPending) { @@ -1022,30 +1339,31 @@ static void sxg_handle_interrupt(struct adapter_t *adapter) return; } #endif - /* */ /* Last (or only) DPC processes the ISR and clears the interrupt. */ - /* */ NewIsr = sxg_process_isr(adapter, 0); - /* */ /* Reenable interrupts */ - /* */ adapter->IsrCopy[0] = 0; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "ClearIsr", adapter, NewIsr, 0, 0); - if (adapter->Stats.RcvNoBuffer < 5) { - DBG_ERROR - ("Exit sxg_handle_interrupt2 after enabling interrupt\n"); - } - - WRITE_REG(adapter->UcodeRegs[0].Isr, NewIsr, TRUE); - SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XHndlInt", adapter, 0, 0, 0); } +static int sxg_poll(struct napi_struct *napi, int budget) +{ + struct adapter_t *adapter = container_of(napi, struct adapter_t, napi); + int work_done = 0; + + sxg_handle_interrupt(adapter, &work_done, budget); + + if (work_done < budget) { + napi_complete(napi); + WRITE_REG(adapter->UcodeRegs[0].Isr, 0, TRUE); + } + return work_done; +} /* - * * sxg_process_isr - Process an interrupt. Called from the line-based and * message based interrupt DPC routines * @@ -1072,24 +1390,28 @@ static int sxg_process_isr(struct adapter_t *adapter, u32 MessageId) } /* No host buffer */ if (Isr & SXG_ISR_RMISS) { - /* There is a bunch of code in the SLIC driver which */ - /* attempts to process more receive events per DPC */ - /* if we start to fall behind. We'll probably */ - /* need to do something similar here, but hold */ - /* off for now. I don't want to make the code more */ - /* complicated than strictly needed. */ - adapter->Stats.RcvNoBuffer++; - if (adapter->Stats.RcvNoBuffer < 5) { + /* + * There is a bunch of code in the SLIC driver which + * attempts to process more receive events per DPC + * if we start to fall behind. We'll probablyd + * need to do something similar here, but hold + * off for now. I don't want to make the code more + * complicated than strictly needed. + */ + adapter->stats.rx_missed_errors++; + if (adapter->stats.rx_missed_errors< 5) { DBG_ERROR("%s: SXG_ISR_ERR RMISS!!\n", __func__); } } /* Card crash */ if (Isr & SXG_ISR_DEAD) { - /* Set aside the crash info and set the adapter state to RESET */ - adapter->CrashCpu = - (unsigned char)((Isr & SXG_ISR_CPU) >> - SXG_ISR_CPU_SHIFT); + /* + * Set aside the crash info and set the adapter state + * to RESET + */ + adapter->CrashCpu = (unsigned char) + ((Isr & SXG_ISR_CPU) >> SXG_ISR_CPU_SHIFT); adapter->CrashLocation = (ushort) (Isr & SXG_ISR_CRASH); adapter->Dead = TRUE; DBG_ERROR("%s: ISR_DEAD %x, CPU: %d\n", __func__, @@ -1097,18 +1419,18 @@ static int sxg_process_isr(struct adapter_t *adapter, u32 MessageId) } /* Event ring full */ if (Isr & SXG_ISR_ERFULL) { - /* Same issue as RMISS, really. This means the */ - /* host is falling behind the card. Need to increase */ - /* event ring size, process more events per interrupt, */ - /* and/or reduce/remove interrupt aggregation. */ + /* + * Same issue as RMISS, really. This means the + * host is falling behind the card. Need to increase + * event ring size, process more events per interrupt, + * and/or reduce/remove interrupt aggregation. + */ adapter->Stats.EventRingFull++; DBG_ERROR("%s: SXG_ISR_ERR EVENT RING FULL!!\n", __func__); } /* Transmit drop - no DRAM buffers or XMT error */ if (Isr & SXG_ISR_XDROP) { - adapter->Stats.XmtDrops++; - adapter->Stats.XmtErrors++; DBG_ERROR("%s: SXG_ISR_ERR XDROP!!\n", __func__); } } @@ -1118,18 +1440,24 @@ static int sxg_process_isr(struct adapter_t *adapter, u32 MessageId) } /* Dump */ if (Isr & SXG_ISR_UPC) { - ASSERT(adapter->DumpCmdRunning); /* Maybe change when debug is added.. */ + /* Maybe change when debug is added.. */ +// ASSERT(adapter->DumpCmdRunning); adapter->DumpCmdRunning = FALSE; } /* Link event */ if (Isr & SXG_ISR_LINK) { - sxg_link_event(adapter); + if (adapter->state != ADAPT_DOWN) { + adapter->link_status_changed = 1; + schedule_work(&adapter->update_link_status); + } } /* Debug - breakpoint hit */ if (Isr & SXG_ISR_BREAK) { - /* At the moment AGDB isn't written to support interactive */ - /* debug sessions. When it is, this interrupt will be used */ - /* to signal AGDB that it has hit a breakpoint. For now, ASSERT. */ + /* + * At the moment AGDB isn't written to support interactive + * debug sessions. When it is, this interrupt will be used to + * signal AGDB that it has hit a breakpoint. For now, ASSERT. + */ ASSERT(0); } /* Heartbeat response */ @@ -1143,7 +1471,33 @@ static int sxg_process_isr(struct adapter_t *adapter, u32 MessageId) } /* + * sxg_rcv_checksum - Set the checksum for received packet * + * Arguements: + * @adapter - Adapter structure on which packet is received + * @skb - Packet which is receieved + * @Event - Event read from hardware + */ + +void sxg_rcv_checksum(struct adapter_t *adapter, struct sk_buff *skb, + struct sxg_event *Event) +{ + skb->ip_summed = CHECKSUM_NONE; + if (likely(adapter->flags & SXG_RCV_IP_CSUM_ENABLED)) { + if (likely(adapter->flags & SXG_RCV_TCP_CSUM_ENABLED) + && (Event->Status & EVENT_STATUS_TCPIP)) { + if(!(Event->Status & EVENT_STATUS_TCPBAD)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + if(!(Event->Status & EVENT_STATUS_IPBAD)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else if(Event->Status & EVENT_STATUS_IPONLY) { + if(!(Event->Status & EVENT_STATUS_IPBAD)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + } +} + +/* * sxg_process_event_queue - Process our event queue * * Arguments: @@ -1153,46 +1507,52 @@ static int sxg_process_isr(struct adapter_t *adapter, u32 MessageId) * Return Value: * None. */ -static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId) +static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId, + int *sxg_napi_continue, int *work_done, int budget) { - struct SXG_EVENT_RING *EventRing = &adapter->EventRings[RssId]; - struct SXG_EVENT *Event = &EventRing->Ring[adapter->NextEvent[RssId]]; + struct sxg_event_ring *EventRing = &adapter->EventRings[RssId]; + struct sxg_event *Event = &EventRing->Ring[adapter->NextEvent[RssId]]; u32 EventsProcessed = 0, Batches = 0; - u32 num_skbs = 0; struct sk_buff *skb; #ifdef LINUX_HANDLES_RCV_INDICATION_LISTS struct sk_buff *prev_skb = NULL; struct sk_buff *IndicationList[SXG_RCV_ARRAYSIZE]; u32 Index; - struct SXG_RCV_DATA_BUFFER_HDR *RcvDataBufferHdr; + struct sxg_rcv_data_buffer_hdr *RcvDataBufferHdr; #endif u32 ReturnStatus = 0; + int sxg_rcv_data_buffers = SXG_RCV_DATA_BUFFERS; ASSERT((adapter->State == SXG_STATE_RUNNING) || (adapter->State == SXG_STATE_PAUSING) || (adapter->State == SXG_STATE_PAUSED) || (adapter->State == SXG_STATE_HALTING)); - /* We may still have unprocessed events on the queue if */ - /* the card crashed. Don't process them. */ + /* + * We may still have unprocessed events on the queue if + * the card crashed. Don't process them. + */ if (adapter->Dead) { return (0); } - /* In theory there should only be a single processor that */ - /* accesses this queue, and only at interrupt-DPC time. So */ - /* we shouldn't need a lock for any of this. */ + /* + * In theory there should only be a single processor that + * accesses this queue, and only at interrupt-DPC time. So/ + * we shouldn't need a lock for any of this. + */ while (Event->Status & EVENT_STATUS_VALID) { + (*sxg_napi_continue) = 1; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "Event", Event, Event->Code, Event->Status, adapter->NextEvent); switch (Event->Code) { case EVENT_CODE_BUFFERS: - ASSERT(!(Event->CommandIndex & 0xFF00)); /* SXG_RING_INFO Head & Tail == unsigned char */ - /* */ + /* struct sxg_ring_info Head & Tail == unsigned char */ + ASSERT(!(Event->CommandIndex & 0xFF00)); sxg_complete_descriptor_blocks(adapter, Event->CommandIndex); - /* */ break; case EVENT_CODE_SLOWRCV: + (*work_done)++; --adapter->RcvBuffersOnCard; if ((skb = sxg_slow_receive(adapter, Event))) { u32 rx_bytes; @@ -1200,51 +1560,61 @@ static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId) /* Add it to our indication list */ SXG_ADD_RCV_PACKET(adapter, skb, prev_skb, IndicationList, num_skbs); - /* In Linux, we just pass up each skb to the protocol above at this point, */ - /* there is no capability of an indication list. */ + /* + * Linux, we just pass up each skb to the + * protocol above at this point, there is no + * capability of an indication list. + */ #else -/* CHECK skb_pull(skb, INIC_RCVBUF_HEADSIZE); */ - rx_bytes = Event->Length; /* (rcvbuf->length & IRHDDR_FLEN_MSK); */ - skb_put(skb, rx_bytes); + /* CHECK skb_pull(skb, INIC_RCVBUF_HEADSIZE); */ + /* (rcvbuf->length & IRHDDR_FLEN_MSK); */ + rx_bytes = Event->Length; adapter->stats.rx_packets++; adapter->stats.rx_bytes += rx_bytes; -#if SXG_OFFLOAD_IP_CHECKSUM - skb->ip_summed = CHECKSUM_UNNECESSARY; -#endif + sxg_rcv_checksum(adapter, skb, Event); skb->dev = adapter->netdev; - skb->protocol = eth_type_trans(skb, skb->dev); - netif_rx(skb); + netif_receive_skb(skb); #endif } break; default: DBG_ERROR("%s: ERROR Invalid EventCode %d\n", __func__, Event->Code); -/* ASSERT(0); */ + /* ASSERT(0); */ } - /* See if we need to restock card receive buffers. */ - /* There are two things to note here: */ - /* First - This test is not SMP safe. The */ - /* adapter->BuffersOnCard field is protected via atomic interlocked calls, but */ - /* we do not protect it with respect to these tests. The only way to do that */ - /* is with a lock, and I don't want to grab a lock every time we adjust the */ - /* BuffersOnCard count. Instead, we allow the buffer replenishment to be off */ - /* once in a while. The worst that can happen is the card is given one */ - /* more-or-less descriptor block than the arbitrary value we've chosen. */ - /* No big deal */ - /* In short DO NOT ADD A LOCK HERE, OR WHERE RcvBuffersOnCard is adjusted. */ - /* Second - We expect this test to rarely evaluate to true. We attempt to */ - /* refill descriptor blocks as they are returned to us */ - /* (sxg_complete_descriptor_blocks), so The only time this should evaluate */ - /* to true is when sxg_complete_descriptor_blocks failed to allocate */ - /* receive buffers. */ - if (adapter->RcvBuffersOnCard < SXG_RCV_DATA_BUFFERS) { + /* + * See if we need to restock card receive buffers. + * There are two things to note here: + * First - This test is not SMP safe. The + * adapter->BuffersOnCard field is protected via atomic + * interlocked calls, but we do not protect it with respect + * to these tests. The only way to do that is with a lock, + * and I don't want to grab a lock every time we adjust the + * BuffersOnCard count. Instead, we allow the buffer + * replenishment to be off once in a while. The worst that + * can happen is the card is given on more-or-less descriptor + * block than the arbitrary value we've chosen. No big deal + * In short DO NOT ADD A LOCK HERE, OR WHERE RcvBuffersOnCard + * is adjusted. + * Second - We expect this test to rarely + * evaluate to true. We attempt to refill descriptor blocks + * as they are returned to us (sxg_complete_descriptor_blocks) + * so The only time this should evaluate to true is when + * sxg_complete_descriptor_blocks failed to allocate + * receive buffers. + */ + if (adapter->JumboEnabled) + sxg_rcv_data_buffers = SXG_JUMBO_RCV_DATA_BUFFERS; + + if (adapter->RcvBuffersOnCard < sxg_rcv_data_buffers) { sxg_stock_rcv_buffers(adapter); } - /* It's more efficient to just set this to zero. */ - /* But clearing the top bit saves potential debug info... */ + /* + * It's more efficient to just set this to zero. + * But clearing the top bit saves potential debug info... + */ Event->Status &= ~EVENT_STATUS_VALID; - /* Advanct to the next event */ + /* Advance to the next event */ SXG_ADVANCE_INDEX(adapter->NextEvent[RssId], EVENT_RING_SIZE); Event = &EventRing->Ring[adapter->NextEvent[RssId]]; EventsProcessed++; @@ -1253,9 +1623,11 @@ static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId) WRITE_REG(adapter->UcodeRegs[RssId].EventRelease, EVENT_RING_BATCH, FALSE); EventsProcessed = 0; - /* If we've processed our batch limit, break out of the */ - /* loop and return SXG_ISR_EVENT to arrange for us to */ - /* be called again */ + /* + * If we've processed our batch limit, break out of the + * loop and return SXG_ISR_EVENT to arrange for us to + * be called again + */ if (Batches++ == EVENT_BATCH_LIMIT) { SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "EvtLimit", Batches, @@ -1264,16 +1636,22 @@ static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId) break; } } + if (*work_done >= budget) { + WRITE_REG(adapter->UcodeRegs[RssId].EventRelease, + EventsProcessed, FALSE); + EventsProcessed = 0; + (*sxg_napi_continue) = 0; + break; + } } + if (!(Event->Status & EVENT_STATUS_VALID)) + (*sxg_napi_continue) = 0; + #ifdef LINUX_HANDLES_RCV_INDICATION_LISTS - /* */ /* Indicate any received dumb-nic frames */ - /* */ SXG_INDICATE_PACKETS(adapter, IndicationList, num_skbs); #endif - /* */ /* Release events back to the card. */ - /* */ if (EventsProcessed) { WRITE_REG(adapter->UcodeRegs[RssId].EventRelease, EventsProcessed, FALSE); @@ -1289,27 +1667,35 @@ static u32 sxg_process_event_queue(struct adapter_t *adapter, u32 RssId) * * Arguments - * adapter - A pointer to our adapter structure - * Return * None */ static void sxg_complete_slow_send(struct adapter_t *adapter) { - struct SXG_XMT_RING *XmtRing = &adapter->XmtRings[0]; - struct SXG_RING_INFO *XmtRingInfo = &adapter->XmtRingZeroInfo; + struct sxg_xmt_ring *XmtRing = &adapter->XmtRings[0]; + struct sxg_ring_info *XmtRingInfo = &adapter->XmtRingZeroInfo; u32 *ContextType; - struct SXG_CMD *XmtCmd; + struct sxg_cmd *XmtCmd; + unsigned long flags = 0; + unsigned long sgl_flags = 0; + unsigned int processed_count = 0; + + /* + * NOTE - This lock is dropped and regrabbed in this loop. + * This means two different processors can both be running/ + * through this loop. Be *very* careful. + */ + spin_lock_irqsave(&adapter->XmtZeroLock, flags); - /* NOTE - This lock is dropped and regrabbed in this loop. */ - /* This means two different processors can both be running */ - /* through this loop. Be *very* careful. */ - spin_lock(&adapter->XmtZeroLock); SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "CmpSnds", adapter, XmtRingInfo->Head, XmtRingInfo->Tail, 0); - while (XmtRingInfo->Tail != *adapter->XmtRingZeroIndex) { - /* Locate the current Cmd (ring descriptor entry), and */ - /* associated SGL, and advance the tail */ + while ((XmtRingInfo->Tail != *adapter->XmtRingZeroIndex) + && processed_count++ < SXG_COMPLETE_SLOW_SEND_LIMIT) { + /* + * Locate the current Cmd (ring descriptor entry), and + * associated SGL, and advance the tail + */ SXG_RETURN_CMD(XmtRing, XmtRingInfo, XmtCmd, ContextType); ASSERT(ContextType); SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "CmpSnd", @@ -1321,30 +1707,45 @@ static void sxg_complete_slow_send(struct adapter_t *adapter) case SXG_SGL_DUMB: { struct sk_buff *skb; + struct sxg_scatter_gather *SxgSgl = + (struct sxg_scatter_gather *)ContextType; + dma64_addr_t FirstSgeAddress; + u32 FirstSgeLength; + /* Dumb-nic send. Command context is the dumb-nic SGL */ skb = (struct sk_buff *)ContextType; + skb = SxgSgl->DumbPacket; + FirstSgeAddress = XmtCmd->Buffer.FirstSgeAddress; + FirstSgeLength = XmtCmd->Buffer.FirstSgeLength; /* Complete the send */ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "DmSndCmp", skb, 0, 0, 0); ASSERT(adapter->Stats.XmtQLen); - adapter->Stats.XmtQLen--; /* within XmtZeroLock */ - adapter->Stats.XmtOk++; - /* Now drop the lock and complete the send back to */ - /* Microsoft. We need to drop the lock because */ - /* Microsoft can come back with a chimney send, which */ - /* results in a double trip in SxgTcpOuput */ - spin_unlock(&adapter->XmtZeroLock); - SXG_COMPLETE_DUMB_SEND(adapter, skb); + /* + * Now drop the lock and complete the send + * back to Microsoft. We need to drop the lock + * because Microsoft can come back with a + * chimney send, which results in a double trip + * in SxgTcpOuput + */ + spin_unlock_irqrestore( + &adapter->XmtZeroLock, flags); + + SxgSgl->DumbPacket = NULL; + SXG_COMPLETE_DUMB_SEND(adapter, skb, + FirstSgeAddress, + FirstSgeLength); + SXG_FREE_SGL_BUFFER(adapter, SxgSgl, NULL); /* and reacquire.. */ - spin_lock(&adapter->XmtZeroLock); + spin_lock_irqsave(&adapter->XmtZeroLock, flags); } break; default: ASSERT(0); } } - spin_unlock(&adapter->XmtZeroLock); + spin_unlock_irqrestore(&adapter->XmtZeroLock, flags); SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "CmpSnd", adapter, XmtRingInfo->Head, XmtRingInfo->Tail, 0); } @@ -1356,22 +1757,27 @@ static void sxg_complete_slow_send(struct adapter_t *adapter) * adapter - A pointer to our adapter structure * Event - Receive event * - * Return - * skb + * Return - skb */ -static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter, struct SXG_EVENT *Event) +static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter, + struct sxg_event *Event) { - struct SXG_RCV_DATA_BUFFER_HDR *RcvDataBufferHdr; + u32 BufferSize = adapter->ReceiveBufferSize; + struct sxg_rcv_data_buffer_hdr *RcvDataBufferHdr; struct sk_buff *Packet; + static int read_counter = 0; - RcvDataBufferHdr = (struct SXG_RCV_DATA_BUFFER_HDR*) Event->HostHandle; + RcvDataBufferHdr = (struct sxg_rcv_data_buffer_hdr *) Event->HostHandle; + if(read_counter++ & 0x100) + { + sxg_collect_statistics(adapter); + read_counter = 0; + } ASSERT(RcvDataBufferHdr); ASSERT(RcvDataBufferHdr->State == SXG_BUFFER_ONCARD); - ASSERT(SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr) == - RcvDataBufferHdr->VirtualAddress); SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "SlowRcv", Event, RcvDataBufferHdr, RcvDataBufferHdr->State, - RcvDataBufferHdr->VirtualAddress); + /*RcvDataBufferHdr->VirtualAddress*/ 0); /* Drop rcv frames in non-running state */ switch (adapter->State) { case SXG_STATE_RUNNING: @@ -1385,14 +1791,16 @@ static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter, struct SXG_EV goto drop; } + /* + * memcpy(SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr), + * RcvDataBufferHdr->VirtualAddress, Event->Length); + */ + /* Change buffer state to UPSTREAM */ RcvDataBufferHdr->State = SXG_BUFFER_UPSTREAM; if (Event->Status & EVENT_STATUS_RCVERR) { SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "RcvError", Event, Event->Status, Event->HostHandle, 0); - /* XXXTODO - Remove this print later */ - DBG_ERROR("SXG: Receive error %x\n", *(u32 *) - SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr)); sxg_process_rcv_error(adapter, *(u32 *) SXG_RECEIVE_DATA_LOCATION (RcvDataBufferHdr)); @@ -1400,8 +1808,9 @@ static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter, struct SXG_EV } #if XXXTODO /* VLAN stuff */ /* If there's a VLAN tag, extract it and validate it */ - if (((struct ether_header*) (SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr)))-> - EtherType == ETHERTYPE_VLAN) { + if (((struct ether_header *) + (SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr)))->EtherType + == ETHERTYPE_VLAN) { if (SxgExtractVlanHeader(adapter, RcvDataBufferHdr, Event) != STATUS_SUCCESS) { SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, @@ -1412,33 +1821,41 @@ static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter, struct SXG_EV } } #endif - /* */ /* Dumb-nic frame. See if it passes our mac filter and update stats */ - /* */ - if (!sxg_mac_filter(adapter, (struct ether_header*) - SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr), - Event->Length)) { + + if (!sxg_mac_filter(adapter, + (struct ether_header *)(SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr)), + Event->Length)) { SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "RcvFiltr", - Event, SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr), - Event->Length, 0); - goto drop; + Event, SXG_RECEIVE_DATA_LOCATION(RcvDataBufferHdr), + Event->Length, 0); + goto drop; } Packet = RcvDataBufferHdr->SxgDumbRcvPacket; + SXG_ADJUST_RCV_PACKET(Packet, RcvDataBufferHdr, Event); + Packet->protocol = eth_type_trans(Packet, adapter->netdev); SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "DumbRcv", RcvDataBufferHdr, Packet, Event->Length, 0); - /* */ /* Lastly adjust the receive packet length. */ - /* */ - SXG_ADJUST_RCV_PACKET(Packet, RcvDataBufferHdr, Event); - + RcvDataBufferHdr->SxgDumbRcvPacket = NULL; + RcvDataBufferHdr->PhysicalAddress = (dma_addr_t)NULL; + SXG_ALLOCATE_RCV_PACKET(adapter, RcvDataBufferHdr, BufferSize); + if (RcvDataBufferHdr->skb) + { + spin_lock(&adapter->RcvQLock); + SXG_FREE_RCV_DATA_BUFFER(adapter, RcvDataBufferHdr); + // adapter->RcvBuffersOnCard ++; + spin_unlock(&adapter->RcvQLock); + } return (Packet); drop: SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DropRcv", RcvDataBufferHdr, Event->Length, 0, 0); - adapter->Stats.RcvDiscards++; + adapter->stats.rx_dropped++; +// adapter->Stats.RcvDiscards++; spin_lock(&adapter->RcvQLock); SXG_FREE_RCV_DATA_BUFFER(adapter, RcvDataBufferHdr); spin_unlock(&adapter->RcvQLock); @@ -1453,14 +1870,13 @@ static struct sk_buff *sxg_slow_receive(struct adapter_t *adapter, struct SXG_EV * adapter - Adapter structure * ErrorStatus - 4-byte receive error status * - * Return Value: - * None + * Return Value : None */ static void sxg_process_rcv_error(struct adapter_t *adapter, u32 ErrorStatus) { u32 Error; - adapter->Stats.RcvErrors++; + adapter->stats.rx_errors++; if (ErrorStatus & SXG_RCV_STATUS_TRANSPORT_ERROR) { Error = ErrorStatus & SXG_RCV_STATUS_TRANSPORT_MASK; @@ -1532,13 +1948,13 @@ static void sxg_process_rcv_error(struct adapter_t *adapter, u32 ErrorStatus) * pether - Ethernet header * length - Frame length * - * Return Value: - * TRUE if the frame is to be allowed + * Return Value : TRUE if the frame is to be allowed */ -static bool sxg_mac_filter(struct adapter_t *adapter, struct ether_header *EtherHdr, - ushort length) +static bool sxg_mac_filter(struct adapter_t *adapter, + struct ether_header *EtherHdr, ushort length) { bool EqualAddr; + struct net_device *dev = adapter->netdev; if (SXG_MULTICAST_PACKET(EtherHdr)) { if (SXG_BROADCAST_PACKET(EtherHdr)) { @@ -1546,8 +1962,6 @@ static bool sxg_mac_filter(struct adapter_t *adapter, struct ether_header *Ether if (adapter->MacFilter & MAC_BCAST) { adapter->Stats.DumbRcvBcastPkts++; adapter->Stats.DumbRcvBcastBytes += length; - adapter->Stats.DumbRcvPkts++; - adapter->Stats.DumbRcvBytes += length; return (TRUE); } } else { @@ -1555,15 +1969,12 @@ static bool sxg_mac_filter(struct adapter_t *adapter, struct ether_header *Ether if (adapter->MacFilter & MAC_ALLMCAST) { adapter->Stats.DumbRcvMcastPkts++; adapter->Stats.DumbRcvMcastBytes += length; - adapter->Stats.DumbRcvPkts++; - adapter->Stats.DumbRcvBytes += length; return (TRUE); } if (adapter->MacFilter & MAC_MCAST) { - struct SXG_MULTICAST_ADDRESS *MulticastAddrs = - adapter->MulticastAddrs; - while (MulticastAddrs) { - ETHER_EQ_ADDR(MulticastAddrs->Address, + struct dev_mc_list *mclist = dev->mc_list; + while (mclist) { + ETHER_EQ_ADDR(mclist->da_addr, EtherHdr->ether_dhost, EqualAddr); if (EqualAddr) { @@ -1571,32 +1982,26 @@ static bool sxg_mac_filter(struct adapter_t *adapter, struct ether_header *Ether DumbRcvMcastPkts++; adapter->Stats. DumbRcvMcastBytes += length; - adapter->Stats.DumbRcvPkts++; - adapter->Stats.DumbRcvBytes += - length; return (TRUE); } - MulticastAddrs = MulticastAddrs->Next; + mclist = mclist->next; } } } } else if (adapter->MacFilter & MAC_DIRECTED) { - /* Not broadcast or multicast. Must be directed at us or */ - /* the card is in promiscuous mode. Either way, consider it */ - /* ours if MAC_DIRECTED is set */ + /* + * Not broadcast or multicast. Must be directed at us or + * the card is in promiscuous mode. Either way, consider it + * ours if MAC_DIRECTED is set + */ adapter->Stats.DumbRcvUcastPkts++; adapter->Stats.DumbRcvUcastBytes += length; - adapter->Stats.DumbRcvPkts++; - adapter->Stats.DumbRcvBytes += length; return (TRUE); } if (adapter->MacFilter & MAC_PROMISC) { /* Whatever it is, keep it. */ - adapter->Stats.DumbRcvPkts++; - adapter->Stats.DumbRcvBytes += length; return (TRUE); } - adapter->Stats.RcvDiscards++; return (FALSE); } @@ -1627,7 +2032,6 @@ static int sxg_register_interrupt(struct adapter_t *adapter) adapter->intrregistered = 1; adapter->IntRegistered = TRUE; /* Disable RSS with line-based interrupts */ - adapter->MsiEnabled = FALSE; adapter->RssEnabled = FALSE; DBG_ERROR("sxg: %s AllocAdaptRsrcs adapter[%p] dev->irq[%x]\n", __func__, adapter, adapter->netdev->irq); @@ -1663,12 +2067,12 @@ static void sxg_deregister_interrupt(struct adapter_t *adapter) */ static int sxg_if_init(struct adapter_t *adapter) { - p_net_device dev = adapter->netdev; + struct net_device *dev = adapter->netdev; int status = 0; - DBG_ERROR("sxg: %s (%s) ENTER states[%d:%d:%d] flags[%x]\n", + DBG_ERROR("sxg: %s (%s) ENTER states[%d:%d] flags[%x]\n", __func__, adapter->netdev->name, - adapter->queues_initialized, adapter->state, + adapter->state, adapter->linkstate, dev->flags); /* adapter should be down at this point */ @@ -1679,31 +2083,31 @@ static int sxg_if_init(struct adapter_t *adapter) ASSERT(adapter->linkstate == LINK_DOWN); adapter->devflags_prev = dev->flags; - adapter->macopts = MAC_DIRECTED; + adapter->MacFilter = MAC_DIRECTED; if (dev->flags) { DBG_ERROR("sxg: %s (%s) Set MAC options: ", __func__, adapter->netdev->name); if (dev->flags & IFF_BROADCAST) { - adapter->macopts |= MAC_BCAST; + adapter->MacFilter |= MAC_BCAST; DBG_ERROR("BCAST "); } if (dev->flags & IFF_PROMISC) { - adapter->macopts |= MAC_PROMISC; + adapter->MacFilter |= MAC_PROMISC; DBG_ERROR("PROMISC "); } if (dev->flags & IFF_ALLMULTI) { - adapter->macopts |= MAC_ALLMCAST; + adapter->MacFilter |= MAC_ALLMCAST; DBG_ERROR("ALL_MCAST "); } if (dev->flags & IFF_MULTICAST) { - adapter->macopts |= MAC_MCAST; + adapter->MacFilter |= MAC_MCAST; DBG_ERROR("MCAST "); } DBG_ERROR("\n"); } - status = sxg_register_interrupt(adapter); + status = sxg_register_intr(adapter); if (status != STATUS_SUCCESS) { - DBG_ERROR("sxg_if_init: sxg_register_interrupt FAILED %x\n", + DBG_ERROR("sxg_if_init: sxg_register_intr FAILED %x\n", status); sxg_deregister_interrupt(adapter); return (status); @@ -1711,18 +2115,90 @@ static int sxg_if_init(struct adapter_t *adapter) adapter->state = ADAPT_UP; - /* - * clear any pending events, then enable interrupts - */ + /* clear any pending events, then enable interrupts */ DBG_ERROR("sxg: %s ENABLE interrupts(slic)\n", __func__); return (STATUS_SUCCESS); } -static int sxg_entry_open(p_net_device dev) +void sxg_set_interrupt_aggregation(struct adapter_t *adapter) +{ + /* + * Top bit disables aggregation on xmt (SXG_AGG_XMT_DISABLE). + * Make sure Max is less than 0x8000. + */ + adapter->max_aggregation = SXG_MAX_AGG_DEFAULT; + adapter->min_aggregation = SXG_MIN_AGG_DEFAULT; + WRITE_REG(adapter->UcodeRegs[0].Aggregation, + ((adapter->max_aggregation << SXG_MAX_AGG_SHIFT) | + adapter->min_aggregation), + TRUE); +} + +static int sxg_entry_open(struct net_device *dev) { struct adapter_t *adapter = (struct adapter_t *) netdev_priv(dev); int status; + static int turn; + int sxg_initial_rcv_data_buffers = SXG_INITIAL_RCV_DATA_BUFFERS; + int i; + + if (adapter->JumboEnabled == TRUE) { + sxg_initial_rcv_data_buffers = + SXG_INITIAL_JUMBO_RCV_DATA_BUFFERS; + SXG_INITIALIZE_RING(adapter->RcvRingZeroInfo, + SXG_JUMBO_RCV_RING_SIZE); + } + + /* + * Allocate receive data buffers. We allocate a block of buffers and + * a corresponding descriptor block at once. See sxghw.h:SXG_RCV_BLOCK + */ + + for (i = 0; i < sxg_initial_rcv_data_buffers; + i += SXG_RCV_DESCRIPTORS_PER_BLOCK) + { + status = sxg_allocate_buffer_memory(adapter, + SXG_RCV_BLOCK_SIZE(SXG_RCV_DATA_HDR_SIZE), + SXG_BUFFER_TYPE_RCV); + if (status != STATUS_SUCCESS) + return status; + } + /* + * NBL resource allocation can fail in the 'AllocateComplete' routine, + * which doesn't return status. Make sure we got the number of buffers + * we requested + */ + + if (adapter->FreeRcvBufferCount < sxg_initial_rcv_data_buffers) { + SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAResF6", + adapter, adapter->FreeRcvBufferCount, SXG_MAX_ENTRIES, + 0); + return (STATUS_RESOURCES); + } + /* + * The microcode expects it to be downloaded on every open. + */ + DBG_ERROR("sxg: %s ENTER sxg_download_microcode\n", __FUNCTION__); + if (sxg_download_microcode(adapter, SXG_UCODE_SYSTEM)) { + DBG_ERROR("sxg: %s ENTER sxg_adapter_set_hwaddr\n", + __FUNCTION__); + sxg_read_config(adapter); + } else { + adapter->state = ADAPT_FAIL; + adapter->linkstate = LINK_DOWN; + DBG_ERROR("sxg_download_microcode FAILED status[%x]\n", + status); + } + msleep(5); + + if (turn) { + sxg_second_open(adapter->netdev); + + return STATUS_SUCCESS; + } + + turn++; ASSERT(adapter); DBG_ERROR("sxg: %s adapter->activated[%d]\n", __func__, @@ -1762,6 +2238,8 @@ static int sxg_entry_open(p_net_device dev) return (status); } DBG_ERROR("sxg: %s ENABLE ALL INTERRUPTS\n", __func__); + sxg_set_interrupt_aggregation(adapter); + napi_enable(&adapter->napi); /* Enable interrupts */ SXG_ENABLE_ALL_INTERRUPTS(adapter); @@ -1772,71 +2250,162 @@ static int sxg_entry_open(p_net_device dev) return STATUS_SUCCESS; } +int sxg_second_open(struct net_device * dev) +{ + struct adapter_t *adapter = (struct adapter_t*) netdev_priv(dev); + int status = 0; + + spin_lock_irqsave(&sxg_global.driver_lock, sxg_global.flags); + netif_start_queue(adapter->netdev); + adapter->state = ADAPT_UP; + adapter->linkstate = LINK_UP; + + status = sxg_initialize_adapter(adapter); + sxg_set_interrupt_aggregation(adapter); + napi_enable(&adapter->napi); + /* Re-enable interrupts */ + SXG_ENABLE_ALL_INTERRUPTS(adapter); + + sxg_register_intr(adapter); + spin_unlock_irqrestore(&sxg_global.driver_lock, sxg_global.flags); + mod_timer(&adapter->watchdog_timer, jiffies); + return (STATUS_SUCCESS); + +} + static void __devexit sxg_entry_remove(struct pci_dev *pcidev) { - p_net_device dev = pci_get_drvdata(pcidev); - u32 mmio_start = 0; - unsigned int mmio_len = 0; + u32 mmio_start = 0; + u32 mmio_len = 0; + + struct net_device *dev = pci_get_drvdata(pcidev); struct adapter_t *adapter = (struct adapter_t *) netdev_priv(dev); - ASSERT(adapter); - DBG_ERROR("sxg: %s ENTER dev[%p] adapter[%p]\n", __func__, dev, - adapter); - sxg_deregister_interrupt(adapter); - sxg_unmap_mmio_space(adapter); - DBG_ERROR("sxg: %s unregister_netdev\n", __func__); + flush_scheduled_work(); + + /* Deallocate Resources */ unregister_netdev(dev); + sxg_reset_interrupt_capability(adapter); + sxg_free_resources(adapter); - mmio_start = pci_resource_start(pcidev, 0); - mmio_len = pci_resource_len(pcidev, 0); + ASSERT(adapter); - DBG_ERROR("sxg: %s rel_region(0) start[%x] len[%x]\n", __func__, - mmio_start, mmio_len); - release_mem_region(mmio_start, mmio_len); + mmio_start = pci_resource_start(pcidev, 0); + mmio_len = pci_resource_len(pcidev, 0); - DBG_ERROR("sxg: %s iounmap dev->base_addr[%x]\n", __func__, - (unsigned int)dev->base_addr); - iounmap((char *)dev->base_addr); + DBG_ERROR("sxg: %s rel_region(0) start[%x] len[%x]\n", __FUNCTION__, + mmio_start, mmio_len); + release_mem_region(mmio_start, mmio_len); + + mmio_start = pci_resource_start(pcidev, 2); + mmio_len = pci_resource_len(pcidev, 2); + + DBG_ERROR("sxg: %s rel_region(2) start[%x] len[%x]\n", __FUNCTION__, + mmio_start, mmio_len); + release_mem_region(mmio_start, mmio_len); + + pci_disable_device(pcidev); DBG_ERROR("sxg: %s deallocate device\n", __func__); kfree(dev); DBG_ERROR("sxg: %s EXIT\n", __func__); } -static int sxg_entry_halt(p_net_device dev) +static int sxg_entry_halt(struct net_device *dev) { struct adapter_t *adapter = (struct adapter_t *) netdev_priv(dev); + struct sxg_hw_regs *HwRegs = adapter->HwRegs; + int i; + u32 RssIds, IsrCount; + unsigned long flags; + RssIds = SXG_RSS_CPU_COUNT(adapter); + IsrCount = adapter->msi_enabled ? RssIds : 1; + /* Disable interrupts */ spin_lock_irqsave(&sxg_global.driver_lock, sxg_global.flags); - DBG_ERROR("sxg: %s (%s) ENTER\n", __func__, dev->name); - - netif_stop_queue(adapter->netdev); + SXG_DISABLE_ALL_INTERRUPTS(adapter); adapter->state = ADAPT_DOWN; adapter->linkstate = LINK_DOWN; + + spin_unlock_irqrestore(&sxg_global.driver_lock, sxg_global.flags); + sxg_deregister_interrupt(adapter); + WRITE_REG(HwRegs->Reset, 0xDEAD, FLUSH); + mdelay(5000); + + del_timer_sync(&adapter->watchdog_timer); + netif_stop_queue(dev); + netif_carrier_off(dev); + + napi_disable(&adapter->napi); + + WRITE_REG(adapter->UcodeRegs[0].RcvCmd, 0, true); adapter->devflags_prev = 0; DBG_ERROR("sxg: %s (%s) set adapter[%p] state to ADAPT_DOWN(%d)\n", __func__, dev->name, adapter, adapter->state); - DBG_ERROR("sxg: %s (%s) EXIT\n", __func__, dev->name); - DBG_ERROR("sxg: %s EXIT\n", __func__); - spin_unlock_irqrestore(&sxg_global.driver_lock, sxg_global.flags); + spin_lock(&adapter->RcvQLock); + /* Free all the blocks and the buffers, moved from remove() routine */ + if (!(IsListEmpty(&adapter->AllRcvBlocks))) { + sxg_free_rcvblocks(adapter); + } + + + InitializeListHead(&adapter->FreeRcvBuffers); + InitializeListHead(&adapter->FreeRcvBlocks); + InitializeListHead(&adapter->AllRcvBlocks); + InitializeListHead(&adapter->FreeSglBuffers); + InitializeListHead(&adapter->AllSglBuffers); + + adapter->FreeRcvBufferCount = 0; + adapter->FreeRcvBlockCount = 0; + adapter->AllRcvBlockCount = 0; + adapter->RcvBuffersOnCard = 0; + adapter->PendingRcvCount = 0; + + memset(adapter->RcvRings, 0, sizeof(struct sxg_rcv_ring) * 1); + memset(adapter->EventRings, 0, sizeof(struct sxg_event_ring) * RssIds); + memset(adapter->Isr, 0, sizeof(u32) * IsrCount); + for (i = 0; i < SXG_MAX_RING_SIZE; i++) + adapter->RcvRingZeroInfo.Context[i] = NULL; + SXG_INITIALIZE_RING(adapter->RcvRingZeroInfo, SXG_RCV_RING_SIZE); + SXG_INITIALIZE_RING(adapter->XmtRingZeroInfo, SXG_XMT_RING_SIZE); + + spin_unlock(&adapter->RcvQLock); + + spin_lock_irqsave(&adapter->XmtZeroLock, flags); + adapter->AllSglBufferCount = 0; + adapter->FreeSglBufferCount = 0; + adapter->PendingXmtCount = 0; + memset(adapter->XmtRings, 0, sizeof(struct sxg_xmt_ring) * 1); + memset(adapter->XmtRingZeroIndex, 0, sizeof(u32)); + spin_unlock_irqrestore(&adapter->XmtZeroLock, flags); + + for (i = 0; i < SXG_MAX_RSS; i++) { + adapter->NextEvent[i] = 0; + } + atomic_set(&adapter->pending_allocations, 0); + adapter->intrregistered = 0; + sxg_remove_isr(adapter); + DBG_ERROR("sxg: %s (%s) EXIT\n", __FUNCTION__, dev->name); return (STATUS_SUCCESS); } -static int sxg_ioctl(p_net_device dev, struct ifreq *rq, int cmd) +static int sxg_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { ASSERT(rq); -/* DBG_ERROR("sxg: %s cmd[%x] rq[%p] dev[%p]\n", __func__, cmd, rq, dev); */ +/* DBG_ERROR("sxg: %s cmd[%x] rq[%p] dev[%p]\n", __func__, cmd, rq, dev);*/ switch (cmd) { case SIOCSLICSETINTAGG: { -/* struct adapter_t *adapter = (struct adapter_t *) netdev_priv(dev); */ + /* struct adapter_t *adapter = (struct adapter_t *) + * netdev_priv(dev); + */ u32 data[7]; u32 intagg; if (copy_from_user(data, rq->ifr_data, 28)) { - DBG_ERROR - ("copy_from_user FAILED getting initial params\n"); + DBG_ERROR("copy_from_user FAILED getting \ + initial params\n"); return -EFAULT; } intagg = data[0]; @@ -1847,7 +2416,7 @@ static int sxg_ioctl(p_net_device dev, struct ifreq *rq, int cmd) } default: -/* DBG_ERROR("sxg: %s UNSUPPORTED[%x]\n", __func__, cmd); */ + /* DBG_ERROR("sxg: %s UNSUPPORTED[%x]\n", __func__, cmd); */ return -EOPNOTSUPP; } return 0; @@ -1856,23 +2425,25 @@ static int sxg_ioctl(p_net_device dev, struct ifreq *rq, int cmd) #define NORMAL_ETHFRAME 0 /* - * * sxg_send_packets - Send a skb packet * * Arguments: - * skb - The packet to send - * dev - Our linux net device that refs our adapter + * skb - The packet to send + * dev - Our linux net device that refs our adapter * * Return: * 0 regardless of outcome XXXTODO refer to e1000 driver */ -static int sxg_send_packets(struct sk_buff *skb, p_net_device dev) +static int sxg_send_packets(struct sk_buff *skb, struct net_device *dev) { struct adapter_t *adapter = (struct adapter_t *) netdev_priv(dev); u32 status = STATUS_SUCCESS; - DBG_ERROR("sxg: %s ENTER sxg_send_packets skb[%p]\n", __func__, - skb); + /* + * DBG_ERROR("sxg: %s ENTER sxg_send_packets skb[%p]\n", __FUNCTION__, + * skb); + */ + /* Check the adapter state */ switch (adapter->State) { case SXG_STATE_INITIALIZING: @@ -1909,17 +2480,18 @@ static int sxg_send_packets(struct sk_buff *skb, p_net_device dev) /* reject & complete all the packets if they cant be sent */ if (status != STATUS_SUCCESS) { #if XXXTODO -/* sxg_send_packets_fail(adapter, skb, status); */ + /* sxg_send_packets_fail(adapter, skb, status); */ #else SXG_DROP_DUMB_SEND(adapter, skb); adapter->stats.tx_dropped++; + return NETDEV_TX_BUSY; #endif } DBG_ERROR("sxg: %s EXIT sxg_send_packets status[%x]\n", __func__, status); xmit_done: - return 0; + return NETDEV_TX_OK; } /* @@ -1931,33 +2503,35 @@ static int sxg_send_packets(struct sk_buff *skb, p_net_device dev) * adapter - Pointer to our adapter structure * skb - The packet to be sent * - * Return - - * STATUS of send + * Return - STATUS of send */ static int sxg_transmit_packet(struct adapter_t *adapter, struct sk_buff *skb) { - struct SCATTER_GATHER_LIST *pSgl; - struct SXG_SCATTER_GATHER *SxgSgl; - void *SglBuffer; - u32 SglBufferLength; + struct sxg_x64_sgl *pSgl; + struct sxg_scatter_gather *SxgSgl; + unsigned long sgl_flags; + /* void *SglBuffer; */ + /* u32 SglBufferLength; */ - /* The vast majority of work is done in the shared */ - /* sxg_dumb_sgl routine. */ + /* + * The vast majority of work is done in the shared + * sxg_dumb_sgl routine. + */ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbSend", adapter, skb, 0, 0); /* Allocate a SGL buffer */ - SXG_GET_SGL_BUFFER(adapter, SxgSgl); + SXG_GET_SGL_BUFFER(adapter, SxgSgl, 0); if (!SxgSgl) { adapter->Stats.NoSglBuf++; - adapter->Stats.XmtErrors++; + adapter->stats.tx_errors++; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "SndPktF1", adapter, skb, 0, 0); return (STATUS_RESOURCES); } ASSERT(SxgSgl->adapter == adapter); - SglBuffer = SXG_SGL_BUFFER(SxgSgl); - SglBufferLength = SXG_SGL_BUF_SIZE; + /*SglBuffer = SXG_SGL_BUFFER(SxgSgl); + SglBufferLength = SXG_SGL_BUF_SIZE; */ SxgSgl->VlanTag.VlanTci = 0; SxgSgl->VlanTag.VlanTpid = 0; SxgSgl->Type = SXG_SGL_DUMB; @@ -1965,9 +2539,7 @@ static int sxg_transmit_packet(struct adapter_t *adapter, struct sk_buff *skb) pSgl = NULL; /* Call the common sxg_dumb_sgl routine to complete the send. */ - sxg_dumb_sgl(pSgl, SxgSgl); - /* Return success sxg_dumb_sgl (or something later) will complete it. */ - return (STATUS_SUCCESS); + return (sxg_dumb_sgl(pSgl, SxgSgl)); } /* @@ -1975,24 +2547,27 @@ static int sxg_transmit_packet(struct adapter_t *adapter, struct sk_buff *skb) * * Arguments: * pSgl - - * SxgSgl - SXG_SCATTER_GATHER + * SxgSgl - struct sxg_scatter_gather * * Return Value: - * None. + * Status of send operation. */ -static void sxg_dumb_sgl(struct SCATTER_GATHER_LIST *pSgl, struct SXG_SCATTER_GATHER *SxgSgl) +static int sxg_dumb_sgl(struct sxg_x64_sgl *pSgl, + struct sxg_scatter_gather *SxgSgl) { struct adapter_t *adapter = SxgSgl->adapter; struct sk_buff *skb = SxgSgl->DumbPacket; /* For now, all dumb-nic sends go on RSS queue zero */ - struct SXG_XMT_RING *XmtRing = &adapter->XmtRings[0]; - struct SXG_RING_INFO *XmtRingInfo = &adapter->XmtRingZeroInfo; - struct SXG_CMD *XmtCmd = NULL; -/* u32 Index = 0; */ + struct sxg_xmt_ring *XmtRing = &adapter->XmtRings[0]; + struct sxg_ring_info *XmtRingInfo = &adapter->XmtRingZeroInfo; + struct sxg_cmd *XmtCmd = NULL; + /* u32 Index = 0; */ u32 DataLength = skb->len; -/* unsigned int BufLen; */ -/* u32 SglOffset; */ + /* unsigned int BufLen; */ + /* u32 SglOffset; */ u64 phys_addr; + unsigned long flags; + unsigned long queue_id=0; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbSgl", pSgl, SxgSgl, 0, 0); @@ -2001,25 +2576,67 @@ static void sxg_dumb_sgl(struct SCATTER_GATHER_LIST *pSgl, struct SXG_SCATTER_GA SxgSgl->pSgl = pSgl; /* Sanity check that our SGL format is as we expect. */ - ASSERT(sizeof(SXG_X64_SGE) == sizeof(SCATTER_GATHER_ELEMENT)); + ASSERT(sizeof(struct sxg_x64_sge) == sizeof(struct sxg_x64_sge)); /* Shouldn't be a vlan tag on this frame */ ASSERT(SxgSgl->VlanTag.VlanTci == 0); ASSERT(SxgSgl->VlanTag.VlanTpid == 0); - /* From here below we work with the SGL placed in our */ - /* buffer. */ + /* + * From here below we work with the SGL placed in our + * buffer. + */ SxgSgl->Sgl.NumberOfElements = 1; + /* + * Set ucode Queue ID based on bottom bits of destination TCP port. + * This Queue ID splits slowpath/dumb-nic packet processing across + * multiple threads on the card to improve performance. It is split + * using the TCP port to avoid out-of-order packets that can result + * from multithreaded processing. We use the destination port because + * we expect to be run on a server, so in nearly all cases the local + * port is likely to be constant (well-known server port) and the + * remote port is likely to be random. The exception to this is iSCSI, + * in which case we use the sport instead. Note + * that original attempt at XOR'ing source and dest port resulted in + * poor balance on NTTTCP/iometer applications since they tend to + * line up (even-even, odd-odd..). + */ + + if (skb->protocol == htons(ETH_P_IP)) { + struct iphdr *ip; + + ip = ip_hdr(skb); + if ((ip->protocol == IPPROTO_TCP)&&(DataLength >= sizeof( + struct tcphdr))){ + queue_id = ((ntohs(tcp_hdr(skb)->dest) == ISCSI_PORT) ? + (ntohs (tcp_hdr(skb)->source) & + SXG_LARGE_SEND_QUEUE_MASK): + (ntohs(tcp_hdr(skb)->dest) & + SXG_LARGE_SEND_QUEUE_MASK)); + } + } else if (skb->protocol == htons(ETH_P_IPV6)) { + if ((ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) && (DataLength >= + sizeof(struct tcphdr)) ) { + queue_id = ((ntohs(tcp_hdr(skb)->dest) == ISCSI_PORT) ? + (ntohs (tcp_hdr(skb)->source) & + SXG_LARGE_SEND_QUEUE_MASK): + (ntohs(tcp_hdr(skb)->dest) & + SXG_LARGE_SEND_QUEUE_MASK)); + } + } /* Grab the spinlock and acquire a command */ - spin_lock(&adapter->XmtZeroLock); + spin_lock_irqsave(&adapter->XmtZeroLock, flags); SXG_GET_CMD(XmtRing, XmtRingInfo, XmtCmd, SxgSgl); if (XmtCmd == NULL) { - /* Call sxg_complete_slow_send to see if we can */ - /* free up any XmtRingZero entries and then try again */ - spin_unlock(&adapter->XmtZeroLock); + /* + * Call sxg_complete_slow_send to see if we can + * free up any XmtRingZero entries and then try again + */ + + spin_unlock_irqrestore(&adapter->XmtZeroLock, flags); sxg_complete_slow_send(adapter); - spin_lock(&adapter->XmtZeroLock); + spin_lock_irqsave(&adapter->XmtZeroLock, flags); SXG_GET_CMD(XmtRing, XmtRingInfo, XmtCmd, SxgSgl); if (XmtCmd == NULL) { adapter->Stats.XmtZeroFull++; @@ -2029,8 +2646,8 @@ static void sxg_dumb_sgl(struct SCATTER_GATHER_LIST *pSgl, struct SXG_SCATTER_GA SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DumbCmd", XmtCmd, XmtRingInfo->Head, XmtRingInfo->Tail, 0); /* Update stats */ - adapter->Stats.DumbXmtPkts++; - adapter->Stats.DumbXmtBytes += DataLength; + adapter->stats.tx_packets++; + adapter->stats.tx_bytes += DataLength; #if XXXTODO /* Stats stuff */ if (SXG_MULTICAST_PACKET(EtherHdr)) { if (SXG_BROADCAST_PACKET(EtherHdr)) { @@ -2045,70 +2662,92 @@ static void sxg_dumb_sgl(struct SCATTER_GATHER_LIST *pSgl, struct SXG_SCATTER_GA adapter->Stats.DumbXmtUcastBytes += DataLength; } #endif - /* Fill in the command */ - /* Copy out the first SGE to the command and adjust for offset */ - phys_addr = - pci_map_single(adapter->pcidev, skb->data, skb->len, + /* + * Fill in the command + * Copy out the first SGE to the command and adjust for offset + */ + phys_addr = pci_map_single(adapter->pcidev, skb->data, skb->len, PCI_DMA_TODEVICE); - XmtCmd->Buffer.FirstSgeAddress = SXG_GET_ADDR_HIGH(phys_addr); - XmtCmd->Buffer.FirstSgeAddress = XmtCmd->Buffer.FirstSgeAddress << 32; - XmtCmd->Buffer.FirstSgeAddress = - XmtCmd->Buffer.FirstSgeAddress | SXG_GET_ADDR_LOW(phys_addr); -/* XmtCmd->Buffer.FirstSgeAddress = SxgSgl->Sgl.Elements[Index].Address; */ -/* XmtCmd->Buffer.FirstSgeAddress.LowPart += MdlOffset; */ + + /* + * SAHARA SGL WORKAROUND + * See if the SGL straddles a 64k boundary. If so, skip to + * the start of the next 64k boundary and continue + */ + + if ((adapter->asictype == SAHARA_REV_A) && + (SXG_INVALID_SGL(phys_addr,skb->data_len))) + { + spin_unlock_irqrestore(&adapter->XmtZeroLock, flags); + /* Silently drop this packet */ + printk(KERN_EMERG"Dropped a packet for 64k boundary problem\n"); + return STATUS_SUCCESS; + } + memset(XmtCmd, '\0', sizeof(*XmtCmd)); + XmtCmd->Buffer.FirstSgeAddress = phys_addr; XmtCmd->Buffer.FirstSgeLength = DataLength; - /* Set a pointer to the remaining SGL entries */ -/* XmtCmd->Sgl = SxgSgl->PhysicalAddress; */ - /* Advance the physical address of the SxgSgl structure to */ - /* the second SGE */ -/* SglOffset = (u32)((u32 *)(&SxgSgl->Sgl.Elements[Index+1]) - */ -/* (u32 *)SxgSgl); */ -/* XmtCmd->Sgl.LowPart += SglOffset; */ XmtCmd->Buffer.SgeOffset = 0; - /* Note - TotalLength might be overwritten with MSS below.. */ XmtCmd->Buffer.TotalLength = DataLength; - XmtCmd->SgEntries = 1; /*(ushort)(SxgSgl->Sgl.NumberOfElements - Index); */ + XmtCmd->SgEntries = 1; XmtCmd->Flags = 0; - /* */ - /* Advance transmit cmd descripter by 1. */ - /* NOTE - See comments in SxgTcpOutput where we write */ - /* to the XmtCmd register regarding CPU ID values and/or */ - /* multiple commands. */ - /* */ - /* */ - WRITE_REG(adapter->UcodeRegs[0].XmtCmd, 1, TRUE); - /* */ - /* */ + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + /* + * We need to set the Checkum in IP header to 0. This is + * required by hardware. + */ + ip_hdr(skb)->check = 0x0; + XmtCmd->CsumFlags.Flags |= SXG_SLOWCMD_CSUM_IP; + XmtCmd->CsumFlags.Flags |= SXG_SLOWCMD_CSUM_TCP; + /* Dont know if length will require a change in case of VLAN */ + XmtCmd->CsumFlags.MacLen = ETH_HLEN; + XmtCmd->CsumFlags.IpHl = skb_network_header_len(skb) >> + SXG_NW_HDR_LEN_SHIFT; + } + /* + * Advance transmit cmd descripter by 1. + * NOTE - See comments in SxgTcpOutput where we write + * to the XmtCmd register regarding CPU ID values and/or + * multiple commands. + * Top 16 bits specify queue_id. See comments about queue_id above + */ + /* Four queues at the moment */ + ASSERT((queue_id & ~SXG_LARGE_SEND_QUEUE_MASK) == 0); + WRITE_REG(adapter->UcodeRegs[0].XmtCmd, ((queue_id << 16) | 1), TRUE); adapter->Stats.XmtQLen++; /* Stats within lock */ - spin_unlock(&adapter->XmtZeroLock); + spin_unlock_irqrestore(&adapter->XmtZeroLock, flags); SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XDumSgl2", XmtCmd, pSgl, SxgSgl, 0); - return; + return STATUS_SUCCESS; abortcmd: - /* NOTE - Only jump to this label AFTER grabbing the */ - /* XmtZeroLock, and DO NOT DROP IT between the */ - /* command allocation and the following abort. */ + /* + * NOTE - Only jump to this label AFTER grabbing the + * XmtZeroLock, and DO NOT DROP IT between the + * command allocation and the following abort. + */ if (XmtCmd) { SXG_ABORT_CMD(XmtRingInfo); } - spin_unlock(&adapter->XmtZeroLock); + spin_unlock_irqrestore(&adapter->XmtZeroLock, flags); -/* failsgl: */ - /* Jump to this label if failure occurs before the */ - /* XmtZeroLock is grabbed */ - adapter->Stats.XmtErrors++; +/* + * failsgl: + * Jump to this label if failure occurs before the + * XmtZeroLock is grabbed + */ + adapter->stats.tx_errors++; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "DumSGFal", pSgl, SxgSgl, XmtRingInfo->Head, XmtRingInfo->Tail); + /* SxgSgl->DumbPacket is the skb */ + // SXG_COMPLETE_DUMB_SEND(adapter, SxgSgl->DumbPacket); - SXG_COMPLETE_DUMB_SEND(adapter, SxgSgl->DumbPacket); /* SxgSgl->DumbPacket is the skb */ + return STATUS_FAILURE; } -/*************************************************************** - * Link management functions - ***************************************************************/ - /* + * Link management functions + * * sxg_initialize_link - Initialize the link stuff * * Arguments - @@ -2119,10 +2758,11 @@ static void sxg_dumb_sgl(struct SCATTER_GATHER_LIST *pSgl, struct SXG_SCATTER_GA */ static int sxg_initialize_link(struct adapter_t *adapter) { - struct SXG_HW_REGS *HwRegs = adapter->HwRegs; + struct sxg_hw_regs *HwRegs = adapter->HwRegs; u32 Value; u32 ConfigData; u32 MaxFrame; + u32 AxgMacReg1; int status; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "InitLink", @@ -2140,15 +2780,17 @@ static int sxg_initialize_link(struct adapter_t *adapter) /* Reset all MAC modules */ WRITE_REG(HwRegs->MacConfig0, AXGMAC_CFG0_SUB_RESET, TRUE); - /* Link address 0 */ - /* XXXTODO - This assumes the MAC address (0a:0b:0c:0d:0e:0f) */ - /* is stored with the first nibble (0a) in the byte 0 */ - /* of the Mac address. Possibly reverse? */ - Value = *(u32 *) adapter->MacAddr; + /* + * Link address 0 + * XXXTODO - This assumes the MAC address (0a:0b:0c:0d:0e:0f) + * is stored with the first nibble (0a) in the byte 0 + * of the Mac address. Possibly reverse? + */ + Value = *(u32 *) adapter->macaddr; WRITE_REG(HwRegs->LinkAddress0Low, Value, TRUE); /* also write the MAC address to the MAC. Endian is reversed. */ WRITE_REG(HwRegs->MacAddressLow, ntohl(Value), TRUE); - Value = (*(u16 *) & adapter->MacAddr[4] & 0x0000FFFF); + Value = (*(u16 *) & adapter->macaddr[4] & 0x0000FFFF); WRITE_REG(HwRegs->LinkAddress0High, Value | LINK_ADDRESS_ENABLE, TRUE); /* endian swap for the MAC (put high bytes in bits [31:16], swapped) */ Value = ntohl(Value); @@ -2167,47 +2809,76 @@ static int sxg_initialize_link(struct adapter_t *adapter) WRITE_REG(HwRegs->MacConfig0, 0, TRUE); /* Configure MAC */ - WRITE_REG(HwRegs->MacConfig1, (AXGMAC_CFG1_XMT_PAUSE | /* Allow sending of pause */ - AXGMAC_CFG1_XMT_EN | /* Enable XMT */ - AXGMAC_CFG1_RCV_PAUSE | /* Enable detection of pause */ - AXGMAC_CFG1_RCV_EN | /* Enable receive */ - AXGMAC_CFG1_SHORT_ASSERT | /* short frame detection */ - AXGMAC_CFG1_CHECK_LEN | /* Verify frame length */ - AXGMAC_CFG1_GEN_FCS | /* Generate FCS */ - AXGMAC_CFG1_PAD_64), /* Pad frames to 64 bytes */ - TRUE); + AxgMacReg1 = ( /* Enable XMT */ + AXGMAC_CFG1_XMT_EN | + /* Enable receive */ + AXGMAC_CFG1_RCV_EN | + /* short frame detection */ + AXGMAC_CFG1_SHORT_ASSERT | + /* Verify frame length */ + AXGMAC_CFG1_CHECK_LEN | + /* Generate FCS */ + AXGMAC_CFG1_GEN_FCS | + /* Pad frames to 64 bytes */ + AXGMAC_CFG1_PAD_64); + + if (adapter->XmtFcEnabled) { + AxgMacReg1 |= AXGMAC_CFG1_XMT_PAUSE; /* Allow sending of pause */ + } + if (adapter->RcvFcEnabled) { + AxgMacReg1 |= AXGMAC_CFG1_RCV_PAUSE; /* Enable detection of pause */ + } + + WRITE_REG(HwRegs->MacConfig1, AxgMacReg1, TRUE); /* Set AXGMAC max frame length if jumbo. Not needed for standard MTU */ if (adapter->JumboEnabled) { WRITE_REG(HwRegs->MacMaxFrameLen, AXGMAC_MAXFRAME_JUMBO, TRUE); } - /* AMIIM Configuration Register - */ - /* The value placed in the AXGMAC_AMIIM_CFG_HALF_CLOCK portion */ - /* (bottom bits) of this register is used to determine the */ - /* MDC frequency as specified in the A-XGMAC Design Document. */ - /* This value must not be zero. The following value (62 or 0x3E) */ - /* is based on our MAC transmit clock frequency (MTCLK) of 312.5 MHz. */ - /* Given a maximum MDIO clock frequency of 2.5 MHz (see the PHY spec), */ - /* we get: 312.5/(2*(X+1)) < 2.5 ==> X = 62. */ - /* This value happens to be the default value for this register, */ - /* so we really don't have to do this. */ - WRITE_REG(HwRegs->MacAmiimConfig, 0x0000003E, TRUE); + /* + * AMIIM Configuration Register - + * The value placed in the AXGMAC_AMIIM_CFG_HALF_CLOCK portion + * (bottom bits) of this register is used to determine the MDC frequency + * as specified in the A-XGMAC Design Document. This value must not be + * zero. The following value (62 or 0x3E) is based on our MAC transmit + * clock frequency (MTCLK) of 312.5 MHz. Given a maximum MDIO clock + * frequency of 2.5 MHz (see the PHY spec), we get: + * 312.5/(2*(X+1)) < 2.5 ==> X = 62. + * This value happens to be the default value for this register, so we + * really don't have to do this. + */ + if (adapter->asictype == SAHARA_REV_B) { + WRITE_REG(HwRegs->MacAmiimConfig, 0x0000001F, TRUE); + } else { + WRITE_REG(HwRegs->MacAmiimConfig, 0x0000003E, TRUE); + } /* Power up and enable PHY and XAUI/XGXS/Serdes logic */ WRITE_REG(HwRegs->LinkStatus, - (LS_PHY_CLR_RESET | - LS_XGXS_ENABLE | - LS_XGXS_CTL | LS_PHY_CLK_EN | LS_ATTN_ALARM), TRUE); + (LS_PHY_CLR_RESET | + LS_XGXS_ENABLE | + LS_XGXS_CTL | + LS_PHY_CLK_EN | + LS_ATTN_ALARM), + TRUE); DBG_ERROR("After Power Up and enable PHY in sxg_initialize_link\n"); - /* Per information given by Aeluros, wait 100 ms after removing reset. */ - /* It's not enough to wait for the self-clearing reset bit in reg 0 to clear. */ + /* + * Per information given by Aeluros, wait 100 ms after removing reset. + * It's not enough to wait for the self-clearing reset bit in reg 0 to + * clear. + */ mdelay(100); - /* Verify the PHY has come up by checking that the Reset bit has cleared. */ - status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */ - PHY_PMA_CONTROL1, /* PMA/PMD control register */ - &Value); + /* Verify the PHY has come up by checking that the Reset bit has + * cleared. + */ + status = sxg_read_mdio_reg(adapter, + MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */ + PHY_PMA_CONTROL1, /* PMA/PMD control register */ + &Value); + DBG_ERROR("After sxg_read_mdio_reg Value[%x] fail=%x\n", Value, + (Value & PMA_CONTROL1_RESET)); if (status != STATUS_SUCCESS) return (STATUS_FAILURE); if (Value & PMA_CONTROL1_RESET) /* reset complete if bit is 0 */ @@ -2228,16 +2899,26 @@ static int sxg_initialize_link(struct adapter_t *adapter) return (STATUS_FAILURE); /* Enable the Link Alarm */ - status = sxg_write_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */ - LASI_CONTROL, /* LASI control register */ - LASI_CTL_LS_ALARM_ENABLE); /* enable link alarm bit */ + + /* MIIM_DEV_PHY_PMA - PHY PMA/PMD module + * LASI_CONTROL - LASI control register + * LASI_CTL_LS_ALARM_ENABLE - enable link alarm bit + */ + status = sxg_write_mdio_reg(adapter, MIIM_DEV_PHY_PMA, + LASI_CONTROL, + LASI_CTL_LS_ALARM_ENABLE); if (status != STATUS_SUCCESS) return (STATUS_FAILURE); /* XXXTODO - temporary - verify bit is set */ - status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */ - LASI_CONTROL, /* LASI control register */ + + /* MIIM_DEV_PHY_PMA - PHY PMA/PMD module + * LASI_CONTROL - LASI control register + */ + status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, + LASI_CONTROL, &Value); + if (status != STATUS_SUCCESS) return (STATUS_FAILURE); if (!(Value & LASI_CTL_LS_ALARM_ENABLE)) { @@ -2253,6 +2934,11 @@ static int sxg_initialize_link(struct adapter_t *adapter) RCV_CONFIG_TZIPV4 | RCV_CONFIG_HASH_16 | RCV_CONFIG_SOCKET | RCV_CONFIG_BUFSIZE(MaxFrame)); + + if (adapter->asictype == SAHARA_REV_B) { + ConfigData |= (RCV_CONFIG_HIPRICTL | + RCV_CONFIG_NEWSTATUSFMT); + } WRITE_REG(HwRegs->RcvConfig, ConfigData, TRUE); WRITE_REG(HwRegs->XmtConfig, XMT_CONFIG_ENABLE, TRUE); @@ -2277,21 +2963,25 @@ static int sxg_initialize_link(struct adapter_t *adapter) static int sxg_phy_init(struct adapter_t *adapter) { u32 Value; - struct PHY_UCODE *p; + struct phy_ucode *p; int status; DBG_ERROR("ENTER %s\n", __func__); - /* Read a register to identify the PHY type */ - status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */ - 0xC205, /* PHY ID register (?) */ - &Value); /* XXXTODO - add def */ + /* MIIM_DEV_PHY_PMA - PHY PMA/PMD module + * 0xC205 - PHY ID register (?) + * &Value - XXXTODO - add def + */ + status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, + 0xC205, + &Value); if (status != STATUS_SUCCESS) return (STATUS_FAILURE); - if (Value == 0x0012) { /* 0x0012 == AEL2005C PHY(?) - XXXTODO - add def */ - DBG_ERROR - ("AEL2005C PHY detected. Downloading PHY microcode.\n"); + if (Value == 0x0012) { + /* 0x0012 == AEL2005C PHY(?) - XXXTODO - add def */ + DBG_ERROR("AEL2005C PHY detected. Downloading PHY \ + microcode.\n"); /* Initialize AEL2005C PHY and download PHY microcode */ for (p = PhyUcode; p->Addr != 0xFFFF; p++) { @@ -2299,10 +2989,13 @@ static int sxg_phy_init(struct adapter_t *adapter) /* if address == 0, data == sleep time in ms */ mdelay(p->Data); } else { - /* write the given data to the specified address */ - status = sxg_write_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */ - p->Addr, /* PHY address */ - p->Data); /* PHY data */ + /* write the given data to the specified address */ + status = sxg_write_mdio_reg(adapter, + MIIM_DEV_PHY_PMA, + /* PHY address */ + p->Addr, + /* PHY data */ + p->Data); if (status != STATUS_SUCCESS) return (STATUS_FAILURE); } @@ -2324,11 +3017,14 @@ static int sxg_phy_init(struct adapter_t *adapter) */ static void sxg_link_event(struct adapter_t *adapter) { - struct SXG_HW_REGS *HwRegs = adapter->HwRegs; + struct sxg_hw_regs *HwRegs = adapter->HwRegs; + struct net_device *netdev = adapter->netdev; enum SXG_LINK_STATE LinkState; int status; u32 Value; + if (adapter->state == ADAPT_DOWN) + return; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "LinkEvnt", adapter, 0, 0, 0); DBG_ERROR("ENTER %s\n", __func__); @@ -2336,35 +3032,57 @@ static void sxg_link_event(struct adapter_t *adapter) /* Check the Link Status register. We should have a Link Alarm. */ READ_REG(HwRegs->LinkStatus, Value); if (Value & LS_LINK_ALARM) { - /* We got a Link Status alarm. First, pause to let the */ - /* link state settle (it can bounce a number of times) */ + /* + * We got a Link Status alarm. First, pause to let the + * link state settle (it can bounce a number of times) + */ mdelay(10); /* Now clear the alarm by reading the LASI status register. */ - status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */ - LASI_STATUS, /* LASI status register */ + /* MIIM_DEV_PHY_PMA - PHY PMA/PMD module */ + status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, + /* LASI status register */ + LASI_STATUS, &Value); if (status != STATUS_SUCCESS) { DBG_ERROR("Error reading LASI Status MDIO register!\n"); sxg_link_state(adapter, SXG_LINK_DOWN); -/* ASSERT(0); */ + /* ASSERT(0); */ } - ASSERT(Value & LASI_STATUS_LS_ALARM); + /* + * We used to assert that the LASI_LS_ALARM bit was set, as + * it should be. But there appears to be cases during + * initialization (when the PHY is reset and re-initialized) + * when we get a link alarm, but the status bit is 0 when we + * read it. Rather than trying to assure this never happens + * (and nver being certain), just ignore it. + + * ASSERT(Value & LASI_STATUS_LS_ALARM); + */ /* Now get and set the link state */ LinkState = sxg_get_link_state(adapter); sxg_link_state(adapter, LinkState); DBG_ERROR("SXG: Link Alarm occurred. Link is %s\n", ((LinkState == SXG_LINK_UP) ? "UP" : "DOWN")); + if (LinkState == SXG_LINK_UP) { + netif_carrier_on(netdev); + netif_tx_start_all_queues(netdev); + } else { + netif_tx_stop_all_queues(netdev); + netif_carrier_off(netdev); + } } else { - /* XXXTODO - Assuming Link Attention is only being generated for the */ - /* Link Alarm pin (and not for a XAUI Link Status change), then it's */ - /* impossible to get here. Yet we've gotten here twice (under extreme */ - /* conditions - bouncing the link up and down many times a second). */ - /* Needs further investigation. */ + /* + * XXXTODO - Assuming Link Attention is only being generated + * for the Link Alarm pin (and not for a XAUI Link Status change) + * , then it's impossible to get here. Yet we've gotten here + * twice (under extreme conditions - bouncing the link up and + * down many times a second). Needs further investigation. + */ DBG_ERROR("SXG: sxg_link_event: Can't get here!\n"); DBG_ERROR("SXG: Link Status == 0x%08X.\n", Value); -/* ASSERT(0); */ + /* ASSERT(0); */ } DBG_ERROR("EXIT %s\n", __func__); @@ -2389,10 +3107,15 @@ static enum SXG_LINK_STATE sxg_get_link_state(struct adapter_t *adapter) SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "GetLink", adapter, 0, 0, 0); - /* Per the Xenpak spec (and the IEEE 10Gb spec?), the link is up if */ - /* the following 3 bits (from 3 different MDIO registers) are all true. */ - status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, /* PHY PMA/PMD module */ - PHY_PMA_RCV_DET, /* PMA/PMD Receive Signal Detect register */ + /* + * Per the Xenpak spec (and the IEEE 10Gb spec?), the link is up if + * the following 3 bits (from 3 different MDIO registers) are all true. + */ + + /* MIIM_DEV_PHY_PMA - PHY PMA/PMD module */ + status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PMA, + /* PMA/PMD Receive Signal Detect register */ + PHY_PMA_RCV_DET, &Value); if (status != STATUS_SUCCESS) goto bad; @@ -2401,8 +3124,10 @@ static enum SXG_LINK_STATE sxg_get_link_state(struct adapter_t *adapter) if (!(Value & PMA_RCV_DETECT)) return (SXG_LINK_DOWN); - status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PCS, /* PHY PCS module */ - PHY_PCS_10G_STATUS1, /* PCS 10GBASE-R Status 1 register */ + /* MIIM_DEV_PHY_PCS - PHY PCS module */ + status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_PCS, + /* PCS 10GBASE-R Status 1 register */ + PHY_PCS_10G_STATUS1, &Value); if (status != STATUS_SUCCESS) goto bad; @@ -2411,8 +3136,9 @@ static enum SXG_LINK_STATE sxg_get_link_state(struct adapter_t *adapter) if (!(Value & PCS_10B_BLOCK_LOCK)) return (SXG_LINK_DOWN); - status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_XS, /* PHY XS module */ - PHY_XS_LANE_STATUS, /* XS Lane Status register */ + status = sxg_read_mdio_reg(adapter, MIIM_DEV_PHY_XS,/* PHY XS module */ + /* XS Lane Status register */ + PHY_XS_LANE_STATUS, &Value); if (status != STATUS_SUCCESS) goto bad; @@ -2427,7 +3153,7 @@ static enum SXG_LINK_STATE sxg_get_link_state(struct adapter_t *adapter) return (SXG_LINK_UP); bad: - /* An error occurred reading an MDIO register. This shouldn't happen. */ + /* An error occurred reading an MDIO register. This shouldn't happen. */ DBG_ERROR("Error reading an MDIO register!\n"); ASSERT(0); return (SXG_LINK_DOWN); @@ -2448,6 +3174,37 @@ static void sxg_indicate_link_state(struct adapter_t *adapter, } /* + * sxg_change_mtu - Change the Maximum Transfer Unit + * * @returns 0 on success, negative on failure + */ +int sxg_change_mtu (struct net_device *netdev, int new_mtu) +{ + struct adapter_t *adapter = (struct adapter_t *) netdev_priv(netdev); + + if (!((new_mtu == SXG_DEFAULT_MTU) || (new_mtu == SXG_JUMBO_MTU))) + return -EINVAL; + + if(new_mtu == netdev->mtu) + return 0; + + netdev->mtu = new_mtu; + + if (new_mtu == SXG_JUMBO_MTU) { + adapter->JumboEnabled = TRUE; + adapter->FrameSize = JUMBOMAXFRAME; + adapter->ReceiveBufferSize = SXG_RCV_JUMBO_BUFFER_SIZE; + } else { + adapter->JumboEnabled = FALSE; + adapter->FrameSize = ETHERMAXFRAME; + adapter->ReceiveBufferSize = SXG_RCV_DATA_BUFFER_SIZE; + } + + sxg_entry_halt(netdev); + sxg_entry_open(netdev); + return 0; +} + +/* * sxg_link_state - Set the link state and if necessary, indicate. * This routine the central point of processing for all link state changes. * Nothing else in the driver should alter the link state or perform @@ -2460,27 +3217,32 @@ static void sxg_indicate_link_state(struct adapter_t *adapter, * Return * None */ -static void sxg_link_state(struct adapter_t *adapter, enum SXG_LINK_STATE LinkState) +static void sxg_link_state(struct adapter_t *adapter, + enum SXG_LINK_STATE LinkState) { SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_IMPORTANT, "LnkINDCT", adapter, LinkState, adapter->LinkState, adapter->State); DBG_ERROR("ENTER %s\n", __func__); - /* Hold the adapter lock during this routine. Maybe move */ - /* the lock to the caller. */ - spin_lock(&adapter->AdapterLock); + /* + * Hold the adapter lock during this routine. Maybe move + * the lock to the caller. + */ + /* IMP TODO : Check if we can survive without taking this lock */ +// spin_lock(&adapter->AdapterLock); if (LinkState == adapter->LinkState) { /* Nothing changed.. */ - spin_unlock(&adapter->AdapterLock); - DBG_ERROR("EXIT #0 %s\n", __func__); +// spin_unlock(&adapter->AdapterLock); + DBG_ERROR("EXIT #0 %s. Link status = %d\n", + __func__, LinkState); return; } /* Save the adapter state */ adapter->LinkState = LinkState; /* Drop the lock and indicate link state */ - spin_unlock(&adapter->AdapterLock); +// spin_unlock(&adapter->AdapterLock); DBG_ERROR("EXIT #1 %s\n", __func__); sxg_indicate_link_state(adapter, LinkState); @@ -2501,14 +3263,16 @@ static void sxg_link_state(struct adapter_t *adapter, enum SXG_LINK_STATE LinkSt static int sxg_write_mdio_reg(struct adapter_t *adapter, u32 DevAddr, u32 RegAddr, u32 Value) { - struct SXG_HW_REGS *HwRegs = adapter->HwRegs; - u32 AddrOp; /* Address operation (written to MIIM field reg) */ - u32 WriteOp; /* Write operation (written to MIIM field reg) */ - u32 Cmd; /* Command (written to MIIM command reg) */ + struct sxg_hw_regs *HwRegs = adapter->HwRegs; + /* Address operation (written to MIIM field reg) */ + u32 AddrOp; + /* Write operation (written to MIIM field reg) */ + u32 WriteOp; + u32 Cmd;/* Command (written to MIIM command reg) */ u32 ValueRead; u32 Timeout; -/* DBG_ERROR("ENTER %s\n", __func__); */ + /* DBG_ERROR("ENTER %s\n", __func__); */ SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "WrtMDIO", adapter, 0, 0, 0); @@ -2571,7 +3335,7 @@ static int sxg_write_mdio_reg(struct adapter_t *adapter, } } while (ValueRead & AXGMAC_AMIIM_INDC_BUSY); -/* DBG_ERROR("EXIT %s\n", __func__); */ + /* DBG_ERROR("EXIT %s\n", __func__); */ return (STATUS_SUCCESS); } @@ -2583,7 +3347,7 @@ static int sxg_write_mdio_reg(struct adapter_t *adapter, * adapter - A pointer to our adapter structure * DevAddr - MDIO device number being addressed * RegAddr - register address for the specified MDIO device - * pValue - pointer to where to put data read from the MDIO register + * pValue - pointer to where to put data read from the MDIO register * * Return * status @@ -2591,16 +3355,16 @@ static int sxg_write_mdio_reg(struct adapter_t *adapter, static int sxg_read_mdio_reg(struct adapter_t *adapter, u32 DevAddr, u32 RegAddr, u32 *pValue) { - struct SXG_HW_REGS *HwRegs = adapter->HwRegs; - u32 AddrOp; /* Address operation (written to MIIM field reg) */ - u32 ReadOp; /* Read operation (written to MIIM field reg) */ - u32 Cmd; /* Command (written to MIIM command reg) */ + struct sxg_hw_regs *HwRegs = adapter->HwRegs; + u32 AddrOp; /* Address operation (written to MIIM field reg) */ + u32 ReadOp; /* Read operation (written to MIIM field reg) */ + u32 Cmd; /* Command (written to MIIM command reg) */ u32 ValueRead; u32 Timeout; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "WrtMDIO", adapter, 0, 0, 0); -/* DBG_ERROR("ENTER %s\n", __func__); */ + DBG_ERROR("ENTER %s\n", __FUNCTION__); /* Ensure values don't exceed field width */ DevAddr &= 0x001F; /* 5-bit field */ @@ -2636,6 +3400,8 @@ static int sxg_read_mdio_reg(struct adapter_t *adapter, udelay(100); /* Timeout in 100us units */ READ_REG(HwRegs->MacAmiimIndicator, ValueRead); if (--Timeout == 0) { + DBG_ERROR("EXIT %s with STATUS_FAILURE 1\n", __FUNCTION__); + return (STATUS_FAILURE); } } while (ValueRead & AXGMAC_AMIIM_INDC_BUSY); @@ -2655,6 +3421,8 @@ static int sxg_read_mdio_reg(struct adapter_t *adapter, udelay(100); /* Timeout in 100us units */ READ_REG(HwRegs->MacAmiimIndicator, ValueRead); if (--Timeout == 0) { + DBG_ERROR("EXIT %s with STATUS_FAILURE 2\n", __FUNCTION__); + return (STATUS_FAILURE); } } while (ValueRead & AXGMAC_AMIIM_INDC_BUSY); @@ -2663,7 +3431,7 @@ static int sxg_read_mdio_reg(struct adapter_t *adapter, READ_REG(HwRegs->MacAmiimField, *pValue); *pValue &= 0xFFFF; /* data is in the lower 16 bits */ -/* DBG_ERROR("EXIT %s\n", __func__); */ + DBG_ERROR("EXIT %s\n", __FUNCTION__); return (STATUS_SUCCESS); } @@ -2672,22 +3440,21 @@ static int sxg_read_mdio_reg(struct adapter_t *adapter, * Functions to obtain the CRC corresponding to the destination mac address. * This is a standard ethernet CRC in that it is a 32-bit, reflected CRC using * the polynomial: - * x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1. - * - * After the CRC for the 6 bytes is generated (but before the value is complemented), - * we must then transpose the value and return bits 30-23. + * x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + * + x^4 + x^2 + x^1. * + * After the CRC for the 6 bytes is generated (but before the value is + * complemented), we must then transpose the value and return bits 30-23. */ -static u32 sxg_crc_table[256]; /* Table of CRC's for all possible byte values */ +static u32 sxg_crc_table[256];/* Table of CRC's for all possible byte values */ +static u32 sxg_crc_init; /* Is table initialized */ -/* - * Contruct the CRC32 table - */ +/* Contruct the CRC32 table */ static void sxg_mcast_init_crc32(void) { - u32 c; /* CRC shit reg */ - u32 e = 0; /* Poly X-or pattern */ - int i; /* counter */ + u32 c; /* CRC shit reg */ + u32 e = 0; /* Poly X-or pattern */ + int i; /* counter */ int k; /* byte being shifted into crc */ static int p[] = { 0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26 }; @@ -2705,8 +3472,6 @@ static void sxg_mcast_init_crc32(void) } } -#if XXXTODO -static u32 sxg_crc_init; /* Is table initialized */ /* * Return the MAC hast as described above. */ @@ -2737,25 +3502,31 @@ static unsigned char sxg_mcast_get_mac_hash(char *macaddr) static void sxg_mcast_set_mask(struct adapter_t *adapter) { - struct SXG_UCODE_REGS *sxg_regs = adapter->UcodeRegs; + struct sxg_ucode_regs *sxg_regs = adapter->UcodeRegs; - DBG_ERROR("%s ENTER (%s) macopts[%x] mask[%llx]\n", __func__, + DBG_ERROR("%s ENTER (%s) MacFilter[%x] mask[%llx]\n", __FUNCTION__, adapter->netdev->name, (unsigned int)adapter->MacFilter, adapter->MulticastMask); if (adapter->MacFilter & (MAC_ALLMCAST | MAC_PROMISC)) { - /* Turn on all multicast addresses. We have to do this for promiscuous - * mode as well as ALLMCAST mode. It saves the Microcode from having - * to keep state about the MAC configuration. + /* + * Turn on all multicast addresses. We have to do this for + * promiscuous mode as well as ALLMCAST mode. It saves the + * Microcode from having keep state about the MAC configuration + */ + /* DBG_ERROR("sxg: %s MacFilter = MAC_ALLMCAST | MAC_PROMISC\n \ + * SLUT MODE!!!\n",__func__); */ -/* DBG_ERROR("sxg: %s macopts = MAC_ALLMCAST | MAC_PROMISC\n SLUT MODE!!!\n",__func__); */ WRITE_REG(sxg_regs->McastLow, 0xFFFFFFFF, FLUSH); WRITE_REG(sxg_regs->McastHigh, 0xFFFFFFFF, FLUSH); -/* DBG_ERROR("%s (%s) WRITE to slic_regs slic_mcastlow&high 0xFFFFFFFF\n",__func__, adapter->netdev->name); */ + /* DBG_ERROR("%s (%s) WRITE to slic_regs slic_mcastlow&high \ + * 0xFFFFFFFF\n",__func__, adapter->netdev->name); + */ } else { - /* Commit our multicast mast to the SLIC by writing to the multicast - * address mask registers + /* + * Commit our multicast mast to the SLIC by writing to the + * multicast address mask registers */ DBG_ERROR("%s (%s) WRITE mcastlow[%lx] mcasthigh[%lx]\n", __func__, adapter->netdev->name, @@ -2771,38 +3542,6 @@ static void sxg_mcast_set_mask(struct adapter_t *adapter) } } -/* - * Allocate a mcast_address structure to hold the multicast address. - * Link it in. - */ -static int sxg_mcast_add_list(struct adapter_t *adapter, char *address) -{ - p_mcast_address_t mcaddr, mlist; - bool equaladdr; - - /* Check to see if it already exists */ - mlist = adapter->mcastaddrs; - while (mlist) { - ETHER_EQ_ADDR(mlist->address, address, equaladdr); - if (equaladdr) { - return (STATUS_SUCCESS); - } - mlist = mlist->next; - } - - /* Doesn't already exist. Allocate a structure to hold it */ - mcaddr = kmalloc(sizeof(mcast_address_t), GFP_ATOMIC); - if (mcaddr == NULL) - return 1; - - memcpy(mcaddr->address, address, 6); - - mcaddr->next = adapter->mcastaddrs; - adapter->mcastaddrs = mcaddr; - - return (STATUS_SUCCESS); -} - static void sxg_mcast_set_bit(struct adapter_t *adapter, char *address) { unsigned char crcpoly; @@ -2810,7 +3549,8 @@ static void sxg_mcast_set_bit(struct adapter_t *adapter, char *address) /* Get the CRC polynomial for the mac address */ crcpoly = sxg_mcast_get_mac_hash(address); - /* We only have space on the SLIC for 64 entries. Lop + /* + * We only have space on the SLIC for 64 entries. Lop * off the top two bits. (2^6 = 64) */ crcpoly &= 0x3F; @@ -2819,76 +3559,119 @@ static void sxg_mcast_set_bit(struct adapter_t *adapter, char *address) adapter->MulticastMask |= (u64) 1 << crcpoly; } -static void sxg_mcast_set_list(p_net_device dev) +/* + * Function takes MAC addresses from dev_mc_list and generates the Mask + */ + +static void sxg_set_mcast_addr(struct adapter_t *adapter) +{ + struct dev_mc_list *mclist; + struct net_device *dev = adapter->netdev; + int i; + + if (adapter->MacFilter & (MAC_ALLMCAST | MAC_MCAST)) { + for (i = 0, mclist = dev->mc_list; i < dev->mc_count; + i++, mclist = mclist->next) { + sxg_mcast_set_bit(adapter,mclist->da_addr); + } + } + sxg_mcast_set_mask(adapter); +} + +static void sxg_mcast_set_list(struct net_device *dev) { struct adapter_t *adapter = (struct adapter_t *) netdev_priv(dev); - int status = STATUS_SUCCESS; - int i; - char *addresses; - struct dev_mc_list *mc_list = dev->mc_list; - int mc_count = dev->mc_count; ASSERT(adapter); + if (dev->flags & IFF_PROMISC) + adapter->MacFilter |= MAC_PROMISC; + if (dev->flags & IFF_MULTICAST) + adapter->MacFilter |= MAC_MCAST; + if (dev->flags & IFF_ALLMULTI) + adapter->MacFilter |= MAC_ALLMCAST; + + //XXX handle other flags as well + sxg_set_mcast_addr(adapter); +} - for (i = 1; i <= mc_count; i++) { - addresses = (char *)&mc_list->dmi_addr; - if (mc_list->dmi_addrlen == 6) { - status = sxg_mcast_add_list(adapter, addresses); - if (status != STATUS_SUCCESS) { - break; - } - } else { - status = -EINVAL; - break; - } - sxg_mcast_set_bit(adapter, addresses); - mc_list = mc_list->next; - } +void sxg_free_sgl_buffers(struct adapter_t *adapter) +{ + struct list_entry *ple; + struct sxg_scatter_gather *Sgl; + + while(!(IsListEmpty(&adapter->AllSglBuffers))) { + ple = RemoveHeadList(&adapter->AllSglBuffers); + Sgl = container_of(ple, struct sxg_scatter_gather, AllList); + kfree(Sgl); + adapter->AllSglBufferCount--; + } +} - DBG_ERROR("%s a->devflags_prev[%x] dev->flags[%x] status[%x]\n", - __func__, adapter->devflags_prev, dev->flags, status); - if (adapter->devflags_prev != dev->flags) { - adapter->macopts = MAC_DIRECTED; - if (dev->flags) { - if (dev->flags & IFF_BROADCAST) { - adapter->macopts |= MAC_BCAST; - } - if (dev->flags & IFF_PROMISC) { - adapter->macopts |= MAC_PROMISC; - } - if (dev->flags & IFF_ALLMULTI) { - adapter->macopts |= MAC_ALLMCAST; - } - if (dev->flags & IFF_MULTICAST) { - adapter->macopts |= MAC_MCAST; - } - } - adapter->devflags_prev = dev->flags; - DBG_ERROR("%s call sxg_config_set adapter->macopts[%x]\n", - __func__, adapter->macopts); - sxg_config_set(adapter, TRUE); - } else { - if (status == STATUS_SUCCESS) { - sxg_mcast_set_mask(adapter); - } +void sxg_free_rcvblocks(struct adapter_t *adapter) +{ + u32 i; + void *temp_RcvBlock; + struct list_entry *ple; + struct sxg_rcv_block_hdr *RcvBlockHdr; + struct sxg_rcv_data_buffer_hdr *RcvDataBufferHdr; + ASSERT((adapter->state == SXG_STATE_INITIALIZING) || + (adapter->state == SXG_STATE_HALTING)); + while(!(IsListEmpty(&adapter->AllRcvBlocks))) { + + ple = RemoveHeadList(&adapter->AllRcvBlocks); + RcvBlockHdr = container_of(ple, struct sxg_rcv_block_hdr, AllList); + + if(RcvBlockHdr->VirtualAddress) { + temp_RcvBlock = RcvBlockHdr->VirtualAddress; + + for(i=0; i< SXG_RCV_DESCRIPTORS_PER_BLOCK; + i++, temp_RcvBlock += SXG_RCV_DATA_HDR_SIZE) { + RcvDataBufferHdr = + (struct sxg_rcv_data_buffer_hdr *)temp_RcvBlock; + SXG_FREE_RCV_PACKET(RcvDataBufferHdr); + } + } + + pci_free_consistent(adapter->pcidev, + SXG_RCV_BLOCK_SIZE(SXG_RCV_DATA_HDR_SIZE), + RcvBlockHdr->VirtualAddress, + RcvBlockHdr->PhysicalAddress); + adapter->AllRcvBlockCount--; } - return; + ASSERT(adapter->AllRcvBlockCount == 0); + SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XFrRBlk", + adapter, 0, 0, 0); +} +void sxg_free_mcast_addrs(struct adapter_t *adapter) +{ + struct sxg_multicast_address *address; + while(adapter->MulticastAddrs) { + address = adapter->MulticastAddrs; + adapter->MulticastAddrs = address->Next; + kfree(address); + } + + adapter->MulticastMask= 0; } -#endif -static void sxg_unmap_mmio_space(struct adapter_t *adapter) +void sxg_unmap_resources(struct adapter_t *adapter) { -#if LINUX_FREES_ADAPTER_RESOURCES -/* if (adapter->Regs) { */ -/* iounmap(adapter->Regs); */ -/* } */ -/* adapter->slic_regs = NULL; */ -#endif + if(adapter->HwRegs) { + iounmap((void *)adapter->HwRegs); + } + if(adapter->UcodeRegs) { + iounmap((void *)adapter->UcodeRegs); + } + + ASSERT(adapter->AllRcvBlockCount == 0); + SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XFrRBlk", + adapter, 0, 0, 0); } -#if XXXTODO + + /* - * SxgFreeResources - Free everything allocated in SxgAllocateResources + * sxg_free_resources - Free everything allocated in SxgAllocateResources * * Arguments - * adapter - A pointer to our adapter structure @@ -2896,94 +3679,76 @@ static void sxg_unmap_mmio_space(struct adapter_t *adapter) * Return * none */ -void SxgFreeResources(struct adapter_t *adapter) +void sxg_free_resources(struct adapter_t *adapter) { u32 RssIds, IsrCount; - PTCP_OBJECT TcpObject; - u32 i; - BOOLEAN TimerCancelled; - - SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "FreeRes", - adapter, adapter->MaxTcbs, 0, 0); - RssIds = SXG_RSS_CPU_COUNT(adapter); - IsrCount = adapter->MsiEnabled ? RssIds : 1; + IsrCount = adapter->msi_enabled ? RssIds : 1; if (adapter->BasicAllocations == FALSE) { - /* No allocations have been made, including spinlocks, */ - /* or listhead initializations. Return. */ + /* + * No allocations have been made, including spinlocks, + * or listhead initializations. Return. + */ return; } if (!(IsListEmpty(&adapter->AllRcvBlocks))) { - SxgFreeRcvBlocks(adapter); + sxg_free_rcvblocks(adapter); } if (!(IsListEmpty(&adapter->AllSglBuffers))) { - SxgFreeSglBuffers(adapter); - } - /* Free event queues. */ - if (adapter->EventRings) { - pci_free_consistent(adapter->pcidev, - sizeof(struct SXG_EVENT_RING) * RssIds, - adapter->EventRings, adapter->PEventRings); - } - if (adapter->Isr) { - pci_free_consistent(adapter->pcidev, - sizeof(u32) * IsrCount, - adapter->Isr, adapter->PIsr); + sxg_free_sgl_buffers(adapter); } + if (adapter->XmtRingZeroIndex) { pci_free_consistent(adapter->pcidev, sizeof(u32), adapter->XmtRingZeroIndex, adapter->PXmtRingZeroIndex); } - if (adapter->IndirectionTable) { - pci_free_consistent(adapter->pcidev, - SXG_MAX_RSS_TABLE_SIZE, - adapter->IndirectionTable, - adapter->PIndirectionTable); + if (adapter->Isr) { + pci_free_consistent(adapter->pcidev, + sizeof(u32) * IsrCount, + adapter->Isr, adapter->PIsr); + } + + if (adapter->EventRings) { + pci_free_consistent(adapter->pcidev, + sizeof(struct sxg_event_ring) * RssIds, + adapter->EventRings, adapter->PEventRings); + } + if (adapter->RcvRings) { + pci_free_consistent(adapter->pcidev, + sizeof(struct sxg_rcv_ring) * 1, + adapter->RcvRings, + adapter->PRcvRings); + adapter->RcvRings = NULL; + } + + if(adapter->XmtRings) { + pci_free_consistent(adapter->pcidev, + sizeof(struct sxg_xmt_ring) * 1, + adapter->XmtRings, + adapter->PXmtRings); + adapter->XmtRings = NULL; + } + + if (adapter->ucode_stats) { + pci_unmap_single(adapter->pcidev, + sizeof(struct sxg_ucode_stats), + adapter->pucode_stats, PCI_DMA_FROMDEVICE); + adapter->ucode_stats = NULL; } - SXG_FREE_PACKET_POOL(adapter->PacketPoolHandle); - SXG_FREE_BUFFER_POOL(adapter->BufferPoolHandle); /* Unmap register spaces */ - SxgUnmapResources(adapter); - - /* Deregister DMA */ - if (adapter->DmaHandle) { - SXG_DEREGISTER_DMA(adapter->DmaHandle); - } - /* Deregister interrupt */ - SxgDeregisterInterrupt(adapter); - - /* Possibly free system info (5.2 only) */ - SXG_RELEASE_SYSTEM_INFO(adapter); - - SxgDiagFreeResources(adapter); + sxg_unmap_resources(adapter); - SxgFreeMCastAddrs(adapter); - - if (SXG_TIMER_ALLOCATED(adapter->ResetTimer)) { - SXG_CANCEL_TIMER(adapter->ResetTimer, TimerCancelled); - SXG_FREE_TIMER(adapter->ResetTimer); - } - if (SXG_TIMER_ALLOCATED(adapter->RssTimer)) { - SXG_CANCEL_TIMER(adapter->RssTimer, TimerCancelled); - SXG_FREE_TIMER(adapter->RssTimer); - } - if (SXG_TIMER_ALLOCATED(adapter->OffloadTimer)) { - SXG_CANCEL_TIMER(adapter->OffloadTimer, TimerCancelled); - SXG_FREE_TIMER(adapter->OffloadTimer); - } + sxg_free_mcast_addrs(adapter); adapter->BasicAllocations = FALSE; - SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XFreeRes", - adapter, adapter->MaxTcbs, 0, 0); } -#endif /* * sxg_allocate_complete - @@ -3000,31 +3765,34 @@ void SxgFreeResources(struct adapter_t *adapter) * Return * None. */ -static void sxg_allocate_complete(struct adapter_t *adapter, +static int sxg_allocate_complete(struct adapter_t *adapter, void *VirtualAddress, dma_addr_t PhysicalAddress, - u32 Length, enum SXG_BUFFER_TYPE Context) + u32 Length, enum sxg_buffer_type Context) { + int status = 0; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AllocCmp", adapter, VirtualAddress, Length, Context); - ASSERT(adapter->AllocationsPending); - --adapter->AllocationsPending; + ASSERT(atomic_read(&adapter->pending_allocations)); + atomic_dec(&adapter->pending_allocations); switch (Context) { case SXG_BUFFER_TYPE_RCV: - sxg_allocate_rcvblock_complete(adapter, + status = sxg_allocate_rcvblock_complete(adapter, VirtualAddress, PhysicalAddress, Length); break; case SXG_BUFFER_TYPE_SGL: - sxg_allocate_sgl_buffer_complete(adapter, (struct SXG_SCATTER_GATHER*) + sxg_allocate_sgl_buffer_complete(adapter, (struct sxg_scatter_gather *) VirtualAddress, PhysicalAddress, Length); break; } SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAlocCmp", adapter, VirtualAddress, Length, Context); + + return status; } /* @@ -3040,7 +3808,7 @@ static void sxg_allocate_complete(struct adapter_t *adapter, * int */ static int sxg_allocate_buffer_memory(struct adapter_t *adapter, - u32 Size, enum SXG_BUFFER_TYPE BufferType) + u32 Size, enum sxg_buffer_type BufferType) { int status; void *Buffer; @@ -3048,39 +3816,40 @@ static int sxg_allocate_buffer_memory(struct adapter_t *adapter, SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AllocMem", adapter, Size, BufferType, 0); - /* Grab the adapter lock and check the state. */ - /* If we're in anything other than INITIALIZING or */ - /* RUNNING state, fail. This is to prevent */ - /* allocations in an improper driver state */ - spin_lock(&adapter->AdapterLock); - - /* Increment the AllocationsPending count while holding */ - /* the lock. Pause processing relies on this */ - ++adapter->AllocationsPending; - spin_unlock(&adapter->AdapterLock); - - /* At initialization time allocate resources synchronously. */ - Buffer = pci_alloc_consistent(adapter->pcidev, Size, &pBuffer); + /* + * Grab the adapter lock and check the state. If we're in anything other + * than INITIALIZING or RUNNING state, fail. This is to prevent + * allocations in an improper driver state + */ + + atomic_inc(&adapter->pending_allocations); + + if(BufferType != SXG_BUFFER_TYPE_SGL) + Buffer = pci_alloc_consistent(adapter->pcidev, Size, &pBuffer); + else { + Buffer = kzalloc(Size, GFP_ATOMIC); + pBuffer = (dma_addr_t)NULL; + } if (Buffer == NULL) { - spin_lock(&adapter->AdapterLock); - /* Decrement the AllocationsPending count while holding */ - /* the lock. Pause processing relies on this */ - --adapter->AllocationsPending; - spin_unlock(&adapter->AdapterLock); + /* + * Decrement the AllocationsPending count while holding + * the lock. Pause processing relies on this + */ + atomic_dec(&adapter->pending_allocations); SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AlcMemF1", adapter, Size, BufferType, 0); return (STATUS_RESOURCES); } - sxg_allocate_complete(adapter, Buffer, pBuffer, Size, BufferType); - status = STATUS_SUCCESS; + status = sxg_allocate_complete(adapter, Buffer, pBuffer, Size, BufferType); SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAlocMem", adapter, Size, BufferType, status); - return (status); + return status; } /* - * sxg_allocate_rcvblock_complete - Complete a receive descriptor block allocation + * sxg_allocate_rcvblock_complete - Complete a receive descriptor + * block allocation * * Arguments - * adapter - A pointer to our adapter structure @@ -3089,9 +3858,8 @@ static int sxg_allocate_buffer_memory(struct adapter_t *adapter, * Length - Memory length * * Return - * */ -static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter, +static int sxg_allocate_rcvblock_complete(struct adapter_t *adapter, void *RcvBlock, dma_addr_t PhysicalAddress, u32 Length) @@ -3099,11 +3867,11 @@ static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter, u32 i; u32 BufferSize = adapter->ReceiveBufferSize; u64 Paddr; - struct SXG_RCV_BLOCK_HDR *RcvBlockHdr; - unsigned char *RcvDataBuffer; - struct SXG_RCV_DATA_BUFFER_HDR *RcvDataBufferHdr; - struct SXG_RCV_DESCRIPTOR_BLOCK *RcvDescriptorBlock; - struct SXG_RCV_DESCRIPTOR_BLOCK_HDR *RcvDescriptorBlockHdr; + void *temp_RcvBlock; + struct sxg_rcv_block_hdr *RcvBlockHdr; + struct sxg_rcv_data_buffer_hdr *RcvDataBufferHdr; + struct sxg_rcv_descriptor_block *RcvDescriptorBlock; + struct sxg_rcv_descriptor_block_hdr *RcvDescriptorBlockHdr; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AlRcvBlk", adapter, RcvBlock, Length, 0); @@ -3113,42 +3881,33 @@ static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter, memset(RcvBlock, 0, Length); ASSERT((BufferSize == SXG_RCV_DATA_BUFFER_SIZE) || (BufferSize == SXG_RCV_JUMBO_BUFFER_SIZE)); - ASSERT(Length == SXG_RCV_BLOCK_SIZE(BufferSize)); - /* First, initialize the contained pool of receive data */ - /* buffers. This initialization requires NBL/NB/MDL allocations, */ - /* If any of them fail, free the block and return without */ - /* queueing the shared memory */ - RcvDataBuffer = RcvBlock; -#if 0 - for (i = 0, Paddr = *PhysicalAddress; - i < SXG_RCV_DESCRIPTORS_PER_BLOCK; - i++, Paddr.LowPart += BufferSize, RcvDataBuffer += BufferSize) -#endif - for (i = 0, Paddr = PhysicalAddress; - i < SXG_RCV_DESCRIPTORS_PER_BLOCK; - i++, Paddr += BufferSize, RcvDataBuffer += BufferSize) { - /* */ - RcvDataBufferHdr = - (struct SXG_RCV_DATA_BUFFER_HDR*) (RcvDataBuffer + - SXG_RCV_DATA_BUFFER_HDR_OFFSET - (BufferSize)); - RcvDataBufferHdr->VirtualAddress = RcvDataBuffer; - RcvDataBufferHdr->PhysicalAddress = Paddr; - RcvDataBufferHdr->State = SXG_BUFFER_UPSTREAM; /* For FREE macro assertion */ - RcvDataBufferHdr->Size = - SXG_RCV_BUFFER_DATA_SIZE(BufferSize); - - SXG_ALLOCATE_RCV_PACKET(adapter, RcvDataBufferHdr); - if (RcvDataBufferHdr->SxgDumbRcvPacket == NULL) - goto fail; + ASSERT(Length == SXG_RCV_BLOCK_SIZE(SXG_RCV_DATA_HDR_SIZE)); + /* + * First, initialize the contained pool of receive data buffers. + * This initialization requires NBL/NB/MDL allocations, if any of them + * fail, free the block and return without queueing the shared memory + */ + //RcvDataBuffer = RcvBlock; + temp_RcvBlock = RcvBlock; + for (i = 0; i < SXG_RCV_DESCRIPTORS_PER_BLOCK; + i++, temp_RcvBlock += SXG_RCV_DATA_HDR_SIZE) { + RcvDataBufferHdr = (struct sxg_rcv_data_buffer_hdr *) + temp_RcvBlock; + /* For FREE macro assertion */ + RcvDataBufferHdr->State = SXG_BUFFER_UPSTREAM; + SXG_ALLOCATE_RCV_PACKET(adapter, RcvDataBufferHdr, BufferSize); + if (RcvDataBufferHdr->SxgDumbRcvPacket == NULL) + goto fail; - } + } - /* Place this entire block of memory on the AllRcvBlocks queue so it can be */ - /* free later */ - RcvBlockHdr = - (struct SXG_RCV_BLOCK_HDR*) ((unsigned char *)RcvBlock + - SXG_RCV_BLOCK_HDR_OFFSET(BufferSize)); + /* + * Place this entire block of memory on the AllRcvBlocks queue so it + * can be free later + */ + + RcvBlockHdr = (struct sxg_rcv_block_hdr *) ((unsigned char *)RcvBlock + + SXG_RCV_BLOCK_HDR_OFFSET(SXG_RCV_DATA_HDR_SIZE)); RcvBlockHdr->VirtualAddress = RcvBlock; RcvBlockHdr->PhysicalAddress = PhysicalAddress; spin_lock(&adapter->RcvQLock); @@ -3156,14 +3915,15 @@ static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter, InsertTailList(&adapter->AllRcvBlocks, &RcvBlockHdr->AllList); spin_unlock(&adapter->RcvQLock); - /* Now free the contained receive data buffers that we initialized above */ - RcvDataBuffer = RcvBlock; + /* Now free the contained receive data buffers that we + * initialized above */ + temp_RcvBlock = RcvBlock; for (i = 0, Paddr = PhysicalAddress; i < SXG_RCV_DESCRIPTORS_PER_BLOCK; - i++, Paddr += BufferSize, RcvDataBuffer += BufferSize) { - RcvDataBufferHdr = (struct SXG_RCV_DATA_BUFFER_HDR*) (RcvDataBuffer + - SXG_RCV_DATA_BUFFER_HDR_OFFSET - (BufferSize)); + i++, Paddr += SXG_RCV_DATA_HDR_SIZE, + temp_RcvBlock += SXG_RCV_DATA_HDR_SIZE) { + RcvDataBufferHdr = + (struct sxg_rcv_data_buffer_hdr *)temp_RcvBlock; spin_lock(&adapter->RcvQLock); SXG_FREE_RCV_DATA_BUFFER(adapter, RcvDataBufferHdr); spin_unlock(&adapter->RcvQLock); @@ -3171,13 +3931,13 @@ static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter, /* Locate the descriptor block and put it on a separate free queue */ RcvDescriptorBlock = - (struct SXG_RCV_DESCRIPTOR_BLOCK*) ((unsigned char *)RcvBlock + + (struct sxg_rcv_descriptor_block *) ((unsigned char *)RcvBlock + SXG_RCV_DESCRIPTOR_BLOCK_OFFSET - (BufferSize)); + (SXG_RCV_DATA_HDR_SIZE)); RcvDescriptorBlockHdr = - (struct SXG_RCV_DESCRIPTOR_BLOCK_HDR*) ((unsigned char *)RcvBlock + + (struct sxg_rcv_descriptor_block_hdr *) ((unsigned char *)RcvBlock + SXG_RCV_DESCRIPTOR_BLOCK_HDR_OFFSET - (BufferSize)); + (SXG_RCV_DATA_HDR_SIZE)); RcvDescriptorBlockHdr->VirtualAddress = RcvDescriptorBlock; RcvDescriptorBlockHdr->PhysicalAddress = Paddr; spin_lock(&adapter->RcvQLock); @@ -3185,17 +3945,15 @@ static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter, spin_unlock(&adapter->RcvQLock); SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAlRBlk", adapter, RcvBlock, Length, 0); - return; - fail: + return STATUS_SUCCESS; +fail: /* Free any allocated resources */ if (RcvBlock) { - RcvDataBuffer = RcvBlock; + temp_RcvBlock = RcvBlock; for (i = 0; i < SXG_RCV_DESCRIPTORS_PER_BLOCK; - i++, RcvDataBuffer += BufferSize) { + i++, temp_RcvBlock += SXG_RCV_DATA_HDR_SIZE) { RcvDataBufferHdr = - (struct SXG_RCV_DATA_BUFFER_HDR*) (RcvDataBuffer + - SXG_RCV_DATA_BUFFER_HDR_OFFSET - (BufferSize)); + (struct sxg_rcv_data_buffer_hdr *)temp_RcvBlock; SXG_FREE_RCV_PACKET(RcvDataBufferHdr); } pci_free_consistent(adapter->pcidev, @@ -3206,6 +3964,10 @@ static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter, adapter, adapter->FreeRcvBufferCount, adapter->FreeRcvBlockCount, adapter->AllRcvBlockCount); adapter->Stats.NoMem++; + /* As allocation failed, free all previously allocated blocks..*/ + //sxg_free_rcvblocks(adapter); + + return STATUS_RESOURCES; } /* @@ -3213,46 +3975,65 @@ static void sxg_allocate_rcvblock_complete(struct adapter_t *adapter, * * Arguments - * adapter - A pointer to our adapter structure - * SxgSgl - SXG_SCATTER_GATHER buffer + * SxgSgl - struct sxg_scatter_gather buffer * PhysicalAddress - Physical address * Length - Memory length * * Return - * */ static void sxg_allocate_sgl_buffer_complete(struct adapter_t *adapter, - struct SXG_SCATTER_GATHER *SxgSgl, + struct sxg_scatter_gather *SxgSgl, dma_addr_t PhysicalAddress, u32 Length) { + unsigned long sgl_flags; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "AlSglCmp", adapter, SxgSgl, Length, 0); - spin_lock(&adapter->SglQLock); + spin_lock_irqsave(&adapter->SglQLock, sgl_flags); adapter->AllSglBufferCount++; - memset(SxgSgl, 0, sizeof(struct SXG_SCATTER_GATHER*)); - SxgSgl->PhysicalAddress = PhysicalAddress; /* *PhysicalAddress; */ - SxgSgl->adapter = adapter; /* Initialize backpointer once */ + /* PhysicalAddress; */ + SxgSgl->PhysicalAddress = PhysicalAddress; + /* Initialize backpointer once */ + SxgSgl->adapter = adapter; InsertTailList(&adapter->AllSglBuffers, &SxgSgl->AllList); - spin_unlock(&adapter->SglQLock); + spin_unlock_irqrestore(&adapter->SglQLock, sgl_flags); SxgSgl->State = SXG_BUFFER_BUSY; SXG_FREE_SGL_BUFFER(adapter, SxgSgl, NULL); SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XAlSgl", adapter, SxgSgl, Length, 0); } -static unsigned char temp_mac_address[6] = - { 0x00, 0xab, 0xcd, 0xef, 0x12, 0x69 }; -static void sxg_adapter_set_hwaddr(struct adapter_t *adapter) +static int sxg_adapter_set_hwaddr(struct adapter_t *adapter) { -/* DBG_ERROR ("%s ENTER card->config_set[%x] port[%d] physport[%d] funct#[%d]\n", __func__, */ -/* card->config_set, adapter->port, adapter->physport, adapter->functionnumber); */ -/* */ -/* sxg_dbg_macaddrs(adapter); */ + /* + * DBG_ERROR ("%s ENTER card->config_set[%x] port[%d] physport[%d] \ + * funct#[%d]\n", __func__, card->config_set, + * adapter->port, adapter->physport, adapter->functionnumber); + * + * sxg_dbg_macaddrs(adapter); + */ + /* DBG_ERROR ("%s AFTER copying from config.macinfo into currmacaddr\n", + * __FUNCTION__); + */ + + /* sxg_dbg_macaddrs(adapter); */ + + struct net_device * dev = adapter->netdev; + if(!dev) + { + printk("sxg: Dev is Null\n"); + } + + DBG_ERROR("%s ENTER (%s)\n", __FUNCTION__, adapter->netdev->name); + + if (netif_running(dev)) { + return -EBUSY; + } + if (!adapter) { + return -EBUSY; + } - memcpy(adapter->macaddr, temp_mac_address, sizeof(struct SXG_CONFIG_MAC)); -/* DBG_ERROR ("%s AFTER copying from config.macinfo into currmacaddr\n", __func__); */ -/* sxg_dbg_macaddrs(adapter); */ if (!(adapter->currmacaddr[0] || adapter->currmacaddr[1] || adapter->currmacaddr[2] || @@ -3262,14 +4043,16 @@ static void sxg_adapter_set_hwaddr(struct adapter_t *adapter) } if (adapter->netdev) { memcpy(adapter->netdev->dev_addr, adapter->currmacaddr, 6); + memcpy(adapter->netdev->perm_addr, adapter->currmacaddr, 6); } -/* DBG_ERROR ("%s EXIT port %d\n", __func__, adapter->port); */ + /* DBG_ERROR ("%s EXIT port %d\n", __func__, adapter->port); */ sxg_dbg_macaddrs(adapter); + return 0; } #if XXXTODO -static int sxg_mac_set_address(p_net_device dev, void *ptr) +static int sxg_mac_set_address(struct net_device *dev, void *ptr) { struct adapter_t *adapter = (struct adapter_t *) netdev_priv(dev); struct sockaddr *addr = ptr; @@ -3300,34 +4083,34 @@ static int sxg_mac_set_address(p_net_device dev, void *ptr) } #endif -/*****************************************************************************/ -/************* SXG DRIVER FUNCTIONS (below) ********************************/ -/*****************************************************************************/ - /* + * SXG DRIVER FUNCTIONS (below) + * * sxg_initialize_adapter - Initialize adapter * * Arguments - * adapter - A pointer to our adapter structure * - * Return - * int + * Return - int */ static int sxg_initialize_adapter(struct adapter_t *adapter) { u32 RssIds, IsrCount; u32 i; int status; + int sxg_rcv_ring_size = SXG_RCV_RING_SIZE; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "InitAdpt", adapter, 0, 0, 0); RssIds = 1; /* XXXTODO SXG_RSS_CPU_COUNT(adapter); */ - IsrCount = adapter->MsiEnabled ? RssIds : 1; + IsrCount = adapter->msi_enabled ? RssIds : 1; - /* Sanity check SXG_UCODE_REGS structure definition to */ - /* make sure the length is correct */ - ASSERT(sizeof(struct SXG_UCODE_REGS) == SXG_REGISTER_SIZE_PER_CPU); + /* + * Sanity check SXG_UCODE_REGS structure definition to + * make sure the length is correct + */ + ASSERT(sizeof(struct sxg_ucode_regs) == SXG_REGISTER_SIZE_PER_CPU); /* Disable interrupts */ SXG_DISABLE_ALL_INTERRUPTS(adapter); @@ -3370,19 +4153,24 @@ static int sxg_initialize_adapter(struct adapter_t *adapter) /* Receive ring base and size */ WRITE_REG64(adapter, adapter->UcodeRegs[0].RcvBase, adapter->PRcvRings, 0); - WRITE_REG(adapter->UcodeRegs[0].RcvSize, SXG_RCV_RING_SIZE, TRUE); + if (adapter->JumboEnabled == TRUE) + sxg_rcv_ring_size = SXG_JUMBO_RCV_RING_SIZE; + WRITE_REG(adapter->UcodeRegs[0].RcvSize, sxg_rcv_ring_size, TRUE); /* Populate the card with receive buffers */ sxg_stock_rcv_buffers(adapter); - /* Initialize checksum offload capabilities. At the moment */ - /* we always enable IP and TCP receive checksums on the card. */ - /* Depending on the checksum configuration specified by the */ - /* user, we can choose to report or ignore the checksum */ - /* information provided by the card. */ + /* + * Initialize checksum offload capabilities. At the moment we always + * enable IP and TCP receive checksums on the card. Depending on the + * checksum configuration specified by the user, we can choose to + * report or ignore the checksum information provided by the card. + */ WRITE_REG(adapter->UcodeRegs[0].ReceiveChecksum, SXG_RCV_TCP_CSUM_ENABLED | SXG_RCV_IP_CSUM_ENABLED, TRUE); + adapter->flags |= (SXG_RCV_TCP_CSUM_ENABLED | SXG_RCV_IP_CSUM_ENABLED ); + /* Initialize the MAC, XAUI */ DBG_ERROR("sxg: %s ENTER sxg_initialize_link\n", __func__); status = sxg_initialize_link(adapter); @@ -3391,10 +4179,16 @@ static int sxg_initialize_adapter(struct adapter_t *adapter) if (status != STATUS_SUCCESS) { return (status); } - /* Initialize Dead to FALSE. */ - /* SlicCheckForHang or SlicDumpThread will take it from here. */ + /* + * Initialize Dead to FALSE. + * SlicCheckForHang or SlicDumpThread will take it from here. + */ adapter->Dead = FALSE; adapter->PingOutstanding = FALSE; + adapter->XmtFcEnabled = TRUE; + adapter->RcvFcEnabled = TRUE; + + adapter->State = SXG_STATE_RUNNING; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XInit", adapter, 0, 0, 0); @@ -3413,15 +4207,14 @@ static int sxg_initialize_adapter(struct adapter_t *adapter) * status */ static int sxg_fill_descriptor_block(struct adapter_t *adapter, - struct SXG_RCV_DESCRIPTOR_BLOCK_HDR - *RcvDescriptorBlockHdr) + struct sxg_rcv_descriptor_block_hdr *RcvDescriptorBlockHdr) { u32 i; - struct SXG_RING_INFO *RcvRingInfo = &adapter->RcvRingZeroInfo; - struct SXG_RCV_DATA_BUFFER_HDR *RcvDataBufferHdr; - struct SXG_RCV_DESCRIPTOR_BLOCK *RcvDescriptorBlock; - struct SXG_CMD *RingDescriptorCmd; - struct SXG_RCV_RING *RingZero = &adapter->RcvRings[0]; + struct sxg_ring_info *RcvRingInfo = &adapter->RcvRingZeroInfo; + struct sxg_rcv_data_buffer_hdr *RcvDataBufferHdr; + struct sxg_rcv_descriptor_block *RcvDescriptorBlock; + struct sxg_cmd *RingDescriptorCmd; + struct sxg_rcv_ring *RingZero = &adapter->RcvRings[0]; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "FilBlk", adapter, adapter->RcvBuffersOnCard, @@ -3429,8 +4222,10 @@ static int sxg_fill_descriptor_block(struct adapter_t *adapter, ASSERT(RcvDescriptorBlockHdr); - /* If we don't have the resources to fill the descriptor block, */ - /* return failure */ + /* + * If we don't have the resources to fill the descriptor block, + * return failure + */ if ((adapter->FreeRcvBufferCount < SXG_RCV_DESCRIPTORS_PER_BLOCK) || SXG_RING_FULL(RcvRingInfo)) { adapter->Stats.NoMem++; @@ -3441,27 +4236,40 @@ static int sxg_fill_descriptor_block(struct adapter_t *adapter, RcvRingInfo, RingDescriptorCmd, RcvDescriptorBlockHdr); ASSERT(RingDescriptorCmd); RcvDescriptorBlockHdr->State = SXG_BUFFER_ONCARD; - RcvDescriptorBlock = - (struct SXG_RCV_DESCRIPTOR_BLOCK*) RcvDescriptorBlockHdr->VirtualAddress; + RcvDescriptorBlock = (struct sxg_rcv_descriptor_block *) + RcvDescriptorBlockHdr->VirtualAddress; /* Fill in the descriptor block */ for (i = 0; i < SXG_RCV_DESCRIPTORS_PER_BLOCK; i++) { SXG_GET_RCV_DATA_BUFFER(adapter, RcvDataBufferHdr); ASSERT(RcvDataBufferHdr); +// ASSERT(RcvDataBufferHdr->SxgDumbRcvPacket); + if (!RcvDataBufferHdr->SxgDumbRcvPacket) { + SXG_ALLOCATE_RCV_PACKET(adapter, RcvDataBufferHdr, + adapter->ReceiveBufferSize); + if(RcvDataBufferHdr->skb) + RcvDataBufferHdr->SxgDumbRcvPacket = + RcvDataBufferHdr->skb; + else + goto no_memory; + } SXG_REINIATIALIZE_PACKET(RcvDataBufferHdr->SxgDumbRcvPacket); RcvDataBufferHdr->State = SXG_BUFFER_ONCARD; RcvDescriptorBlock->Descriptors[i].VirtualAddress = - (void *)RcvDataBufferHdr; + (void *)RcvDataBufferHdr; + RcvDescriptorBlock->Descriptors[i].PhysicalAddress = RcvDataBufferHdr->PhysicalAddress; } /* Add the descriptor block to receive descriptor ring 0 */ RingDescriptorCmd->Sgl = RcvDescriptorBlockHdr->PhysicalAddress; - /* RcvBuffersOnCard is not protected via the receive lock (see */ - /* sxg_process_event_queue) We don't want to grap a lock every time a */ - /* buffer is returned to us, so we use atomic interlocked functions */ - /* instead. */ + /* + * RcvBuffersOnCard is not protected via the receive lock (see + * sxg_process_event_queue) We don't want to grap a lock every time a + * buffer is returned to us, so we use atomic interlocked functions + * instead. + */ adapter->RcvBuffersOnCard += SXG_RCV_DESCRIPTORS_PER_BLOCK; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "DscBlk", @@ -3473,6 +4281,23 @@ static int sxg_fill_descriptor_block(struct adapter_t *adapter, adapter, adapter->RcvBuffersOnCard, adapter->FreeRcvBufferCount, adapter->AllRcvBlockCount); return (STATUS_SUCCESS); +no_memory: + for (; i >= 0 ; i--) { + if (RcvDescriptorBlock->Descriptors[i].VirtualAddress) { + RcvDataBufferHdr = (struct sxg_rcv_data_buffer_hdr *) + RcvDescriptorBlock->Descriptors[i]. + VirtualAddress; + RcvDescriptorBlock->Descriptors[i].PhysicalAddress = + (dma_addr_t)NULL; + RcvDescriptorBlock->Descriptors[i].VirtualAddress=NULL; + } + SXG_FREE_RCV_DATA_BUFFER(adapter, RcvDataBufferHdr); + } + RcvDescriptorBlockHdr->State = SXG_BUFFER_FREE; + SXG_RETURN_CMD(RingZero, RcvRingInfo, RingDescriptorCmd, + RcvDescriptorBlockHdr); + + return (-ENOMEM); } /* @@ -3486,34 +4311,42 @@ static int sxg_fill_descriptor_block(struct adapter_t *adapter, */ static void sxg_stock_rcv_buffers(struct adapter_t *adapter) { - struct SXG_RCV_DESCRIPTOR_BLOCK_HDR *RcvDescriptorBlockHdr; + struct sxg_rcv_descriptor_block_hdr *RcvDescriptorBlockHdr; + int sxg_rcv_data_buffers = SXG_RCV_DATA_BUFFERS; + int sxg_min_rcv_data_buffers = SXG_MIN_RCV_DATA_BUFFERS; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "StockBuf", adapter, adapter->RcvBuffersOnCard, adapter->FreeRcvBufferCount, adapter->AllRcvBlockCount); - /* First, see if we've got less than our minimum threshold of */ - /* receive buffers, there isn't an allocation in progress, and */ - /* we haven't exceeded our maximum.. get another block of buffers */ - /* None of this needs to be SMP safe. It's round numbers. */ - if ((adapter->FreeRcvBufferCount < SXG_MIN_RCV_DATA_BUFFERS) && + /* + * First, see if we've got less than our minimum threshold of + * receive buffers, there isn't an allocation in progress, and + * we haven't exceeded our maximum.. get another block of buffers + * None of this needs to be SMP safe. It's round numbers. + */ + if (adapter->JumboEnabled == TRUE) + sxg_min_rcv_data_buffers = SXG_MIN_JUMBO_RCV_DATA_BUFFERS; + if ((adapter->FreeRcvBufferCount < sxg_min_rcv_data_buffers) && (adapter->AllRcvBlockCount < SXG_MAX_RCV_BLOCKS) && - (adapter->AllocationsPending == 0)) { + (atomic_read(&adapter->pending_allocations) == 0)) { sxg_allocate_buffer_memory(adapter, - SXG_RCV_BLOCK_SIZE(adapter-> - ReceiveBufferSize), + SXG_RCV_BLOCK_SIZE + (SXG_RCV_DATA_HDR_SIZE), SXG_BUFFER_TYPE_RCV); } /* Now grab the RcvQLock lock and proceed */ spin_lock(&adapter->RcvQLock); - while (adapter->RcvBuffersOnCard < SXG_RCV_DATA_BUFFERS) { - struct LIST_ENTRY *_ple; + if (adapter->JumboEnabled) + sxg_rcv_data_buffers = SXG_JUMBO_RCV_DATA_BUFFERS; + while (adapter->RcvBuffersOnCard < sxg_rcv_data_buffers) { + struct list_entry *_ple; /* Get a descriptor block */ RcvDescriptorBlockHdr = NULL; if (adapter->FreeRcvBlockCount) { _ple = RemoveHeadList(&adapter->FreeRcvBlocks); RcvDescriptorBlockHdr = - container_of(_ple, struct SXG_RCV_DESCRIPTOR_BLOCK_HDR, + container_of(_ple, struct sxg_rcv_descriptor_block_hdr, FreeList); adapter->FreeRcvBlockCount--; RcvDescriptorBlockHdr->State = SXG_BUFFER_BUSY; @@ -3553,10 +4386,10 @@ static void sxg_stock_rcv_buffers(struct adapter_t *adapter) static void sxg_complete_descriptor_blocks(struct adapter_t *adapter, unsigned char Index) { - struct SXG_RCV_RING *RingZero = &adapter->RcvRings[0]; - struct SXG_RING_INFO *RcvRingInfo = &adapter->RcvRingZeroInfo; - struct SXG_RCV_DESCRIPTOR_BLOCK_HDR *RcvDescriptorBlockHdr; - struct SXG_CMD *RingDescriptorCmd; + struct sxg_rcv_ring *RingZero = &adapter->RcvRings[0]; + struct sxg_ring_info *RcvRingInfo = &adapter->RcvRingZeroInfo; + struct sxg_rcv_descriptor_block_hdr *RcvDescriptorBlockHdr; + struct sxg_cmd *RingDescriptorCmd; SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "CmpRBlks", adapter, Index, RcvRingInfo->Head, RcvRingInfo->Tail); @@ -3564,12 +4397,13 @@ static void sxg_complete_descriptor_blocks(struct adapter_t *adapter, /* Now grab the RcvQLock lock and proceed */ spin_lock(&adapter->RcvQLock); ASSERT(Index != RcvRingInfo->Tail); - while (RcvRingInfo->Tail != Index) { - /* */ - /* Locate the current Cmd (ring descriptor entry), and */ - /* associated receive descriptor block, and advance */ - /* the tail */ - /* */ + while (sxg_ring_get_forward_diff(RcvRingInfo, Index, + RcvRingInfo->Tail) > 3) { + /* + * Locate the current Cmd (ring descriptor entry), and + * associated receive descriptor block, and advance + * the tail + */ SXG_RETURN_CMD(RingZero, RcvRingInfo, RingDescriptorCmd, RcvDescriptorBlockHdr); @@ -3579,23 +4413,66 @@ static void sxg_complete_descriptor_blocks(struct adapter_t *adapter, /* Clear the SGL field */ RingDescriptorCmd->Sgl = 0; - /* Attempt to refill it and hand it right back to the */ - /* card. If we fail to refill it, free the descriptor block */ - /* header. The card will be restocked later via the */ - /* RcvBuffersOnCard test */ - if (sxg_fill_descriptor_block(adapter, RcvDescriptorBlockHdr) == - STATUS_FAILURE) { + /* + * Attempt to refill it and hand it right back to the + * card. If we fail to refill it, free the descriptor block + * header. The card will be restocked later via the + * RcvBuffersOnCard test + */ + if (sxg_fill_descriptor_block(adapter, + RcvDescriptorBlockHdr) == STATUS_FAILURE) SXG_FREE_RCV_DESCRIPTOR_BLOCK(adapter, RcvDescriptorBlockHdr); - } } spin_unlock(&adapter->RcvQLock); SXG_TRACE(TRACE_SXG, SxgTraceBuffer, TRACE_NOISY, "XCRBlks", adapter, Index, RcvRingInfo->Head, RcvRingInfo->Tail); } +/* + * Read the statistics which the card has been maintaining. + */ +void sxg_collect_statistics(struct adapter_t *adapter) +{ + if(adapter->ucode_stats) + WRITE_REG64(adapter, adapter->UcodeRegs[0].GetUcodeStats, + adapter->pucode_stats, 0); + adapter->stats.rx_fifo_errors = adapter->ucode_stats->ERDrops; + adapter->stats.rx_over_errors = adapter->ucode_stats->NBDrops; + adapter->stats.tx_fifo_errors = adapter->ucode_stats->XDrops; +} + +static struct net_device_stats *sxg_get_stats(struct net_device * dev) +{ + struct adapter_t *adapter = netdev_priv(dev); + + sxg_collect_statistics(adapter); + return (&adapter->stats); +} + +static void sxg_watchdog(unsigned long data) +{ + struct adapter_t *adapter = (struct adapter_t *) data; + + if (adapter->state != ADAPT_DOWN) { + sxg_link_event(adapter); + /* Reset the timer */ + mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ)); + } +} + +static void sxg_update_link_status (struct work_struct *work) +{ + struct adapter_t *adapter = (struct adapter_t *)container_of + (work, struct adapter_t, update_link_status); + if (likely(adapter->link_status_changed)) { + sxg_link_event(adapter); + adapter->link_status_changed = 0; + } +} + static struct pci_driver sxg_driver = { - .name = DRV_NAME, + .name = sxg_driver_name, .id_table = sxg_pci_tbl, .probe = sxg_entry_probe, .remove = sxg_entry_remove, @@ -3603,7 +4480,7 @@ static struct pci_driver sxg_driver = { .suspend = sxgpm_suspend, .resume = sxgpm_resume, #endif -/* .shutdown = slic_shutdown, MOOK_INVESTIGATE */ + /* .shutdown = slic_shutdown, MOOK_INVESTIGATE */ }; static int __init sxg_module_init(void) |