mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-18 08:35:03 +00:00
874 lines
25 KiB
C
874 lines
25 KiB
C
|
/*
|
||
|
*************************************************************************
|
||
|
* Ralink Tech Inc.
|
||
|
* 5F., No.36, Taiyuan St., Jhubei City,
|
||
|
* Hsinchu County 302,
|
||
|
* Taiwan, R.O.C.
|
||
|
*
|
||
|
* (c) Copyright 2002-2007, Ralink Technology, Inc.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify *
|
||
|
* it under the terms of the GNU General Public License as published by *
|
||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||
|
* (at your option) any later version. *
|
||
|
* *
|
||
|
* This program is distributed in the hope that it will be useful, *
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||
|
* GNU General Public License for more details. *
|
||
|
* *
|
||
|
* You should have received a copy of the GNU General Public License *
|
||
|
* along with this program; if not, write to the *
|
||
|
* Free Software Foundation, Inc., *
|
||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||
|
* *
|
||
|
*************************************************************************
|
||
|
|
||
|
Module Name:
|
||
|
pci_main_dev.c
|
||
|
|
||
|
Abstract:
|
||
|
Create and register network interface for PCI based chipsets in Linux platform.
|
||
|
|
||
|
Revision History:
|
||
|
Who When What
|
||
|
-------- ---------- ----------------------------------------------
|
||
|
*/
|
||
|
|
||
|
#include "rt_config.h"
|
||
|
#include <linux/pci.h>
|
||
|
|
||
|
//
|
||
|
// Function declarations
|
||
|
//
|
||
|
extern int rt28xx_close(IN struct net_device *net_dev);
|
||
|
extern int rt28xx_open(struct net_device *net_dev);
|
||
|
|
||
|
static VOID __devexit rt2860_remove_one(struct pci_dev *pci_dev);
|
||
|
static INT __devinit rt2860_probe(struct pci_dev *pci_dev, const struct pci_device_id *ent);
|
||
|
static void __exit rt2860_cleanup_module(void);
|
||
|
static int __init rt2860_init_module(void);
|
||
|
|
||
|
static VOID RTMPInitPCIeDevice(
|
||
|
IN struct pci_dev *pci_dev,
|
||
|
IN PRTMP_ADAPTER pAd);
|
||
|
|
||
|
#ifdef CONFIG_PM
|
||
|
static int rt2860_suspend(struct pci_dev *pci_dev, pm_message_t state);
|
||
|
static int rt2860_resume(struct pci_dev *pci_dev);
|
||
|
#endif // CONFIG_PM //
|
||
|
|
||
|
//
|
||
|
// Ralink PCI device table, include all supported chipsets
|
||
|
//
|
||
|
static struct pci_device_id rt2860_pci_tbl[] __devinitdata =
|
||
|
{
|
||
|
{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC2860_PCI_DEVICE_ID)}, //RT28602.4G
|
||
|
{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC2860_PCIe_DEVICE_ID)},
|
||
|
{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC2760_PCI_DEVICE_ID)},
|
||
|
{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC2790_PCIe_DEVICE_ID)},
|
||
|
{PCI_DEVICE(VEN_AWT_PCI_VENDOR_ID, VEN_AWT_PCIe_DEVICE_ID)},
|
||
|
{PCI_DEVICE(EDIMAX_PCI_VENDOR_ID, 0x7708)},
|
||
|
{PCI_DEVICE(EDIMAX_PCI_VENDOR_ID, 0x7728)},
|
||
|
{PCI_DEVICE(EDIMAX_PCI_VENDOR_ID, 0x7758)},
|
||
|
{PCI_DEVICE(EDIMAX_PCI_VENDOR_ID, 0x7727)},
|
||
|
{PCI_DEVICE(EDIMAX_PCI_VENDOR_ID, 0x7738)},
|
||
|
{PCI_DEVICE(EDIMAX_PCI_VENDOR_ID, 0x7748)},
|
||
|
{PCI_DEVICE(EDIMAX_PCI_VENDOR_ID, 0x7768)},
|
||
|
{0,} // terminate list
|
||
|
};
|
||
|
|
||
|
MODULE_DEVICE_TABLE(pci, rt2860_pci_tbl);
|
||
|
MODULE_LICENSE("GPL");
|
||
|
#ifdef MODULE_VERSION
|
||
|
MODULE_VERSION(STA_DRIVER_VERSION);
|
||
|
#endif
|
||
|
|
||
|
|
||
|
//
|
||
|
// Our PCI driver structure
|
||
|
//
|
||
|
static struct pci_driver rt2860_driver =
|
||
|
{
|
||
|
name: "rt2860",
|
||
|
id_table: rt2860_pci_tbl,
|
||
|
probe: rt2860_probe,
|
||
|
remove: __devexit_p(rt2860_remove_one),
|
||
|
#ifdef CONFIG_PM
|
||
|
suspend: rt2860_suspend,
|
||
|
resume: rt2860_resume,
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
*
|
||
|
* PCI device initialization related procedures.
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
#ifdef CONFIG_PM
|
||
|
|
||
|
VOID RT2860RejectPendingPackets(
|
||
|
IN PRTMP_ADAPTER pAd)
|
||
|
{
|
||
|
// clear PS packets
|
||
|
// clear TxSw packets
|
||
|
}
|
||
|
|
||
|
static int rt2860_suspend(
|
||
|
struct pci_dev *pci_dev,
|
||
|
pm_message_t state)
|
||
|
{
|
||
|
struct net_device *net_dev = pci_get_drvdata(pci_dev);
|
||
|
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)NULL;
|
||
|
INT32 retval = 0;
|
||
|
|
||
|
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("===> rt2860_suspend()\n"));
|
||
|
|
||
|
if (net_dev == NULL)
|
||
|
{
|
||
|
DBGPRINT(RT_DEBUG_ERROR, ("net_dev == NULL!\n"));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GET_PAD_FROM_NET_DEV(pAd, net_dev);
|
||
|
|
||
|
/* we can not use IFF_UP because ra0 down but ra1 up */
|
||
|
/* and 1 suspend/resume function for 1 module, not for each interface */
|
||
|
/* so Linux will call suspend/resume function once */
|
||
|
if (VIRTUAL_IF_NUM(pAd) > 0)
|
||
|
{
|
||
|
// avoid users do suspend after interface is down
|
||
|
|
||
|
// stop interface
|
||
|
netif_carrier_off(net_dev);
|
||
|
netif_stop_queue(net_dev);
|
||
|
|
||
|
// mark device as removed from system and therefore no longer available
|
||
|
netif_device_detach(net_dev);
|
||
|
|
||
|
// mark halt flag
|
||
|
RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS);
|
||
|
RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
|
||
|
|
||
|
// take down the device
|
||
|
rt28xx_close((PNET_DEV)net_dev);
|
||
|
|
||
|
RT_MOD_DEC_USE_COUNT();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// reference to http://vovo2000.com/type-lab/linux/kernel-api/linux-kernel-api.html
|
||
|
// enable device to generate PME# when suspended
|
||
|
// pci_choose_state(): Choose the power state of a PCI device to be suspended
|
||
|
retval = pci_enable_wake(pci_dev, pci_choose_state(pci_dev, state), 1);
|
||
|
// save the PCI configuration space of a device before suspending
|
||
|
pci_save_state(pci_dev);
|
||
|
// disable PCI device after use
|
||
|
pci_disable_device(pci_dev);
|
||
|
|
||
|
retval = pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
|
||
|
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2860_suspend()\n"));
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
static int rt2860_resume(
|
||
|
struct pci_dev *pci_dev)
|
||
|
{
|
||
|
struct net_device *net_dev = pci_get_drvdata(pci_dev);
|
||
|
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)NULL;
|
||
|
INT32 retval;
|
||
|
|
||
|
|
||
|
// set the power state of a PCI device
|
||
|
// PCI has 4 power states, DO (normal) ~ D3(less power)
|
||
|
// in include/linux/pci.h, you can find that
|
||
|
// #define PCI_D0 ((pci_power_t __force) 0)
|
||
|
// #define PCI_D1 ((pci_power_t __force) 1)
|
||
|
// #define PCI_D2 ((pci_power_t __force) 2)
|
||
|
// #define PCI_D3hot ((pci_power_t __force) 3)
|
||
|
// #define PCI_D3cold ((pci_power_t __force) 4)
|
||
|
// #define PCI_UNKNOWN ((pci_power_t __force) 5)
|
||
|
// #define PCI_POWER_ERROR ((pci_power_t __force) -1)
|
||
|
retval = pci_set_power_state(pci_dev, PCI_D0);
|
||
|
|
||
|
// restore the saved state of a PCI device
|
||
|
pci_restore_state(pci_dev);
|
||
|
|
||
|
// initialize device before it's used by a driver
|
||
|
if (pci_enable_device(pci_dev))
|
||
|
{
|
||
|
printk("pci enable fail!\n");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("===> rt2860_resume()\n"));
|
||
|
|
||
|
if (net_dev == NULL)
|
||
|
{
|
||
|
DBGPRINT(RT_DEBUG_ERROR, ("net_dev == NULL!\n"));
|
||
|
}
|
||
|
else
|
||
|
GET_PAD_FROM_NET_DEV(pAd, net_dev);
|
||
|
|
||
|
if (pAd != NULL)
|
||
|
{
|
||
|
/* we can not use IFF_UP because ra0 down but ra1 up */
|
||
|
/* and 1 suspend/resume function for 1 module, not for each interface */
|
||
|
/* so Linux will call suspend/resume function once */
|
||
|
if (VIRTUAL_IF_NUM(pAd) > 0)
|
||
|
{
|
||
|
// mark device as attached from system and restart if needed
|
||
|
netif_device_attach(net_dev);
|
||
|
|
||
|
if (rt28xx_open((PNET_DEV)net_dev) != 0)
|
||
|
{
|
||
|
// open fail
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2860_resume()\n"));
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// increase MODULE use count
|
||
|
RT_MOD_INC_USE_COUNT();
|
||
|
|
||
|
RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS);
|
||
|
RTMP_CLEAR_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF);
|
||
|
|
||
|
netif_start_queue(net_dev);
|
||
|
netif_carrier_on(net_dev);
|
||
|
netif_wake_queue(net_dev);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2860_resume()\n"));
|
||
|
return 0;
|
||
|
}
|
||
|
#endif // CONFIG_PM //
|
||
|
|
||
|
|
||
|
static INT __init rt2860_init_module(VOID)
|
||
|
{
|
||
|
return pci_register_driver(&rt2860_driver);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Driver module unload function
|
||
|
//
|
||
|
static VOID __exit rt2860_cleanup_module(VOID)
|
||
|
{
|
||
|
pci_unregister_driver(&rt2860_driver);
|
||
|
}
|
||
|
|
||
|
module_init(rt2860_init_module);
|
||
|
module_exit(rt2860_cleanup_module);
|
||
|
|
||
|
|
||
|
//
|
||
|
// PCI device probe & initialization function
|
||
|
//
|
||
|
static INT __devinit rt2860_probe(
|
||
|
IN struct pci_dev *pci_dev,
|
||
|
IN const struct pci_device_id *pci_id)
|
||
|
{
|
||
|
PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)NULL;
|
||
|
struct net_device *net_dev;
|
||
|
PVOID handle;
|
||
|
PSTRING print_name;
|
||
|
ULONG csr_addr;
|
||
|
INT rv = 0;
|
||
|
RTMP_OS_NETDEV_OP_HOOK netDevHook;
|
||
|
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("===> rt2860_probe\n"));
|
||
|
|
||
|
//PCIDevInit==============================================
|
||
|
// wake up and enable device
|
||
|
if ((rv = pci_enable_device(pci_dev))!= 0)
|
||
|
{
|
||
|
DBGPRINT(RT_DEBUG_ERROR, ("Enable PCI device failed, errno=%d!\n", rv));
|
||
|
return rv;
|
||
|
}
|
||
|
|
||
|
print_name = pci_name(pci_dev);
|
||
|
|
||
|
if ((rv = pci_request_regions(pci_dev, print_name)) != 0)
|
||
|
{
|
||
|
DBGPRINT(RT_DEBUG_ERROR, ("Request PCI resource failed, errno=%d!\n", rv));
|
||
|
goto err_out;
|
||
|
}
|
||
|
|
||
|
// map physical address to virtual address for accessing register
|
||
|
csr_addr = (unsigned long) ioremap(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0));
|
||
|
if (!csr_addr)
|
||
|
{
|
||
|
DBGPRINT(RT_DEBUG_ERROR, ("ioremap failed for device %s, region 0x%lX @ 0x%lX\n",
|
||
|
print_name, (ULONG)pci_resource_len(pci_dev, 0), (ULONG)pci_resource_start(pci_dev, 0)));
|
||
|
goto err_out_free_res;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("%s: at 0x%lx, VA 0x%lx, IRQ %d. \n", print_name,
|
||
|
(ULONG)pci_resource_start(pci_dev, 0), (ULONG)csr_addr, pci_dev->irq));
|
||
|
}
|
||
|
|
||
|
// Set DMA master
|
||
|
pci_set_master(pci_dev);
|
||
|
|
||
|
|
||
|
//RtmpDevInit==============================================
|
||
|
// Allocate RTMP_ADAPTER adapter structure
|
||
|
handle = kmalloc(sizeof(struct os_cookie), GFP_KERNEL);
|
||
|
if (handle == NULL)
|
||
|
{
|
||
|
DBGPRINT(RT_DEBUG_ERROR, ("%s(): Allocate memory for os handle failed!\n", __func__));
|
||
|
goto err_out_iounmap;
|
||
|
}
|
||
|
|
||
|
((POS_COOKIE)handle)->pci_dev = pci_dev;
|
||
|
|
||
|
rv = RTMPAllocAdapterBlock(handle, &pAd); //shiang: we may need the pci_dev for allocate structure of "RTMP_ADAPTER"
|
||
|
if (rv != NDIS_STATUS_SUCCESS)
|
||
|
goto err_out_iounmap;
|
||
|
// Here are the RTMP_ADAPTER structure with pci-bus specific parameters.
|
||
|
pAd->CSRBaseAddress = (PUCHAR)csr_addr;
|
||
|
DBGPRINT(RT_DEBUG_ERROR, ("pAd->CSRBaseAddress =0x%lx, csr_addr=0x%lx!\n", (ULONG)pAd->CSRBaseAddress, csr_addr));
|
||
|
RtmpRaDevCtrlInit(pAd, RTMP_DEV_INF_PCI);
|
||
|
|
||
|
|
||
|
//NetDevInit==============================================
|
||
|
net_dev = RtmpPhyNetDevInit(pAd, &netDevHook);
|
||
|
if (net_dev == NULL)
|
||
|
goto err_out_free_radev;
|
||
|
|
||
|
// Here are the net_device structure with pci-bus specific parameters.
|
||
|
net_dev->irq = pci_dev->irq; // Interrupt IRQ number
|
||
|
net_dev->base_addr = csr_addr; // Save CSR virtual address and irq to device structure
|
||
|
pci_set_drvdata(pci_dev, net_dev); // Set driver data
|
||
|
|
||
|
/* for supporting Network Manager */
|
||
|
/* Set the sysfs physical device reference for the network logical device
|
||
|
* if set prior to registration will cause a symlink during initialization.
|
||
|
*/
|
||
|
SET_NETDEV_DEV(net_dev, &(pci_dev->dev));
|
||
|
|
||
|
|
||
|
//All done, it's time to register the net device to linux kernel.
|
||
|
// Register this device
|
||
|
rv = RtmpOSNetDevAttach(net_dev, &netDevHook);
|
||
|
if (rv)
|
||
|
goto err_out_free_netdev;
|
||
|
|
||
|
pAd->StaCfg.OriDevType = net_dev->type;
|
||
|
RTMPInitPCIeDevice(pci_dev, pAd);
|
||
|
|
||
|
#ifdef KTHREAD_SUPPORT
|
||
|
#endif // KTHREAD_SUPPORT //
|
||
|
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2860_probe\n"));
|
||
|
|
||
|
return 0; // probe ok
|
||
|
|
||
|
|
||
|
/* --------------------------- ERROR HANDLE --------------------------- */
|
||
|
err_out_free_netdev:
|
||
|
RtmpOSNetDevFree(net_dev);
|
||
|
|
||
|
err_out_free_radev:
|
||
|
/* free RTMP_ADAPTER strcuture and os_cookie*/
|
||
|
RTMPFreeAdapter(pAd);
|
||
|
|
||
|
err_out_iounmap:
|
||
|
iounmap((void *)(csr_addr));
|
||
|
release_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0));
|
||
|
|
||
|
err_out_free_res:
|
||
|
pci_release_regions(pci_dev);
|
||
|
|
||
|
err_out:
|
||
|
pci_disable_device(pci_dev);
|
||
|
|
||
|
DBGPRINT(RT_DEBUG_ERROR, ("<=== rt2860_probe failed with rv = %d!\n", rv));
|
||
|
|
||
|
return -ENODEV; /* probe fail */
|
||
|
}
|
||
|
|
||
|
|
||
|
static VOID __devexit rt2860_remove_one(
|
||
|
IN struct pci_dev *pci_dev)
|
||
|
{
|
||
|
PNET_DEV net_dev = pci_get_drvdata(pci_dev);
|
||
|
RTMP_ADAPTER *pAd = NULL;
|
||
|
ULONG csr_addr = net_dev->base_addr; // pAd->CSRBaseAddress;
|
||
|
|
||
|
GET_PAD_FROM_NET_DEV(pAd, net_dev);
|
||
|
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("===> rt2860_remove_one\n"));
|
||
|
|
||
|
if (pAd != NULL)
|
||
|
{
|
||
|
// Unregister/Free all allocated net_device.
|
||
|
RtmpPhyNetDevExit(pAd, net_dev);
|
||
|
|
||
|
// Unmap CSR base address
|
||
|
iounmap((char *)(csr_addr));
|
||
|
|
||
|
// release memory region
|
||
|
release_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0));
|
||
|
|
||
|
// Free RTMP_ADAPTER related structures.
|
||
|
RtmpRaDevCtrlExit(pAd);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Unregister network device
|
||
|
RtmpOSNetDevDetach(net_dev);
|
||
|
|
||
|
// Unmap CSR base address
|
||
|
iounmap((char *)(net_dev->base_addr));
|
||
|
|
||
|
// release memory region
|
||
|
release_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0));
|
||
|
}
|
||
|
|
||
|
// Free the root net_device
|
||
|
RtmpOSNetDevFree(net_dev);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
========================================================================
|
||
|
Routine Description:
|
||
|
Check the chipset vendor/product ID.
|
||
|
|
||
|
Arguments:
|
||
|
_dev_p Point to the PCI or USB device
|
||
|
|
||
|
Return Value:
|
||
|
TRUE Check ok
|
||
|
FALSE Check fail
|
||
|
|
||
|
Note:
|
||
|
========================================================================
|
||
|
*/
|
||
|
BOOLEAN RT28XXChipsetCheck(
|
||
|
IN void *_dev_p)
|
||
|
{
|
||
|
/* always TRUE */
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/***************************************************************************
|
||
|
*
|
||
|
* PCIe device initialization related procedures.
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
static VOID RTMPInitPCIeDevice(
|
||
|
IN struct pci_dev *pci_dev,
|
||
|
IN PRTMP_ADAPTER pAd)
|
||
|
{
|
||
|
USHORT device_id;
|
||
|
POS_COOKIE pObj;
|
||
|
|
||
|
pObj = (POS_COOKIE) pAd->OS_Cookie;
|
||
|
pci_read_config_word(pci_dev, PCI_DEVICE_ID, &device_id);
|
||
|
device_id = le2cpu16(device_id);
|
||
|
pObj->DeviceID = device_id;
|
||
|
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE);
|
||
|
if (
|
||
|
(device_id == NIC2860_PCIe_DEVICE_ID) ||
|
||
|
(device_id == NIC2790_PCIe_DEVICE_ID) ||
|
||
|
(device_id == VEN_AWT_PCIe_DEVICE_ID) ||
|
||
|
0)
|
||
|
{
|
||
|
UINT32 MacCsr0 = 0, Index= 0;
|
||
|
do
|
||
|
{
|
||
|
RTMP_IO_READ32(pAd, MAC_CSR0, &MacCsr0);
|
||
|
|
||
|
if ((MacCsr0 != 0x00) && (MacCsr0 != 0xFFFFFFFF))
|
||
|
break;
|
||
|
|
||
|
RTMPusecDelay(10);
|
||
|
} while (Index++ < 100);
|
||
|
|
||
|
// Support advanced power save after 2892/2790.
|
||
|
// MAC version at offset 0x1000 is 0x2872XXXX/0x2870XXXX(PCIe, USB, SDIO).
|
||
|
if ((MacCsr0&0xffff0000) != 0x28600000)
|
||
|
{
|
||
|
OPSTATUS_SET_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID RTMPInitPCIeLinkCtrlValue(
|
||
|
IN PRTMP_ADAPTER pAd)
|
||
|
{
|
||
|
INT pos;
|
||
|
USHORT reg16, data2, PCIePowerSaveLevel, Configuration;
|
||
|
BOOLEAN bFindIntel = FALSE;
|
||
|
POS_COOKIE pObj;
|
||
|
|
||
|
pObj = (POS_COOKIE) pAd->OS_Cookie;
|
||
|
|
||
|
if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
|
||
|
return;
|
||
|
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("%s.===>\n", __func__));
|
||
|
// Init EEPROM, and save settings
|
||
|
if (!IS_RT3090(pAd))
|
||
|
{
|
||
|
RT28xx_EEPROM_READ16(pAd, 0x22, PCIePowerSaveLevel);
|
||
|
pAd->PCIePowerSaveLevel = PCIePowerSaveLevel & 0xff;
|
||
|
|
||
|
if ((PCIePowerSaveLevel&0xff) == 0xff)
|
||
|
{
|
||
|
OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE);
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("====> PCIePowerSaveLevel = 0x%x.\n", PCIePowerSaveLevel));
|
||
|
return;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PCIePowerSaveLevel &= 0x3;
|
||
|
RT28xx_EEPROM_READ16(pAd, 0x24, data2);
|
||
|
|
||
|
if( !(((data2&0xff00) == 0x9200) && ((data2&0x80) !=0)) )
|
||
|
{
|
||
|
if (PCIePowerSaveLevel > 1 )
|
||
|
PCIePowerSaveLevel = 1;
|
||
|
}
|
||
|
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("====> Write 0x83 = 0x%x.\n", PCIePowerSaveLevel));
|
||
|
AsicSendCommandToMcu(pAd, 0x83, 0xff, (UCHAR)PCIePowerSaveLevel, 0x00);
|
||
|
RT28xx_EEPROM_READ16(pAd, 0x22, PCIePowerSaveLevel);
|
||
|
PCIePowerSaveLevel &= 0xff;
|
||
|
PCIePowerSaveLevel = PCIePowerSaveLevel >> 6;
|
||
|
switch(PCIePowerSaveLevel)
|
||
|
{
|
||
|
case 0: // Only support L0
|
||
|
pAd->LnkCtrlBitMask = 0;
|
||
|
break;
|
||
|
case 1: // Only enable L0s
|
||
|
pAd->LnkCtrlBitMask = 1;
|
||
|
break;
|
||
|
case 2: // enable L1, L0s
|
||
|
pAd->LnkCtrlBitMask = 3;
|
||
|
break;
|
||
|
case 3: // sync with host clk and enable L1, L0s
|
||
|
pAd->LnkCtrlBitMask = 0x103;
|
||
|
break;
|
||
|
}
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("====> LnkCtrlBitMask = 0x%x.\n", pAd->LnkCtrlBitMask));
|
||
|
}
|
||
|
}
|
||
|
else if (IS_RT3090(pAd))
|
||
|
{
|
||
|
// 1. read setting from inf file.
|
||
|
// .....
|
||
|
USHORT PCIePowerSetting = 0;
|
||
|
/* code from windows, default value of rt30xxPowerMode = 0
|
||
|
PCIePowerSetting = pAd->StaCfg.PSControl.field.rt30xxPowerMode;
|
||
|
*/
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("====> rt30xx Read PowerLevelMode = 0x%x.\n", PCIePowerSetting));
|
||
|
// 2. Check EnableNewPS
|
||
|
/*
|
||
|
if (pAd->StaCfg.PSControl.field.EnableNewPS == FALSE)
|
||
|
PCIePowerSetting = 1;
|
||
|
*/
|
||
|
|
||
|
if ((pAd->MACVersion&0xffff) <= 0x0211)
|
||
|
{
|
||
|
// Chip Version E only allow 1
|
||
|
PCIePowerSetting = 1;
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("====> rt30xx Write 0x83 Command = 0x%x.\n", PCIePowerSetting));
|
||
|
AsicSendCommandToMcu(pAd, 0x83, 0xff, (UCHAR)PCIePowerSetting, 0x00);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Chip Version F only allow 1 or 2
|
||
|
if ((PCIePowerSetting > 2) || (PCIePowerSetting == 0))
|
||
|
PCIePowerSetting = 1;
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("====> rt30xx Write 0x83 Command = 0x%x.\n", PCIePowerSetting));
|
||
|
AsicSendCommandToMcu(pAd, 0x83, 0xff, (UCHAR)PCIePowerSetting, 0x00);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// Find Ralink PCIe Device's Express Capability Offset
|
||
|
pos = pci_find_capability(pObj->pci_dev, PCI_CAP_ID_EXP);
|
||
|
|
||
|
if (pos != 0)
|
||
|
{
|
||
|
// Ralink PCIe Device's Link Control Register Offset
|
||
|
pAd->RLnkCtrlOffset = pos + PCI_EXP_LNKCTL;
|
||
|
pci_read_config_word(pObj->pci_dev, pAd->RLnkCtrlOffset, ®16);
|
||
|
Configuration = le2cpu16(reg16);
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("Read (Ralink PCIe Link Control Register) offset 0x%x = 0x%x\n",
|
||
|
pAd->RLnkCtrlOffset, Configuration));
|
||
|
pAd->RLnkCtrlConfiguration = (Configuration & 0x103);
|
||
|
Configuration &= 0xfefc;
|
||
|
Configuration |= (0x0);
|
||
|
if ((pObj->DeviceID == NIC2860_PCIe_DEVICE_ID)
|
||
|
||(pObj->DeviceID == NIC2790_PCIe_DEVICE_ID))
|
||
|
{
|
||
|
reg16 = cpu2le16(Configuration);
|
||
|
pci_write_config_word(pObj->pci_dev, pAd->RLnkCtrlOffset, reg16);
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("Write (Ralink PCIe Link Control Register) offset 0x%x = 0x%x\n",
|
||
|
pos + PCI_EXP_LNKCTL, Configuration));
|
||
|
}
|
||
|
|
||
|
RTMPFindHostPCIDev(pAd);
|
||
|
if (pObj->parent_pci_dev)
|
||
|
{
|
||
|
USHORT vendor_id;
|
||
|
|
||
|
pci_read_config_word(pObj->parent_pci_dev, PCI_VENDOR_ID, &vendor_id);
|
||
|
vendor_id = le2cpu16(vendor_id);
|
||
|
if (vendor_id == PCIBUS_INTEL_VENDOR)
|
||
|
bFindIntel = TRUE;
|
||
|
|
||
|
// Find PCI-to-PCI Bridge Express Capability Offset
|
||
|
pos = pci_find_capability(pObj->parent_pci_dev, PCI_CAP_ID_EXP);
|
||
|
|
||
|
if (pos != 0)
|
||
|
{
|
||
|
BOOLEAN bChange = FALSE;
|
||
|
// PCI-to-PCI Bridge Link Control Register Offset
|
||
|
pAd->HostLnkCtrlOffset = pos + PCI_EXP_LNKCTL;
|
||
|
pci_read_config_word(pObj->parent_pci_dev, pAd->HostLnkCtrlOffset, ®16);
|
||
|
Configuration = le2cpu16(reg16);
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("Read (Host PCI-to-PCI Bridge Link Control Register) offset 0x%x = 0x%x\n",
|
||
|
pAd->HostLnkCtrlOffset, Configuration));
|
||
|
pAd->HostLnkCtrlConfiguration = (Configuration & 0x103);
|
||
|
Configuration &= 0xfefc;
|
||
|
Configuration |= (0x0);
|
||
|
|
||
|
switch (pObj->DeviceID)
|
||
|
{
|
||
|
case NIC2860_PCIe_DEVICE_ID:
|
||
|
case NIC2790_PCIe_DEVICE_ID:
|
||
|
bChange = TRUE;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (bChange)
|
||
|
{
|
||
|
reg16 = cpu2le16(Configuration);
|
||
|
pci_write_config_word(pObj->parent_pci_dev, pAd->HostLnkCtrlOffset, reg16);
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("Write (Host PCI-to-PCI Bridge Link Control Register) offset 0x%x = 0x%x\n",
|
||
|
pAd->HostLnkCtrlOffset, Configuration));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pAd->HostLnkCtrlOffset = 0;
|
||
|
DBGPRINT(RT_DEBUG_ERROR, ("%s: cannot find PCI-to-PCI Bridge PCI Express Capability!\n", __func__));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pAd->RLnkCtrlOffset = 0;
|
||
|
pAd->HostLnkCtrlOffset = 0;
|
||
|
DBGPRINT(RT_DEBUG_ERROR, ("%s: cannot find Ralink PCIe Device's PCI Express Capability!\n", __func__));
|
||
|
}
|
||
|
|
||
|
if (bFindIntel == FALSE)
|
||
|
{
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("Doesn't find Intel PCI host controller. \n"));
|
||
|
// Doesn't switch L0, L1, So set PCIePowerSaveLevel to 0xff
|
||
|
pAd->PCIePowerSaveLevel = 0xff;
|
||
|
if ((pAd->RLnkCtrlOffset != 0)
|
||
|
)
|
||
|
{
|
||
|
pci_read_config_word(pObj->pci_dev, pAd->RLnkCtrlOffset, ®16);
|
||
|
Configuration = le2cpu16(reg16);
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("Read (Ralink 30xx PCIe Link Control Register) offset 0x%x = 0x%x\n",
|
||
|
pAd->RLnkCtrlOffset, Configuration));
|
||
|
pAd->RLnkCtrlConfiguration = (Configuration & 0x103);
|
||
|
Configuration &= 0xfefc;
|
||
|
Configuration |= (0x0);
|
||
|
reg16 = cpu2le16(Configuration);
|
||
|
pci_write_config_word(pObj->pci_dev, pAd->RLnkCtrlOffset, reg16);
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("Write (Ralink PCIe Link Control Register) offset 0x%x = 0x%x\n",
|
||
|
pos + PCI_EXP_LNKCTL, Configuration));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VOID RTMPFindHostPCIDev(
|
||
|
IN PRTMP_ADAPTER pAd)
|
||
|
{
|
||
|
USHORT reg16;
|
||
|
UCHAR reg8;
|
||
|
UINT DevFn;
|
||
|
PPCI_DEV pPci_dev;
|
||
|
POS_COOKIE pObj;
|
||
|
|
||
|
pObj = (POS_COOKIE) pAd->OS_Cookie;
|
||
|
|
||
|
if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
|
||
|
return;
|
||
|
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("%s.===>\n", __func__));
|
||
|
|
||
|
pObj->parent_pci_dev = NULL;
|
||
|
if (pObj->pci_dev->bus->parent)
|
||
|
{
|
||
|
for (DevFn = 0; DevFn < 255; DevFn++)
|
||
|
{
|
||
|
pPci_dev = pci_get_slot(pObj->pci_dev->bus->parent, DevFn);
|
||
|
if (pPci_dev)
|
||
|
{
|
||
|
pci_read_config_word(pPci_dev, PCI_CLASS_DEVICE, ®16);
|
||
|
reg16 = le2cpu16(reg16);
|
||
|
pci_read_config_byte(pPci_dev, PCI_CB_CARD_BUS, ®8);
|
||
|
if ((reg16 == PCI_CLASS_BRIDGE_PCI) &&
|
||
|
(reg8 == pObj->pci_dev->bus->number))
|
||
|
{
|
||
|
pObj->parent_pci_dev = pPci_dev;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
========================================================================
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Arguments:
|
||
|
Level = RESTORE_HALT : Restore PCI host and Ralink PCIe Link Control field to its default value.
|
||
|
Level = Other Value : Restore from dot11 power save or radio off status. And force PCI host Link Control fields to 0x1
|
||
|
|
||
|
========================================================================
|
||
|
*/
|
||
|
VOID RTMPPCIeLinkCtrlValueRestore(
|
||
|
IN PRTMP_ADAPTER pAd,
|
||
|
IN UCHAR Level)
|
||
|
{
|
||
|
USHORT PCIePowerSaveLevel, reg16;
|
||
|
USHORT Configuration;
|
||
|
POS_COOKIE pObj;
|
||
|
|
||
|
pObj = (POS_COOKIE) pAd->OS_Cookie;
|
||
|
|
||
|
if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
|
||
|
return;
|
||
|
|
||
|
if (!((pObj->DeviceID == NIC2860_PCIe_DEVICE_ID)
|
||
|
||(pObj->DeviceID == NIC2790_PCIe_DEVICE_ID)))
|
||
|
return;
|
||
|
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("%s.===>\n", __func__));
|
||
|
PCIePowerSaveLevel = pAd->PCIePowerSaveLevel;
|
||
|
if ((PCIePowerSaveLevel&0xff) == 0xff)
|
||
|
{
|
||
|
DBGPRINT(RT_DEBUG_TRACE,("return \n"));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (pObj->parent_pci_dev && (pAd->HostLnkCtrlOffset != 0))
|
||
|
{
|
||
|
PCI_REG_READ_WORD(pObj->parent_pci_dev, pAd->HostLnkCtrlOffset, Configuration);
|
||
|
if ((Configuration != 0) &&
|
||
|
(Configuration != 0xFFFF))
|
||
|
{
|
||
|
Configuration &= 0xfefc;
|
||
|
// If call from interface down, restore to orginial setting.
|
||
|
if (Level == RESTORE_CLOSE)
|
||
|
{
|
||
|
Configuration |= pAd->HostLnkCtrlConfiguration;
|
||
|
}
|
||
|
else
|
||
|
Configuration |= 0x0;
|
||
|
PCI_REG_WIRTE_WORD(pObj->parent_pci_dev, pAd->HostLnkCtrlOffset, Configuration);
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("Restore PCI host : offset 0x%x = 0x%x\n", pAd->HostLnkCtrlOffset, Configuration));
|
||
|
}
|
||
|
else
|
||
|
DBGPRINT(RT_DEBUG_ERROR, ("Restore PCI host : PCI_REG_READ_WORD failed (Configuration = 0x%x)\n", Configuration));
|
||
|
}
|
||
|
|
||
|
if (pObj->pci_dev && (pAd->RLnkCtrlOffset != 0))
|
||
|
{
|
||
|
PCI_REG_READ_WORD(pObj->pci_dev, pAd->RLnkCtrlOffset, Configuration);
|
||
|
if ((Configuration != 0) &&
|
||
|
(Configuration != 0xFFFF))
|
||
|
{
|
||
|
Configuration &= 0xfefc;
|
||
|
// If call from interface down, restore to orginial setting.
|
||
|
if (Level == RESTORE_CLOSE)
|
||
|
Configuration |= pAd->RLnkCtrlConfiguration;
|
||
|
else
|
||
|
Configuration |= 0x0;
|
||
|
PCI_REG_WIRTE_WORD(pObj->pci_dev, pAd->RLnkCtrlOffset, Configuration);
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("Restore Ralink : offset 0x%x = 0x%x\n", pAd->RLnkCtrlOffset, Configuration));
|
||
|
}
|
||
|
else
|
||
|
DBGPRINT(RT_DEBUG_ERROR, ("Restore Ralink : PCI_REG_READ_WORD failed (Configuration = 0x%x)\n", Configuration));
|
||
|
}
|
||
|
|
||
|
DBGPRINT(RT_DEBUG_TRACE,("%s <===\n", __func__));
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
========================================================================
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Arguments:
|
||
|
Max : limit Host PCI and Ralink PCIe device's LINK CONTROL field's value.
|
||
|
Because now frequently set our device to mode 1 or mode 3 will cause problem.
|
||
|
|
||
|
========================================================================
|
||
|
*/
|
||
|
VOID RTMPPCIeLinkCtrlSetting(
|
||
|
IN PRTMP_ADAPTER pAd,
|
||
|
IN USHORT Max)
|
||
|
{
|
||
|
USHORT PCIePowerSaveLevel, reg16;
|
||
|
USHORT Configuration;
|
||
|
POS_COOKIE pObj;
|
||
|
|
||
|
pObj = (POS_COOKIE) pAd->OS_Cookie;
|
||
|
|
||
|
if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_ADVANCE_POWER_SAVE_PCIE_DEVICE))
|
||
|
return;
|
||
|
|
||
|
if (!((pObj->DeviceID == NIC2860_PCIe_DEVICE_ID)
|
||
|
||(pObj->DeviceID == NIC2790_PCIe_DEVICE_ID)))
|
||
|
return;
|
||
|
|
||
|
DBGPRINT(RT_DEBUG_TRACE,("%s===>\n", __func__));
|
||
|
PCIePowerSaveLevel = pAd->PCIePowerSaveLevel;
|
||
|
if ((PCIePowerSaveLevel&0xff) == 0xff)
|
||
|
{
|
||
|
DBGPRINT(RT_DEBUG_TRACE,("return \n"));
|
||
|
return;
|
||
|
}
|
||
|
PCIePowerSaveLevel = PCIePowerSaveLevel>>6;
|
||
|
|
||
|
|
||
|
if (pObj->pci_dev && (pAd->RLnkCtrlOffset != 0))
|
||
|
{
|
||
|
// first 2892 chip not allow to frequently set mode 3. will cause hang problem.
|
||
|
if (PCIePowerSaveLevel > Max)
|
||
|
PCIePowerSaveLevel = Max;
|
||
|
|
||
|
PCI_REG_READ_WORD(pObj->pci_dev, pAd->RLnkCtrlOffset, Configuration);
|
||
|
Configuration |= 0x100;
|
||
|
PCI_REG_WIRTE_WORD(pObj->pci_dev, pAd->RLnkCtrlOffset, Configuration);
|
||
|
DBGPRINT(RT_DEBUG_TRACE, ("Write Ralink device : offset 0x%x = 0x%x\n", pAd->RLnkCtrlOffset, Configuration));
|
||
|
}
|
||
|
|
||
|
DBGPRINT(RT_DEBUG_TRACE,("RTMPPCIePowerLinkCtrl <==============\n"));
|
||
|
}
|