Linux-2.6.33.2/drivers/staging/rt2860/pci_main_dev.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>

/* Following information will be show when you run 'modinfo' */
/* *** If you have a solution for the bug in current version of driver, please mail to me. */
/* Otherwise post to forum in ralinktech's web site(www.ralinktech.com) and let all users help you. *** */
MODULE_AUTHOR("Jett Chen <jett_chen@ralinktech.com>");
MODULE_DESCRIPTION("RT2860/RT3090 Wireless Lan Linux Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("rt3090sta");

/* */
/* 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,
			       struct rt_rtmp_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 = {
#ifdef RT2860
	{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)},
#endif
#ifdef RT3090
	{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC3090_PCIe_DEVICE_ID)},
	{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC3091_PCIe_DEVICE_ID)},
	{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC3092_PCIe_DEVICE_ID)},
#endif /* RT3090 // */
#ifdef RT3390
	{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC3390_PCIe_DEVICE_ID)},
	{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC3391_PCIe_DEVICE_ID)},
	{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC3392_PCIe_DEVICE_ID)},
#endif /* RT3390 // */
	{0,}			/* terminate list */
};

MODULE_DEVICE_TABLE(pci, rt2860_pci_tbl);
#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(struct rt_rtmp_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);
	struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)NULL;
	int 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((struct net_device *)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);
	struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)NULL;
	int 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((struct net_device *)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)
{
	struct rt_rtmp_adapter *pAd = (struct rt_rtmp_adapter *)NULL;
	struct net_device *net_dev;
	void *handle;
	char *print_name;
	unsigned long csr_addr;
	int rv = 0;
	struct rt_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 = (char *)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, (unsigned long)pci_resource_len(pci_dev, 0),
			  (unsigned long)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,
			  (unsigned long)pci_resource_start(pci_dev, 0),
			  (unsigned long)csr_addr, pci_dev->irq));
	}

	/* Set DMA master */
	pci_set_master(pci_dev);

/*RtmpDevInit============================================== */
	/* Allocate struct rt_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;
	}

	((struct os_cookie *)handle)->pci_dev = pci_dev;

	rv = RTMPAllocAdapterBlock(handle, &pAd);	/*shiang: we may need the pci_dev for allocate structure of "struct rt_rtmp_adapter" */
	if (rv != NDIS_STATUS_SUCCESS)
		goto err_out_iounmap;
	/* Here are the struct rt_rtmp_adapter structure with pci-bus specific parameters. */
	pAd->CSRBaseAddress = (u8 *)csr_addr;
	DBGPRINT(RT_DEBUG_ERROR,
		 ("pAd->CSRBaseAddress =0x%lx, csr_addr=0x%lx!\n",
		  (unsigned long)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);

	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 struct rt_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)
{
	struct net_device *net_dev = pci_get_drvdata(pci_dev);
	struct rt_rtmp_adapter *pAd = NULL;
	unsigned long 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 struct rt_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(struct pci_dev *pci_dev, struct rt_rtmp_adapter *pAd)
{
	u16 device_id;
	struct os_cookie *pObj;

	pObj = (struct os_cookie *)pAd->OS_Cookie;
	pci_read_config_word(pci_dev, PCI_DEVICE_ID, &device_id);
	device_id = le2cpu16(device_id);
	pObj->DeviceID = device_id;
	if (
#ifdef RT2860
		   (device_id == NIC2860_PCIe_DEVICE_ID) ||
		   (device_id == NIC2790_PCIe_DEVICE_ID) ||
		   (device_id == VEN_AWT_PCIe_DEVICE_ID) ||
#endif
#ifdef RT3090
		   (device_id == NIC3090_PCIe_DEVICE_ID) ||
		   (device_id == NIC3091_PCIe_DEVICE_ID) ||
		   (device_id == NIC3092_PCIe_DEVICE_ID) ||
#endif /* RT3090 // */
		   0) {
		u32 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_PCIE_DEVICE);
		}
	}
}

