diff options
Diffstat (limited to 'drivers/staging/wlags49_h2/wl_pci.c')
-rw-r--r-- | drivers/staging/wlags49_h2/wl_pci.c | 1581 |
1 files changed, 1581 insertions, 0 deletions
diff --git a/drivers/staging/wlags49_h2/wl_pci.c b/drivers/staging/wlags49_h2/wl_pci.c new file mode 100644 index 00000000000..a3db111d4a9 --- /dev/null +++ b/drivers/staging/wlags49_h2/wl_pci.c @@ -0,0 +1,1581 @@ +/******************************************************************************* + * Agere Systems Inc. + * Wireless device driver for Linux (wlags49). + * + * Copyright (c) 1998-2003 Agere Systems Inc. + * All rights reserved. + * http://www.agere.com + * + * Initially developed by TriplePoint, Inc. + * http://www.triplepoint.com + * + *------------------------------------------------------------------------------ + * + * This file contains processing and initialization specific to PCI/miniPCI + * devices. + * + *------------------------------------------------------------------------------ + * + * SOFTWARE LICENSE + * + * This software is provided subject to the following terms and conditions, + * which you should read carefully before using the software. Using this + * software indicates your acceptance of these terms and conditions. If you do + * not agree with these terms and conditions, do not use the software. + * + * Copyright © 2003 Agere Systems Inc. + * All rights reserved. + * + * Redistribution and use in source or binary forms, with or without + * modifications, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following Disclaimer as comments in the code as + * well as in the documentation and/or other materials provided with the + * distribution. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following Disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name of Agere Systems Inc. nor the names of the contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * Disclaimer + * + * THIS SOFTWARE IS PROVIDED “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, INFRINGEMENT AND THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ANY + * USE, MODIFICATION OR DISTRIBUTION OF THIS SOFTWARE IS SOLELY AT THE USERS OWN + * RISK. IN NO EVENT SHALL AGERE SYSTEMS INC. OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, INCLUDING, BUT NOT LIMITED TO, CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + ******************************************************************************/ + +/******************************************************************************* + * include files + ******************************************************************************/ +#include <wireless/wl_version.h> + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/ctype.h> +#include <linux/string.h> +//#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/in.h> +#include <linux/delay.h> +#include <asm/system.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/bitops.h> +#include <asm/uaccess.h> + +#include <linux/ethtool.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/ioport.h> + +#include <hcf/debug.h> + +#include <hcf.h> +#include <dhf.h> +#include <hcfdef.h> + +#include <wireless/wl_if.h> +#include <wireless/wl_internal.h> +#include <wireless/wl_util.h> +#include <wireless/wl_main.h> +#include <wireless/wl_netdev.h> +#include <wireless/wl_pci.h> + + +/******************************************************************************* + * global variables + ******************************************************************************/ +#if DBG +extern dbg_info_t *DbgInfo; +#endif // DBG + +/* define the PCI device Table Cardname and id tables */ +enum hermes_pci_versions { + CH_Agere_Systems_Mini_PCI_V1 = 0, +}; + +static struct pci_device_id wl_pci_tbl[] __devinitdata = { + { WL_LKM_PCI_VENDOR_ID, WL_LKM_PCI_DEVICE_ID_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Agere_Systems_Mini_PCI_V1 }, + { WL_LKM_PCI_VENDOR_ID, WL_LKM_PCI_DEVICE_ID_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Agere_Systems_Mini_PCI_V1 }, + { WL_LKM_PCI_VENDOR_ID, WL_LKM_PCI_DEVICE_ID_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_Agere_Systems_Mini_PCI_V1 }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(pci, wl_pci_tbl); + +/******************************************************************************* + * function prototypes + ******************************************************************************/ +int __devinit wl_pci_probe( struct pci_dev *pdev, + const struct pci_device_id *ent ); +void __devexit wl_pci_remove(struct pci_dev *pdev); +int wl_pci_setup( struct pci_dev *pdev ); +void wl_pci_enable_cardbus_interrupts( struct pci_dev *pdev ); + +#ifdef ENABLE_DMA +int wl_pci_dma_alloc( struct pci_dev *pdev, struct wl_private *lp ); +int wl_pci_dma_free( struct pci_dev *pdev, struct wl_private *lp ); +int wl_pci_dma_alloc_tx_packet( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT **desc ); +int wl_pci_dma_free_tx_packet( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT **desc ); +int wl_pci_dma_alloc_rx_packet( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT **desc ); +int wl_pci_dma_free_rx_packet( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT **desc ); +int wl_pci_dma_alloc_desc_and_buf( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT **desc, int size ); +int wl_pci_dma_free_desc_and_buf( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT **desc ); +int wl_pci_dma_alloc_desc( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT **desc ); +int wl_pci_dma_free_desc( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT **desc ); +int wl_pci_dma_alloc_buf( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT *desc, int size ); +int wl_pci_dma_free_buf( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT *desc ); + +void wl_pci_dma_hcf_reclaim_rx( struct wl_private *lp ); +#endif // ENABLE_DMA + +/******************************************************************************* + * PCI module function registration + ******************************************************************************/ +static struct pci_driver wl_driver = +{ + name: MODULE_NAME, + id_table: wl_pci_tbl, + probe: wl_pci_probe, + remove: __devexit_p(wl_pci_remove), + suspend: NULL, + resume: NULL, +}; + +/******************************************************************************* + * wl_adapter_init_module() + ******************************************************************************* + * + * DESCRIPTION: + * + * Called by init_module() to perform PCI-specific driver initialization. + * + * PARAMETERS: + * + * N/A + * + * RETURNS: + * + * 0 + * + ******************************************************************************/ +int wl_adapter_init_module( void ) +{ + int result; + /*------------------------------------------------------------------------*/ + + DBG_FUNC( "wl_adapter_init_module()" ); + DBG_ENTER( DbgInfo ); + DBG_TRACE( DbgInfo, "wl_adapter_init_module() -- PCI\n" ); + + result = pci_register_driver( &wl_driver ); //;?replace with pci_module_init, Rubini pg 490 + //;? why not do something with the result + + DBG_LEAVE( DbgInfo ); + return 0; +} // wl_adapter_init_module +/*============================================================================*/ + +/******************************************************************************* + * wl_adapter_cleanup_module() + ******************************************************************************* + * + * DESCRIPTION: + * + * Called by cleanup_module() to perform PCI-specific driver cleanup. + * + * PARAMETERS: + * + * N/A + * + * RETURNS: + * + * N/A + * + ******************************************************************************/ +void wl_adapter_cleanup_module( void ) +{ + //;?how comes wl_adapter_cleanup_module is located in a seemingly pci specific module + DBG_FUNC( "wl_adapter_cleanup_module" ); + DBG_ENTER( DbgInfo ); + + //;?DBG_TRACE below feels like nearly redundant in the light of DBG_ENTER above + DBG_TRACE( DbgInfo, "wl_adapter_cleanup_module() -- PCI\n" ); + + pci_unregister_driver( &wl_driver ); + + DBG_LEAVE( DbgInfo ); + return; +} // wl_adapter_cleanup_module +/*============================================================================*/ + +/******************************************************************************* + * wl_adapter_insert() + ******************************************************************************* + * + * DESCRIPTION: + * + * Called by wl_pci_probe() to continue the process of device insertion. + * + * PARAMETERS: + * + * dev - a pointer to the device's net_device structure + * + * RETURNS: + * + * TRUE or FALSE + * + ******************************************************************************/ +int wl_adapter_insert( struct net_device *dev ) +{ + int result = FALSE; + /*------------------------------------------------------------------------*/ + + DBG_FUNC( "wl_adapter_insert" ); + DBG_ENTER( DbgInfo ); + + DBG_TRACE( DbgInfo, "wl_adapter_insert() -- PCI\n" ); + + if( dev == NULL ) { + DBG_ERROR( DbgInfo, "net_device pointer is NULL!!!\n" ); + } else if( dev->priv == NULL ) { + DBG_ERROR( DbgInfo, "wl_private pointer is NULL!!!\n" ); + } else if( wl_insert( dev ) ) { /* Perform remaining device initialization */ + result = TRUE; + } else { + DBG_TRACE( DbgInfo, "wl_insert() FAILED\n" ); + } + DBG_LEAVE( DbgInfo ); + return result; +} // wl_adapter_insert +/*============================================================================*/ + +/******************************************************************************* + * wl_adapter_open() + ******************************************************************************* + * + * DESCRIPTION: + * + * Open the device. + * + * PARAMETERS: + * + * dev - a pointer to the device's net_device structure + * + * RETURNS: + * + * an HCF status code + * + ******************************************************************************/ +int wl_adapter_open( struct net_device *dev ) +{ + int result = 0; + int hcf_status = HCF_SUCCESS; + /*------------------------------------------------------------------------*/ + + DBG_FUNC( "wl_adapter_open" ); + DBG_ENTER( DbgInfo ); + + DBG_TRACE( DbgInfo, "wl_adapter_open() -- PCI\n" ); + + hcf_status = wl_open( dev ); + + if( hcf_status != HCF_SUCCESS ) { + result = -ENODEV; + } + + DBG_LEAVE( DbgInfo ); + return result; +} // wl_adapter_open +/*============================================================================*/ + +/******************************************************************************* + * wl_adapter_close() + ******************************************************************************* + * + * DESCRIPTION: + * + * Close the device + * + * PARAMETERS: + * + * dev - a pointer to the device's net_device structure + * + * RETURNS: + * + * 0 + * + ******************************************************************************/ +int wl_adapter_close( struct net_device *dev ) +{ + DBG_FUNC( "wl_adapter_close" ); + DBG_ENTER( DbgInfo ); + + DBG_TRACE( DbgInfo, "wl_adapter_close() -- PCI\n" ); + DBG_TRACE( DbgInfo, "%s: Shutting down adapter.\n", dev->name ); + + wl_close( dev ); + + DBG_LEAVE( DbgInfo ); + return 0; +} // wl_adapter_close +/*============================================================================*/ + +/******************************************************************************* + * wl_adapter_is_open() + ******************************************************************************* + * + * DESCRIPTION: + * + * Check whether this device is open. Returns + * + * PARAMETERS: + * + * dev - a pointer to the device's net_device structure + * + * RETURNS: + * + * nonzero if device is open. + * + ******************************************************************************/ +int wl_adapter_is_open( struct net_device *dev ) +{ + /* This function is used in PCMCIA to check the status of the 'open' field + in the dev_link_t structure associated with a network device. There + doesn't seem to be an analog to this for PCI, and checking the status + contained in the net_device structure doesn't have the same effect. + For now, return TRUE, but find out if this is necessary for PCI. */ + + return TRUE; +} // wl_adapter_is_open +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_probe() + ******************************************************************************* + * + * DESCRIPTION: + * + * Registered in the pci_driver structure, this function is called when the + * PCI subsystem finds a new PCI device which matches the infomation contained + * in the pci_device_id table. + * + * PARAMETERS: + * + * pdev - a pointer to the device's pci_dev structure + * ent - this device's entry in the pci_device_id table + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +int __devinit wl_pci_probe( struct pci_dev *pdev, + const struct pci_device_id *ent ) +{ + int result; + /*------------------------------------------------------------------------*/ + + DBG_FUNC( "wl_pci_probe" ); + DBG_ENTER( DbgInfo ); + DBG_PRINT( "%s\n", VERSION_INFO ); + + result = wl_pci_setup( pdev ); + + DBG_LEAVE( DbgInfo ); + + return result; +} // wl_pci_probe +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_remove() + ******************************************************************************* + * + * DESCRIPTION: + * + * Registered in the pci_driver structure, this function is called when the + * PCI subsystem detects that a PCI device which matches the infomation + * contained in the pci_device_id table has been removed. + * + * PARAMETERS: + * + * pdev - a pointer to the device's pci_dev structure + * + * RETURNS: + * + * N/A + * + ******************************************************************************/ +void __devexit wl_pci_remove(struct pci_dev *pdev) +{ + struct net_device *dev = NULL; + /*------------------------------------------------------------------------*/ + + DBG_FUNC( "wl_pci_remove" ); + DBG_ENTER( DbgInfo ); + + /* Make sure the pci_dev pointer passed in is valid */ + if( pdev == NULL ) { + DBG_ERROR( DbgInfo, "PCI subsys passed in an invalid pci_dev pointer\n" ); + return; + } + + dev = (struct net_device *)pci_get_drvdata( pdev ); + if( dev == NULL ) { + DBG_ERROR( DbgInfo, "Could not retrieve net_device structure\n" ); + return; + } + + /* Perform device cleanup */ + wl_remove( dev ); + free_irq( dev->irq, dev ); + +#ifdef ENABLE_DMA + wl_pci_dma_free( pdev, (struct wl_private *)dev->priv ); +#endif + + wl_device_dealloc( dev ); + + DBG_LEAVE( DbgInfo ); + return; +} // wl_pci_remove +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_setup() + ******************************************************************************* + * + * DESCRIPTION: + * + * Called by wl_pci_probe() to begin a device's initialization process. + * + * PARAMETERS: + * + * pdev - a pointer to the device's pci_dev structure + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +int wl_pci_setup( struct pci_dev *pdev ) +{ + int result = 0; + struct net_device *dev = NULL; + struct wl_private *lp = NULL; + /*------------------------------------------------------------------------*/ + + DBG_FUNC( "wl_pci_setup" ); + DBG_ENTER( DbgInfo ); + + /* Make sure the pci_dev pointer passed in is valid */ + if( pdev == NULL ) { + DBG_ERROR( DbgInfo, "PCI subsys passed in an invalid pci_dev pointer\n" ); + return -ENODEV; + } + + result = pci_enable_device( pdev ); + if( result != 0 ) { + DBG_ERROR( DbgInfo, "pci_enable_device() failed\n" ); + DBG_LEAVE( DbgInfo ); + return result; + } + + /* We found our device! Let's register it with the system */ + DBG_TRACE( DbgInfo, "Found our device, now registering\n" ); + dev = wl_device_alloc( ); + if( dev == NULL ) { + DBG_ERROR( DbgInfo, "Could not register device!!!\n" ); + DBG_LEAVE( DbgInfo ); + return -ENOMEM; + } + + /* Make sure that space was allocated for our private adapter struct */ + if( dev->priv == NULL ) { + DBG_ERROR( DbgInfo, "Private adapter struct was not allocated!!!\n" ); + DBG_LEAVE( DbgInfo ); + return -ENOMEM; + } + +#ifdef ENABLE_DMA + /* Allocate DMA Descriptors */ + if( wl_pci_dma_alloc( pdev, (struct wl_private *)dev->priv ) < 0 ) { + DBG_ERROR( DbgInfo, "Could not allocate DMA descriptor memory!!!\n" ); + DBG_LEAVE( DbgInfo ); + return -ENOMEM; + } +#endif + + /* Register our private adapter structure with PCI */ + pci_set_drvdata( pdev, dev ); + + /* Fill out bus specific information in the net_device struct */ + dev->irq = pdev->irq; + SET_MODULE_OWNER( dev ); + + DBG_TRACE( DbgInfo, "Device Base Address: %#03lx\n", pdev->resource[0].start ); + dev->base_addr = pdev->resource[0].start; + + /* Initialize our device here */ + if( !wl_adapter_insert( dev )) { + DBG_ERROR( DbgInfo, "wl_adapter_insert() FAILED!!!\n" ); + wl_device_dealloc( dev ); + DBG_LEAVE( DbgInfo ); + return -EINVAL; + } + + /* Register our ISR */ + DBG_TRACE( DbgInfo, "Registering ISR...\n" ); + + result = request_irq(dev->irq, wl_isr, SA_SHIRQ, dev->name, dev); + if( result ) { + DBG_WARNING( DbgInfo, "Could not register ISR!!!\n" ); + DBG_LEAVE( DbgInfo ); + return result; + } + + /* Make sure interrupts are enabled properly for CardBus */ + lp = (struct wl_private *)dev->priv; + + if( lp->hcfCtx.IFB_BusType == CFG_NIC_BUS_TYPE_CARDBUS || + lp->hcfCtx.IFB_BusType == CFG_NIC_BUS_TYPE_PCI ) { + DBG_TRACE( DbgInfo, "This is a PCI/CardBus card, enable interrupts\n" ); + wl_pci_enable_cardbus_interrupts( pdev ); + } + + /* Enable bus mastering */ + pci_set_master( pdev ); + + DBG_LEAVE( DbgInfo ); + return 0; +} // wl_pci_setup +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_enable_cardbus_interrupts() + ******************************************************************************* + * + * DESCRIPTION: + * + * Called by wl_pci_setup() to enable interrupts on a CardBus device. This + * is done by writing bit 15 to the function event mask register. This + * CardBus-specific register is located in BAR2 (counting from BAR0), in memory + * space at byte offset 1f4 (7f4 for WARP). + * + * PARAMETERS: + * + * pdev - a pointer to the device's pci_dev structure + * + * RETURNS: + * + * N/A + * + ******************************************************************************/ +void wl_pci_enable_cardbus_interrupts( struct pci_dev *pdev ) +{ + u32 bar2_reg; + u32 mem_addr_bus; + u32 func_evt_mask_reg; + void *mem_addr_kern = NULL; + /*------------------------------------------------------------------------*/ + + DBG_FUNC( "wl_pci_enable_cardbus_interrupts" ); + DBG_ENTER( DbgInfo ); + + /* Initialize to known bad values */ + bar2_reg = 0xdeadbeef; + mem_addr_bus = 0xdeadbeef; + + /* Read the BAR2 register; this register contains the base address of the + memory region where the function event mask register lives */ + pci_read_config_dword( pdev, PCI_BASE_ADDRESS_2, &bar2_reg ); + mem_addr_bus = bar2_reg & PCI_BASE_ADDRESS_MEM_MASK; + + /* Once the base address is obtained, remap the memory region to kernel + space so we can retrieve the register */ + mem_addr_kern = ioremap( mem_addr_bus, 0x200 ); + +#ifdef HERMES25 +#define REG_OFFSET 0x07F4 +#else +#define REG_OFFSET 0x01F4 +#endif // HERMES25 + +#define BIT15 0x8000 + + /* Retrieve the functional event mask register, enable interrupts by + setting Bit 15, and write back the value */ + func_evt_mask_reg = *(u32 *)( mem_addr_kern + REG_OFFSET ); + func_evt_mask_reg |= BIT15; + *(u32 *)( mem_addr_kern + REG_OFFSET ) = func_evt_mask_reg; + + /* Once complete, unmap the region and exit */ + iounmap( mem_addr_kern ); + + DBG_LEAVE( DbgInfo ); + return; +} // wl_pci_enable_cardbus_interrupts +/*============================================================================*/ + +#ifdef ENABLE_DMA +/******************************************************************************* + * wl_pci_dma_alloc() + ******************************************************************************* + * + * DESCRIPTION: + * + * Allocates all resources needed for PCI/CardBus DMA operation + * + * PARAMETERS: + * + * pdev - a pointer to the device's pci_dev structure + * lp - the device's private adapter structure + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +int wl_pci_dma_alloc( struct pci_dev *pdev, struct wl_private *lp ) +{ + int i; + int status = 0; + /*------------------------------------------------------------------------*/ + + DBG_FUNC( "wl_pci_dma_alloc" ); + DBG_ENTER( DbgInfo ); + +// lp->dma.tx_rsc_ind = lp->dma.rx_rsc_ind = 0; +// +// /* Alloc for the Tx chain and its reclaim descriptor */ +// for( i = 0; i < NUM_TX_DESC; i++ ) { +// status = wl_pci_dma_alloc_tx_packet( pdev, lp, &lp->dma.tx_packet[i] ); +// if( status == 0 ) { +// DBG_PRINT( "lp->dma.tx_packet[%d] : 0x%p\n", i, lp->dma.tx_packet[i] ); +// DBG_PRINT( "lp->dma.tx_packet[%d]->next_desc_addr : 0x%p\n", i, lp->dma.tx_packet[i]->next_desc_addr ); +// lp->dma.tx_rsc_ind++; +// } else { +// DBG_ERROR( DbgInfo, "Could not alloc DMA Tx Packet\n" ); +// break; +// } +// } +// if( status == 0 ) { +// status = wl_pci_dma_alloc_desc( pdev, lp, &lp->dma.tx_reclaim_desc ); +// DBG_PRINT( "lp->dma.tx_reclaim_desc: 0x%p\n", lp->dma.tx_reclaim_desc ); +// } +// /* Alloc for the Rx chain and its reclaim descriptor */ +// if( status == 0 ) { +// for( i = 0; i < NUM_RX_DESC; i++ ) { +// status = wl_pci_dma_alloc_rx_packet( pdev, lp, &lp->dma.rx_packet[i] ); +// if( status == 0 ) { +// DBG_PRINT( "lp->dma.rx_packet[%d] : 0x%p\n", i, lp->dma.rx_packet[i] ); +// DBG_PRINT( "lp->dma.rx_packet[%d]->next_desc_addr : 0x%p\n", i, lp->dma.rx_packet[i]->next_desc_addr ); +// lp->dma.rx_rsc_ind++; +// } else { +// DBG_ERROR( DbgInfo, "Could not alloc DMA Rx Packet\n" ); +// break; +// } +// } +// } +// if( status == 0 ) { +// status = wl_pci_dma_alloc_desc( pdev, lp, &lp->dma.rx_reclaim_desc ); +// DBG_PRINT( "lp->dma.rx_reclaim_desc: 0x%p\n", lp->dma.rx_reclaim_desc ); +// } +// /* Store status, as host should not call HCF functions if this fails */ +// lp->dma.status = status; //;?all useages of dma.status have been commented out +// DBG_LEAVE( DbgInfo ); + return status; +} // wl_pci_dma_alloc +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_free() + ******************************************************************************* + * + * DESCRIPTION: + * + * Deallocated all resources needed for PCI/CardBus DMA operation + * + * PARAMETERS: + * + * pdev - a pointer to the device's pci_dev structure + * lp - the device's private adapter structure + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +int wl_pci_dma_free( struct pci_dev *pdev, struct wl_private *lp ) +{ + int i; + int status = 0; + /*------------------------------------------------------------------------*/ + + DBG_FUNC( "wl_pci_dma_free" ); + DBG_ENTER( DbgInfo ); + + /* Reclaim all Rx packets that were handed over to the HCF */ + /* Do I need to do this? Before this free is called, I've already disabled + the port which will call wl_pci_dma_hcf_reclaim */ + //if( lp->dma.status == 0 ) + //{ + // wl_pci_dma_hcf_reclaim( lp ); + //} + + /* Free everything needed for DMA Rx */ + for( i = 0; i < NUM_RX_DESC; i++ ) { + if( lp->dma.rx_packet[i] ) { + status = wl_pci_dma_free_rx_packet( pdev, lp, &lp->dma.rx_packet[i] ); + if( status != 0 ) { + DBG_WARNING( DbgInfo, "Problem freeing Rx packet\n" ); + } + } + } + lp->dma.rx_rsc_ind = 0; + + if( lp->dma.rx_reclaim_desc ) { + status = wl_pci_dma_free_desc( pdev, lp, &lp->dma.rx_reclaim_desc ); + if( status != 0 ) { + DBG_WARNING( DbgInfo, "Problem freeing Rx reclaim descriptor\n" ); + } + } + + /* Free everything needed for DMA Tx */ + for( i = 0; i < NUM_TX_DESC; i++ ) { + if( lp->dma.tx_packet[i] ) { + status = wl_pci_dma_free_tx_packet( pdev, lp, &lp->dma.tx_packet[i] ); + if( status != 0 ) { + DBG_WARNING( DbgInfo, "Problem freeing Tx packet\n" ); + } + } + } + lp->dma.tx_rsc_ind = 0; + + if( lp->dma.tx_reclaim_desc ) { + status = wl_pci_dma_free_desc( pdev, lp, &lp->dma.tx_reclaim_desc ); + if( status != 0 ) { + DBG_WARNING( DbgInfo, "Problem freeing Tx reclaim descriptor\n" ); + } + } + + DBG_LEAVE( DbgInfo ); + return status; +} // wl_pci_dma_free + +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_alloc_tx_packet() + ******************************************************************************* + * + * DESCRIPTION: + * + * Allocates a single Tx packet, consisting of several descriptors and + * buffers. Data to transmit is first copied into the 'payload' buffer + * before being transmitted. + * + * PARAMETERS: + * + * pdev - a pointer to the device's pci_dev structure + * lp - the device's private adapter structure + * desc - a pointer which will reference the descriptor to be alloc'd. + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +int wl_pci_dma_alloc_tx_packet( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT **desc ) +{ +// int status = 0; +// /*------------------------------------------------------------------------*/ +// +// if( desc == NULL ) { +// status = -EFAULT; +// } +// if( status == 0 ) { +// status = wl_pci_dma_alloc_desc_and_buf( pdev, lp, desc, +// HCF_DMA_TX_BUF1_SIZE ); +// +// if( status == 0 ) { +// status = wl_pci_dma_alloc_desc_and_buf( pdev, lp, +// &( (*desc)->next_desc_addr ), +// HCF_MAX_PACKET_SIZE ); +// } +// } +// if( status == 0 ) { +// (*desc)->next_desc_phys_addr = (*desc)->next_desc_addr->desc_phys_addr; +// } +// return status; +} // wl_pci_dma_alloc_tx_packet +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_free_tx_packet() + ******************************************************************************* + * + * DESCRIPTION: + * + * Frees a single Tx packet, described in the corresponding alloc function. + * + * PARAMETERS: + * + * pdev - a pointer to the device's pci_dev structure + * lp - the device's private adapter structure + * desc - a pointer which will reference the descriptor to be alloc'd. + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +int wl_pci_dma_free_tx_packet( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT **desc ) +{ + int status = 0; + /*------------------------------------------------------------------------*/ + + if( *desc == NULL ) { + DBG_PRINT( "Null descriptor\n" ); + status = -EFAULT; + } + //;?the "limited" NDIS strategy, assuming a frame consists ALWAYS out of 2 + //descriptors, make this robust + if( status == 0 && (*desc)->next_desc_addr ) { + status = wl_pci_dma_free_desc_and_buf( pdev, lp, &(*desc)->next_desc_addr ); + } + if( status == 0 ) { + status = wl_pci_dma_free_desc_and_buf( pdev, lp, desc ); + } + return status; +} // wl_pci_dma_free_tx_packet +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_alloc_rx_packet() + ******************************************************************************* + * + * DESCRIPTION: + * + * Allocates a single Rx packet, consisting of two descriptors and one + * contiguous buffer. THe buffer starts with the hermes-specific header. + * One descriptor points at the start, the other at offset 0x3a of the + * buffer. + * + * PARAMETERS: + * + * pdev - a pointer to the device's pci_dev structure + * lp - the device's private adapter structure + * desc - a pointer which will reference the descriptor to be alloc'd. + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +int wl_pci_dma_alloc_rx_packet( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT **desc ) +{ + int status = 0; + DESC_STRCT *p; + /*------------------------------------------------------------------------*/ + +// if( desc == NULL ) { +// status = -EFAULT; +// } +// //;?the "limited" NDIS strategy, assuming a frame consists ALWAYS out of 2 +// //descriptors, make this robust +// if( status == 0 ) { +// status = wl_pci_dma_alloc_desc( pdev, lp, desc ); +// } +// if( status == 0 ) { +// status = wl_pci_dma_alloc_buf( pdev, lp, *desc, HCF_MAX_PACKET_SIZE ); +// } +// if( status == 0 ) { +// status = wl_pci_dma_alloc_desc( pdev, lp, &p ); +// } +// if( status == 0 ) { +// /* Size of 1st descriptor becomes 0x3a bytes */ +// SET_BUF_SIZE( *desc, HCF_DMA_RX_BUF1_SIZE ); +// +// /* Make 2nd descriptor point at offset 0x3a of the buffer */ +// SET_BUF_SIZE( p, ( HCF_MAX_PACKET_SIZE - HCF_DMA_RX_BUF1_SIZE )); +// p->buf_addr = (*desc)->buf_addr + HCF_DMA_RX_BUF1_SIZE; +// p->buf_phys_addr = (*desc)->buf_phys_addr + HCF_DMA_RX_BUF1_SIZE; +// p->next_desc_addr = NULL; +// +// /* Chain 2nd descriptor to 1st descriptor */ +// (*desc)->next_desc_addr = p; +// (*desc)->next_desc_phys_addr = p->desc_phys_addr; +// } + + return status; +} // wl_pci_dma_alloc_rx_packet +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_free_rx_packet() + ******************************************************************************* + * + * DESCRIPTION: + * + * Frees a single Rx packet, described in the corresponding alloc function. + * + * PARAMETERS: + * + * pdev - a pointer to the device's pci_dev structure + * lp - the device's private adapter structure + * desc - a pointer which will reference the descriptor to be alloc'd. + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +int wl_pci_dma_free_rx_packet( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT **desc ) +{ + int status = 0; + DESC_STRCT *p; + /*------------------------------------------------------------------------*/ + + if( *desc == NULL ) { + status = -EFAULT; + } + if( status == 0 ) { + p = (*desc)->next_desc_addr; + + /* Free the 2nd descriptor */ + if( p != NULL ) { + p->buf_addr = NULL; + p->buf_phys_addr = 0; + + status = wl_pci_dma_free_desc( pdev, lp, &p ); + } + } + + /* Free the buffer and 1st descriptor */ + if( status == 0 ) { + SET_BUF_SIZE( *desc, HCF_MAX_PACKET_SIZE ); + status = wl_pci_dma_free_desc_and_buf( pdev, lp, desc ); + } + return status; +} // wl_pci_dma_free_rx_packet +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_alloc_desc_and_buf() + ******************************************************************************* + * + * DESCRIPTION: + * + * Allocates a DMA descriptor and buffer, and associates them with one + * another. + * + * PARAMETERS: + * + * pdev - a pointer to the device's pci_dev structure + * lp - the device's private adapter structure + * desc - a pointer which will reference the descriptor to be alloc'd + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +int wl_pci_dma_alloc_desc_and_buf( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT **desc, int size ) +{ + int status = 0; + /*------------------------------------------------------------------------*/ + +// if( desc == NULL ) { +// status = -EFAULT; +// } +// if( status == 0 ) { +// status = wl_pci_dma_alloc_desc( pdev, lp, desc ); +// +// if( status == 0 ) { +// status = wl_pci_dma_alloc_buf( pdev, lp, *desc, size ); +// } +// } + return status; +} // wl_pci_dma_alloc_desc_and_buf +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_free_desc_and_buf() + ******************************************************************************* + * + * DESCRIPTION: + * + * Frees a DMA descriptor and associated buffer. + * + * PARAMETERS: + * + * pdev - a pointer to the device's pci_dev structure + * lp - the device's private adapter structure + * desc - a pointer which will reference the descriptor to be alloc'd + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +int wl_pci_dma_free_desc_and_buf( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT **desc ) +{ + int status = 0; + /*------------------------------------------------------------------------*/ + + if( desc == NULL ) { + status = -EFAULT; + } + if( status == 0 && *desc == NULL ) { + status = -EFAULT; + } + if( status == 0 ) { + status = wl_pci_dma_free_buf( pdev, lp, *desc ); + + if( status == 0 ) { + status = wl_pci_dma_free_desc( pdev, lp, desc ); + } + } + return status; +} // wl_pci_dma_free_desc_and_buf +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_alloc_desc() + ******************************************************************************* + * + * DESCRIPTION: + * + * Allocates one DMA descriptor in cache coherent memory. + * + * PARAMETERS: + * + * pdev - a pointer to the device's pci_dev structure + * lp - the device's private adapter structure + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +int wl_pci_dma_alloc_desc( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT **desc ) +{ +// int status = 0; +// dma_addr_t pa; +// /*------------------------------------------------------------------------*/ +// +// DBG_FUNC( "wl_pci_dma_alloc_desc" ); +// DBG_ENTER( DbgInfo ); +// +// if( desc == NULL ) { +// status = -EFAULT; +// } +// if( status == 0 ) { +// *desc = pci_alloc_consistent( pdev, sizeof( DESC_STRCT ), &pa ); +// } +// if( *desc == NULL ) { +// DBG_ERROR( DbgInfo, "pci_alloc_consistent() failed\n" ); +// status = -ENOMEM; +// } else { +// memset( *desc, 0, sizeof( DESC_STRCT )); +// (*desc)->desc_phys_addr = cpu_to_le32( pa ); +// } +// DBG_LEAVE( DbgInfo ); +// return status; +} // wl_pci_dma_alloc_desc +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_free_desc() + ******************************************************************************* + * + * DESCRIPTION: + * + * Frees one DMA descriptor in cache coherent memory. + * + * PARAMETERS: + * + * pdev - a pointer to the device's pci_dev structure + * lp - the device's private adapter structure + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +int wl_pci_dma_free_desc( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT **desc ) +{ + int status = 0; + /*------------------------------------------------------------------------*/ + + if( *desc == NULL ) { + status = -EFAULT; + } + if( status == 0 ) { + pci_free_consistent( pdev, sizeof( DESC_STRCT ), *desc, + (*desc)->desc_phys_addr ); + } + *desc = NULL; + return status; +} // wl_pci_dma_free_desc +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_alloc_buf() + ******************************************************************************* + * + * DESCRIPTION: + * + * Allocates one DMA buffer in cache coherent memory, and associates a DMA + * descriptor with this buffer. + * + * PARAMETERS: + * + * pdev - a pointer to the device's pci_dev structure + * lp - the device's private adapter structure + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +int wl_pci_dma_alloc_buf( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT *desc, int size ) +{ + int status = 0; + dma_addr_t pa; + /*------------------------------------------------------------------------*/ + +// DBG_FUNC( "wl_pci_dma_alloc_buf" ); +// DBG_ENTER( DbgInfo ); +// +// if( desc == NULL ) { +// status = -EFAULT; +// } +// if( status == 0 && desc->buf_addr != NULL ) { +// status = -EFAULT; +// } +// if( status == 0 ) { +// desc->buf_addr = pci_alloc_consistent( pdev, size, &pa ); +// } +// if( desc->buf_addr == NULL ) { +// DBG_ERROR( DbgInfo, "pci_alloc_consistent() failed\n" ); +// status = -ENOMEM; +// } else { +// desc->buf_phys_addr = cpu_to_le32( pa ); +// SET_BUF_SIZE( desc, size ); +// } +// DBG_LEAVE( DbgInfo ); + return status; +} // wl_pci_dma_alloc_buf +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_free_buf() + ******************************************************************************* + * + * DESCRIPTION: + * + * Allocates one DMA buffer in cache coherent memory, and associates a DMA + * descriptor with this buffer. + * + * PARAMETERS: + * + * pdev - a pointer to the device's pci_dev structure + * lp - the device's private adapter structure + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +int wl_pci_dma_free_buf( struct pci_dev *pdev, struct wl_private *lp, + DESC_STRCT *desc ) +{ + int status = 0; + /*------------------------------------------------------------------------*/ + + if( desc == NULL ) { + status = -EFAULT; + } + if( status == 0 && desc->buf_addr == NULL ) { + status = -EFAULT; + } + if( status == 0 ) { + pci_free_consistent( pdev, GET_BUF_SIZE( desc ), desc->buf_addr, + desc->buf_phys_addr ); + + desc->buf_addr = 0; + desc->buf_phys_addr = 0; + SET_BUF_SIZE( desc, 0 ); + } + return status; +} // wl_pci_dma_free_buf +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_hcf_supply() + ******************************************************************************* + * + * DESCRIPTION: + * + * Supply HCF with DMA-related resources. These consist of: + * - buffers and descriptors for receive purposes + * - one 'reclaim' descriptor for the transmit path, used to fulfill a + * certain H25 DMA engine requirement + * - one 'reclaim' descriptor for the receive path, used to fulfill a + * certain H25 DMA engine requirement + * + * This function is called at start-of-day or at re-initialization. + * + * PARAMETERS: + * + * lp - the device's private adapter structure + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +void wl_pci_dma_hcf_supply( struct wl_private *lp ) +{ + int i; + /*------------------------------------------------------------------------*/ + + DBG_FUNC( "wl_pci_dma_hcf_supply" ); + DBG_ENTER( DbgInfo ); + + //if( lp->dma.status == 0 ); + //{ + /* Hand over the Rx/Tx reclaim descriptors to the HCF */ + if( lp->dma.tx_reclaim_desc ) { + DBG_PRINT( "lp->dma.tx_reclaim_desc: 0x%p\n", lp->dma.tx_reclaim_desc ); + hcf_dma_tx_put( &lp->hcfCtx, lp->dma.tx_reclaim_desc, 0 ); + lp->dma.tx_reclaim_desc = NULL; + DBG_PRINT( "lp->dma.tx_reclaim_desc: 0x%p\n", lp->dma.tx_reclaim_desc ); + } + if( lp->dma.rx_reclaim_desc ) { + DBG_PRINT( "lp->dma.rx_reclaim_desc: 0x%p\n", lp->dma.rx_reclaim_desc ); + hcf_dma_rx_put( &lp->hcfCtx, lp->dma.rx_reclaim_desc ); + lp->dma.rx_reclaim_desc = NULL; + DBG_PRINT( "lp->dma.rx_reclaim_desc: 0x%p\n", lp->dma.rx_reclaim_desc ); + } + /* Hand over the Rx descriptor chain to the HCF */ + for( i = 0; i < NUM_RX_DESC; i++ ) { + DBG_PRINT( "lp->dma.rx_packet[%d]: 0x%p\n", i, lp->dma.rx_packet[i] ); + hcf_dma_rx_put( &lp->hcfCtx, lp->dma.rx_packet[i] ); + lp->dma.rx_packet[i] = NULL; + DBG_PRINT( "lp->dma.rx_packet[%d]: 0x%p\n", i, lp->dma.rx_packet[i] ); + } + //} + + DBG_LEAVE( DbgInfo ); + return; +} // wl_pci_dma_hcf_supply +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_hcf_reclaim() + ******************************************************************************* + * + * DESCRIPTION: + * + * Return DMA-related resources from the HCF. These consist of: + * - buffers and descriptors for receive purposes + * - buffers and descriptors for transmit purposes + * - one 'reclaim' descriptor for the transmit path, used to fulfill a + * certain H25 DMA engine requirement + * - one 'reclaim' descriptor for the receive path, used to fulfill a + * certain H25 DMA engine requirement + * + * This function is called at end-of-day or at re-initialization. + * + * PARAMETERS: + * + * lp - the device's private adapter structure + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +void wl_pci_dma_hcf_reclaim( struct wl_private *lp ) +{ + int i; + /*------------------------------------------------------------------------*/ + + DBG_FUNC( "wl_pci_dma_hcf_reclaim" ); + DBG_ENTER( DbgInfo ); + + wl_pci_dma_hcf_reclaim_rx( lp ); + for( i = 0; i < NUM_RX_DESC; i++ ) { + DBG_PRINT( "rx_packet[%d] 0x%p\n", i, lp->dma.rx_packet[i] ); +// if( lp->dma.rx_packet[i] == NULL ) { +// DBG_PRINT( "wl_pci_dma_hcf_reclaim: rx_packet[%d] NULL\n", i ); +// } + } + + wl_pci_dma_hcf_reclaim_tx( lp ); + for( i = 0; i < NUM_TX_DESC; i++ ) { + DBG_PRINT( "tx_packet[%d] 0x%p\n", i, lp->dma.tx_packet[i] ); +// if( lp->dma.tx_packet[i] == NULL ) { +// DBG_PRINT( "wl_pci_dma_hcf_reclaim: tx_packet[%d] NULL\n", i ); +// } + } + + DBG_LEAVE( DbgInfo ); + return; +} // wl_pci_dma_hcf_reclaim +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_hcf_reclaim_rx() + ******************************************************************************* + * + * DESCRIPTION: + * + * Reclaim Rx packets that have already been processed by the HCF. + * + * PARAMETERS: + * + * lp - the device's private adapter structure + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +void wl_pci_dma_hcf_reclaim_rx( struct wl_private *lp ) +{ + int i; + DESC_STRCT *p; + /*------------------------------------------------------------------------*/ + + DBG_FUNC( "wl_pci_dma_hcf_reclaim_rx" ); + DBG_ENTER( DbgInfo ); + + //if( lp->dma.status == 0 ) + //{ + while ( ( p = hcf_dma_rx_get( &lp->hcfCtx ) ) != NULL ) { + if( p && p->buf_addr == NULL ) { + /* A reclaim descriptor is being given back by the HCF. Reclaim + descriptors have a NULL buf_addr */ + lp->dma.rx_reclaim_desc = p; + DBG_PRINT( "reclaim_descriptor: 0x%p\n", p ); + continue; + } + for( i = 0; i < NUM_RX_DESC; i++ ) { + if( lp->dma.rx_packet[i] == NULL ) { + break; + } + } + /* An Rx buffer descriptor is being given back by the HCF */ + lp->dma.rx_packet[i] = p; + lp->dma.rx_rsc_ind++; + DBG_PRINT( "rx_packet[%d] 0x%p\n", i, lp->dma.rx_packet[i] ); + } + //} + DBG_LEAVE( DbgInfo ); +} // wl_pci_dma_hcf_reclaim_rx +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_get_tx_packet() + ******************************************************************************* + * + * DESCRIPTION: + * + * Obtains a Tx descriptor from the chain to use for Tx. + * + * PARAMETERS: + * + * lp - a pointer to the device's wl_private structure. + * + * RETURNS: + * + * A pointer to the retrieved descriptor + * + ******************************************************************************/ +DESC_STRCT * wl_pci_dma_get_tx_packet( struct wl_private *lp ) +{ + int i; + DESC_STRCT *desc = NULL; + /*------------------------------------------------------------------------*/ + + for( i = 0; i < NUM_TX_DESC; i++ ) { + if( lp->dma.tx_packet[i] ) { + break; + } + } + + if( i != NUM_TX_DESC ) { + desc = lp->dma.tx_packet[i]; + + lp->dma.tx_packet[i] = NULL; + lp->dma.tx_rsc_ind--; + + memset( desc->buf_addr, 0, HCF_DMA_TX_BUF1_SIZE ); + } + + return desc; +} // wl_pci_dma_get_tx_packet +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_put_tx_packet() + ******************************************************************************* + * + * DESCRIPTION: + * + * Returns a Tx descriptor to the chain. + * + * PARAMETERS: + * + * lp - a pointer to the device's wl_private structure. + * desc - a pointer to the descriptor to return. + * + * RETURNS: + * + * N/A + * + ******************************************************************************/ +void wl_pci_dma_put_tx_packet( struct wl_private *lp, DESC_STRCT *desc ) +{ + int i; + /*------------------------------------------------------------------------*/ + + for( i = 0; i < NUM_TX_DESC; i++ ) { + if( lp->dma.tx_packet[i] == NULL ) { + break; + } + } + + if( i != NUM_TX_DESC ) { + lp->dma.tx_packet[i] = desc; + lp->dma.tx_rsc_ind++; + } +} // wl_pci_dma_put_tx_packet +/*============================================================================*/ + +/******************************************************************************* + * wl_pci_dma_hcf_reclaim_tx() + ******************************************************************************* + * + * DESCRIPTION: + * + * Reclaim Tx packets that have either been processed by the HCF due to a + * port disable or a Tx completion. + * + * PARAMETERS: + * + * lp - the device's private adapter structure + * + * RETURNS: + * + * 0 on success + * errno value otherwise + * + ******************************************************************************/ +void wl_pci_dma_hcf_reclaim_tx( struct wl_private *lp ) +{ + int i; + DESC_STRCT *p; + /*------------------------------------------------------------------------*/ + + DBG_FUNC( "wl_pci_dma_hcf_reclaim_tx" ); + DBG_ENTER( DbgInfo ); + + //if( lp->dma.status == 0 ) + //{ + while ( ( p = hcf_dma_tx_get( &lp->hcfCtx ) ) != NULL ) { + + if( p != NULL && p->buf_addr == NULL ) { + /* A Reclaim descriptor is being given back by the HCF. Reclaim + descriptors have a NULL buf_addr */ + lp->dma.tx_reclaim_desc = p; + DBG_PRINT( "reclaim_descriptor: 0x%p\n", p ); + continue; + } + for( i = 0; i < NUM_TX_DESC; i++ ) { + if( lp->dma.tx_packet[i] == NULL ) { + break; + } + } + /* An Rx buffer descriptor is being given back by the HCF */ + lp->dma.tx_packet[i] = p; + lp->dma.tx_rsc_ind++; + DBG_PRINT( "tx_packet[%d] 0x%p\n", i, lp->dma.tx_packet[i] ); + } + //} + + if( lp->netif_queue_on == FALSE ) { + netif_wake_queue( lp->dev ); + WL_WDS_NETIF_WAKE_QUEUE( lp ); + lp->netif_queue_on = TRUE; + } + DBG_LEAVE( DbgInfo ); + return; +} // wl_pci_dma_hcf_reclaim_tx +/*============================================================================*/ +#endif // ENABLE_DMA |