void RTMPInitPCIeLinkCtrlValue(struct rt_rtmp_adapter *pAd)
{
	int pos;
	u16 reg16, data2, PCIePowerSaveLevel, Configuration;
	u32 MacValue;
	BOOLEAN bFindIntel = FALSE;
	struct os_cookie *pObj;

	pObj = (struct os_cookie *)pAd->OS_Cookie;

	if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE))
		return;

	DBGPRINT(RT_DEBUG_TRACE, ("%s.===>\n", __func__));
	/* Init EEPROM, and save settings */
	if (!(IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd))) {
		RT28xx_EEPROM_READ16(pAd, 0x22, PCIePowerSaveLevel);
		pAd->PCIePowerSaveLevel = PCIePowerSaveLevel & 0xff;

		pAd->LnkCtrlBitMask = 0;
		if ((PCIePowerSaveLevel & 0xff) == 0xff) {
			OPSTATUS_CLEAR_FLAG(pAd, fOP_STATUS_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,
					     (u8)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;
			}
			RT28xx_EEPROM_READ16(pAd, 0x24, data2);
			if ((PCIePowerSaveLevel & 0xff) != 0xff) {
				PCIePowerSaveLevel &= 0x3;

				if (!
				    (((data2 & 0xff00) == 0x9200)
				     && ((data2 & 0x80) != 0))) {
					if (PCIePowerSaveLevel > 1)
						PCIePowerSaveLevel = 1;
				}

				DBGPRINT(RT_DEBUG_TRACE,
					 ("====> rt28xx Write 0x83 Command = 0x%x.\n",
					  PCIePowerSaveLevel));

				AsicSendCommandToMcu(pAd, 0x83, 0xff,
						     (u8)PCIePowerSaveLevel,
						     0x00);
			}
			DBGPRINT(RT_DEBUG_TRACE,
				 ("====> LnkCtrlBitMask = 0x%x.\n",
				  pAd->LnkCtrlBitMask));
		}
	} else if (IS_RT3090(pAd) || IS_RT3572(pAd) || IS_RT3390(pAd)) {
		u8 LinkCtrlSetting = 0;

		/* Check 3090E special setting chip. */
		RT28xx_EEPROM_READ16(pAd, 0x24, data2);
		if ((data2 == 0x9280) && ((pAd->MACVersion & 0xffff) == 0x0211)) {
			pAd->b3090ESpecialChip = TRUE;
			DBGPRINT_RAW(RT_DEBUG_ERROR, ("Special 3090E chip \n"));
		}

		RTMP_IO_READ32(pAd, AUX_CTRL, &MacValue);
		/*enable WAKE_PCIE function, which forces to enable PCIE clock when mpu interrupt asserting. */
		/*Force PCIE 125MHz CLK to toggle */
		MacValue |= 0x402;
		RTMP_IO_WRITE32(pAd, AUX_CTRL, MacValue);
		DBGPRINT_RAW(RT_DEBUG_ERROR,
			     (" AUX_CTRL = 0x%32x\n", MacValue));

		/* for RT30xx F and after, PCIe infterface, and for power solution 3 */
		if ((IS_VERSION_AFTER_F(pAd))
		    && (pAd->StaCfg.PSControl.field.rt30xxPowerMode >= 2)
		    && (pAd->StaCfg.PSControl.field.rt30xxPowerMode <= 3)) {
			RTMP_IO_READ32(pAd, AUX_CTRL, &MacValue);
			DBGPRINT_RAW(RT_DEBUG_ERROR,
				     (" Read AUX_CTRL = 0x%x\n", MacValue));
			/* turn on bit 12. */
			/*enable 32KHz clock mode for power saving */
			MacValue |= 0x1000;
			if (MacValue != 0xffffffff) {
				RTMP_IO_WRITE32(pAd, AUX_CTRL, MacValue);
				DBGPRINT_RAW(RT_DEBUG_ERROR,
					     (" Write AUX_CTRL = 0x%x\n",
					      MacValue));
				/* 1. if use PCIePowerSetting is 2 or 3, need to program OSC_CTRL to 0x3ff11. */
				MacValue = 0x3ff11;
				RTMP_IO_WRITE32(pAd, OSC_CTRL, MacValue);
				DBGPRINT_RAW(RT_DEBUG_ERROR,
					     (" OSC_CTRL = 0x%x\n", MacValue));
				/* 2. Write PCI register Clk ref bit */
				RTMPrt3xSetPCIePowerLinkCtrl(pAd);
			} else {
				/* Error read Aux_Ctrl value.  Force to use solution 1 */
				DBGPRINT(RT_DEBUG_ERROR,
					 (" Error Value in AUX_CTRL = 0x%x\n",
					  MacValue));
				pAd->StaCfg.PSControl.field.rt30xxPowerMode = 1;
				DBGPRINT(RT_DEBUG_ERROR,
					 (" Force to use power solution1 \n"));
			}
		}
		/* 1. read setting from inf file. */

		PCIePowerSaveLevel =
		    (u16)pAd->StaCfg.PSControl.field.rt30xxPowerMode;
		DBGPRINT(RT_DEBUG_ERROR,
			 ("====> rt30xx Read PowerLevelMode =  0x%x.\n",
			  PCIePowerSaveLevel));
		/* 2. Check EnableNewPS. */
		if (pAd->StaCfg.PSControl.field.EnableNewPS == FALSE)
			PCIePowerSaveLevel = 1;

		if (IS_VERSION_BEFORE_F(pAd)
		    && (pAd->b3090ESpecialChip == FALSE)) {
			/* Chip Version E only allow 1, So force set 1. */
			PCIePowerSaveLevel &= 0x1;
			pAd->PCIePowerSaveLevel = (u16)PCIePowerSaveLevel;
			DBGPRINT(RT_DEBUG_TRACE,
				 ("====> rt30xx E Write 0x83 Command = 0x%x.\n",
				  PCIePowerSaveLevel));

			AsicSendCommandToMcu(pAd, 0x83, 0xff,
					     (u8)PCIePowerSaveLevel, 0x00);
		} else {
			/* Chip Version F and after only allow 1 or 2 or 3. This might be modified after new chip version come out. */
			if (!
			    ((PCIePowerSaveLevel == 1)
			     || (PCIePowerSaveLevel == 3)))
				PCIePowerSaveLevel = 1;
			DBGPRINT(RT_DEBUG_ERROR,
				 ("====> rt30xx F Write 0x83 Command = 0x%x.\n",
				  PCIePowerSaveLevel));
			pAd->PCIePowerSaveLevel = (u16)PCIePowerSaveLevel;
			/* for 3090F , we need to add high-byte arg for 0x83 command to indicate the link control setting in */
			/* PCI Configuration Space. Because firmware can't read PCI Configuration Space */
			if ((pAd->Rt3xxRalinkLinkCtrl & 0x2)
			    && (pAd->Rt3xxHostLinkCtrl & 0x2)) {
				LinkCtrlSetting = 1;
			}
			DBGPRINT(RT_DEBUG_TRACE,
				 ("====> rt30xxF LinkCtrlSetting = 0x%x.\n",
				  LinkCtrlSetting));
			AsicSendCommandToMcu(pAd, 0x83, 0xff,
					     (u8)PCIePowerSaveLevel,
					     LinkCtrlSetting);
		}
	}
	/* 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,
				     &reg16);
		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);
#ifdef RT2860
		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));
		}
#endif /* RT2860 // */

		RTMPFindHostPCIDev(pAd);
		if (pObj->parent_pci_dev) {
			u16 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;
				RTMP_SET_PSFLAG(pAd, fRTMP_PS_TOGGLE_L1);
			}
			/* 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,
						     &reg16);
				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) {
#ifdef RT2860
				case NIC2860_PCIe_DEVICE_ID:
				case NIC2790_PCIe_DEVICE_ID:
					bChange = TRUE;
					break;
#endif /* RT2860 // */
#ifdef RT3090
				case NIC3090_PCIe_DEVICE_ID:
				case NIC3091_PCIe_DEVICE_ID:
				case NIC3092_PCIe_DEVICE_ID:
					if (bFindIntel == FALSE)
						bChange = TRUE;
					break;
#endif /* RT3090 // */
				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)
#ifdef RT3090
		    && ((pObj->DeviceID == NIC3090_PCIe_DEVICE_ID)
			|| (pObj->DeviceID == NIC3091_PCIe_DEVICE_ID)
			|| (pObj->DeviceID == NIC3092_PCIe_DEVICE_ID))
#endif /* RT3090 // */
		    ) {
			pci_read_config_word(pObj->pci_dev, pAd->RLnkCtrlOffset,
					     &reg16);
			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(struct rt_rtmp_adapter *pAd)
{
	u16 reg16;
	u8 reg8;
	u32 DevFn;
	struct pci_dev *pPci_dev;
	struct os_cookie *pObj;

	pObj = (struct os_cookie *)pAd->OS_Cookie;

	if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_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,
						     &reg16);
				reg16 = le2cpu16(reg16);
				pci_read_config_byte(pPci_dev, PCI_CB_CARD_BUS,
						     &reg8);
				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(struct rt_rtmp_adapter *pAd, u8 Level)
{
	u16 PCIePowerSaveLevel, reg16;
	u16 Configuration;
	struct os_cookie *pObj;

	pObj = (struct os_cookie *)pAd->OS_Cookie;

	if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE))
		return;

#ifdef RT2860
	if (!((pObj->DeviceID == NIC2860_PCIe_DEVICE_ID)
	      || (pObj->DeviceID == NIC2790_PCIe_DEVICE_ID)))
		return;
#endif /* RT2860 // */
	/* Check PSControl Configuration */
	if (pAd->StaCfg.PSControl.field.EnableNewPS == FALSE)
		return;

	/*3090 will not execute the following codes. */
	/* Check interface : If not PCIe interface, return. */

#ifdef RT3090
	if ((pObj->DeviceID == NIC3090_PCIe_DEVICE_ID)
	    || (pObj->DeviceID == NIC3091_PCIe_DEVICE_ID)
	    || (pObj->DeviceID == NIC3092_PCIe_DEVICE_ID))
		return;
#endif /* RT3090 // */

	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(struct rt_rtmp_adapter *pAd, u16 Max)
{
	u16 PCIePowerSaveLevel, reg16;
	u16 Configuration;
	struct os_cookie *pObj;

	pObj = (struct os_cookie *)pAd->OS_Cookie;

	if (!OPSTATUS_TEST_FLAG(pAd, fOP_STATUS_PCIE_DEVICE))
		return;

#ifdef RT2860
	if (!((pObj->DeviceID == NIC2860_PCIe_DEVICE_ID)
	      || (pObj->DeviceID == NIC2790_PCIe_DEVICE_ID)))
		return;
#endif /* RT2860 // */
	/* Check PSControl Configuration */
	if (pAd->StaCfg.PSControl.field.EnableNewPS == FALSE)
		return;

	/* Check interface : If not PCIe interface, return. */
	/*Block 3090 to enter the following function */

#ifdef RT3090
	if ((pObj->DeviceID == NIC3090_PCIe_DEVICE_ID)
	    || (pObj->DeviceID == NIC3091_PCIe_DEVICE_ID)
	    || (pObj->DeviceID == NIC3092_PCIe_DEVICE_ID))
		return;
#endif /* RT3090 // */
	if (!RTMP_TEST_PSFLAG(pAd, fRTMP_PS_CAN_GO_SLEEP)) {
		DBGPRINT(RT_DEBUG_INFO,
			 ("RTMPPCIePowerLinkCtrl return on fRTMP_PS_CAN_GO_SLEEP flag\n"));
		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;

	/* Skip non-exist deice right away */
	if (pObj->parent_pci_dev && (pAd->HostLnkCtrlOffset != 0)) {
		PCI_REG_READ_WORD(pObj->parent_pci_dev, pAd->HostLnkCtrlOffset,
				  Configuration);
		switch (PCIePowerSaveLevel) {
		case 0:
			/* Set b0 and b1 of LinkControl (both 2892 and PCIe bridge) to 00 */
			Configuration &= 0xfefc;
			break;
		case 1:
			/* Set b0 and b1 of LinkControl (both 2892 and PCIe bridge) to 01 */
			Configuration &= 0xfefc;
			Configuration |= 0x1;
			break;
		case 2:
			/*  Set b0 and b1 of LinkControl (both 2892 and PCIe bridge) to 11 */
			Configuration &= 0xfefc;
			Configuration |= 0x3;
			break;
		case 3:
			/* Set b0 and b1 of LinkControl (both 2892 and PCIe bridge) to 11 and bit 8 of LinkControl of 2892 to 1 */
			Configuration &= 0xfefc;
			Configuration |= 0x103;
			break;
		}
		PCI_REG_WIRTE_WORD(pObj->parent_pci_dev, pAd->HostLnkCtrlOffset,
				   Configuration);
		DBGPRINT(RT_DEBUG_TRACE,
			 ("Write PCI host offset 0x%x = 0x%x\n",
			  pAd->HostLnkCtrlOffset, Configuration));
	}

	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);
		switch (PCIePowerSaveLevel) {
		case 0:
			/* No PCI power safe */
			/* Set b0 and b1 of LinkControl (both 2892 and PCIe bridge) to 00 . */
			Configuration &= 0xfefc;
			break;
		case 1:
			/*  L0 */
			/* Set b0 and b1 of LinkControl (both 2892 and PCIe bridge) to 01 . */
			Configuration &= 0xfefc;
			Configuration |= 0x1;
			break;
		case 2:
			/* L0 and L1 */
			/*  Set b0 and b1 of LinkControl (both 2892 and PCIe bridge) to 11 */
			Configuration &= 0xfefc;
			Configuration |= 0x3;
			break;
		case 3:
			/* L0 , L1 and clock management. */
			/* Set b0 and b1 of LinkControl (both 2892 and PCIe bridge) to 11 and bit 8 of LinkControl of 2892 to 1 */
			Configuration &= 0xfefc;
			Configuration |= 0x103;
			pAd->bPCIclkOff = TRUE;
			break;
		}
		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"));
}

/*
	========================================================================

	Routine Description:
		1. Write a PCI register for rt30xx power solution 3

	========================================================================
*/
void RTMPrt3xSetPCIePowerLinkCtrl(struct rt_rtmp_adapter *pAd)
{

	unsigned long HostConfiguration = 0;
	unsigned long Configuration;
	struct os_cookie *pObj;
	int pos;
	u16 reg16;

	pObj = (struct os_cookie *)pAd->OS_Cookie;

	DBGPRINT(RT_DEBUG_INFO,
		 ("RTMPrt3xSetPCIePowerLinkCtrl.===> %lx\n",
		  pAd->StaCfg.PSControl.word));

	/* Check PSControl Configuration */
	if (pAd->StaCfg.PSControl.field.EnableNewPS == FALSE)
		return;
	RTMPFindHostPCIDev(pAd);
	if (pObj->parent_pci_dev) {
		/* Find PCI-to-PCI Bridge Express Capability Offset */
		pos = pci_find_capability(pObj->parent_pci_dev, PCI_CAP_ID_EXP);

		if (pos != 0) {
			pAd->HostLnkCtrlOffset = pos + PCI_EXP_LNKCTL;
		}
		/* If configurared to turn on L1. */
		HostConfiguration = 0;
		if (pAd->StaCfg.PSControl.field.rt30xxForceASPMTest == 1) {
			DBGPRINT(RT_DEBUG_TRACE, ("Enter,PSM : Force ASPM \n"));

			/* Skip non-exist deice right away */
			if ((pAd->HostLnkCtrlOffset != 0)) {
				PCI_REG_READ_WORD(pObj->parent_pci_dev,
						  pAd->HostLnkCtrlOffset,
						  HostConfiguration);
				/* Prepare Configuration to write to Host */
				HostConfiguration |= 0x3;
				PCI_REG_WIRTE_WORD(pObj->parent_pci_dev,
						   pAd->HostLnkCtrlOffset,
						   HostConfiguration);
				pAd->Rt3xxHostLinkCtrl = HostConfiguration;
				/* Because in rt30xxForceASPMTest Mode, Force turn on L0s, L1. */
				/* Fix HostConfiguration bit0:1 = 0x3 for later use. */
				HostConfiguration = 0x3;
				DBGPRINT(RT_DEBUG_TRACE,
					 ("PSM : Force ASPM : "
					  "Host device L1/L0s Value =  0x%lx\n",
					  HostConfiguration));
			}
		} else if (pAd->StaCfg.PSControl.field.rt30xxFollowHostASPM ==
			   1) {

			/* Skip non-exist deice right away */
			if ((pAd->HostLnkCtrlOffset != 0)) {
				PCI_REG_READ_WORD(pObj->parent_pci_dev,
						  pAd->HostLnkCtrlOffset,
						  HostConfiguration);
				pAd->Rt3xxHostLinkCtrl = HostConfiguration;
				HostConfiguration &= 0x3;
				DBGPRINT(RT_DEBUG_TRACE,
					 ("PSM : Follow Host ASPM : "
					  "Host device L1/L0s Value =  0x%lx\n",
					  HostConfiguration));
			}
		}
	}
	/* Prepare to write Ralink setting. */
	/* 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,
				     &reg16);
		Configuration = le2cpu16(reg16);
		DBGPRINT(RT_DEBUG_TRACE,
			 ("Read (Ralink PCIe Link Control Register) "
			  "offset 0x%x = 0x%lx\n",
			  pAd->RLnkCtrlOffset, Configuration));
		Configuration |= 0x100;
		if ((pAd->StaCfg.PSControl.field.rt30xxFollowHostASPM == 1)
		    || (pAd->StaCfg.PSControl.field.rt30xxForceASPMTest == 1)) {
			switch (HostConfiguration) {
			case 0:
				Configuration &= 0xffffffc;
				break;
			case 1:
				Configuration &= 0xffffffc;
				Configuration |= 0x1;
				break;
			case 2:
				Configuration &= 0xffffffc;
				Configuration |= 0x2;
				break;
			case 3:
				Configuration |= 0x3;
				break;
			}
		}
		reg16 = cpu2le16(Configuration);
		pci_write_config_word(pObj->pci_dev, pAd->RLnkCtrlOffset,
				      reg16);
		pAd->Rt3xxRalinkLinkCtrl = Configuration;
		DBGPRINT(RT_DEBUG_TRACE,
			 ("PSM :Write Ralink device L1/L0s Value =  0x%lx\n",
			  Configuration));
	}
	DBGPRINT(RT_DEBUG_INFO,
		 ("PSM :RTMPrt3xSetPCIePowerLinkCtrl <==============\n"));
}